从目录规范到追踪可视化:Coze Studio@coze-devops/common-modules公共业务模块包深度解析
【免费下载链接】coze-studioAn AI agent development platform with all-in-one visual tools, simplifying agent creation, debugging, and deployment like never before. Coze your way to AI Agent creation.项目地址: https://gitcode.com/GitHub_Trending/co/coze-studio
@coze-devops/common-modules是 Coze Studio 开源仓库中 devops 前端体系(位于 frontend/packages/devops)下的公共业务模块包,它以 React 组件库 + Storybook 的工程形态组织代码,并以query-trace(查询追踪)为旗舰业务模块,为 Agent 运行时的 Span/Trace 数据提供从原始数据转换、调用树构建到火焰图/拓扑图/树形可视化的一整套前端能力。本文以该包的 README 目录结构说明为骨架,结合 package.json、统一出口 src/index.ts 及query-trace模块源码,完整剖析其工程规范与数据管线实现,读完你可以掌握:这个包为何这样分层、如何在自身项目中复刻同一目录规范、以及query-trace如何把底层Span数据演化为可直接驱动的可视化数据。
包定位与依赖关系:devops 的"公共业务模块"仓库
从 package.json 可以看到该包的完整身份信息:
- 包名:
@coze-devops/common-modules,version: 0.0.1,private: true,仅用于仓库内部 workspace 引用; - 描述:
common business modules for devops,即 devops(开发运维 / 调试观测)场景下的公共业务模块集合; - License:
Apache-2.0,与仓库整体协议一致。
它暴露了三级导入入口(exports字段):
"exports": { ".": "./src/index.ts", "./query-trace": "./src/modules/query-trace/index.ts", "./tree": "./src/modules/query-trace/components/tree/index.tsx" }同时用typesVersions为query-trace和tree提供对应的类型解析路径。这种"根入口 + 子路径入口"的设计,允许消费方按需引入,避免把整个包(尤其是体积较大的可视化组件)全部打进 bundle。
依赖关系揭示了它的技术底座(均为 workspace 内部包或固定版本的外部库):
| 依赖 | 用途 |
|---|---|
@coze-arch/bot-api(workspace:*) | 提供Span、SpanType、SpanStatus、SpanCategory等观测 API 类型(ob_query_api) |
@coze-arch/bot-hooks | 页面跳转服务(usePageJumpService、SceneType),如从追踪树跳转到工作流 |
@coze-arch/bot-semi/@coze-arch/coze-design | UI 组件与设计体系 |
@coze-arch/bot-icons/@coze-arch/i18n | 图标与国际化 |
@dagrejs/dagre | 拓扑图自动布局引擎 |
@visactor/vgrammar | 火焰图(flamethread)可视化语法 |
reactflow | 拓扑流程图节点/边渲染 |
ahooks/lodash-es/dayjs/classnames | React hooks、工具函数、时间格式化、样式拼接 |
peerDependencies要求react >= 18.2.0、react-dom >= 18.2.0,即包本身不内置 React,由宿主应用提供。
目录结构规范:一份可复刻的组件库模板
该包 README 的核心是一份目录结构树,它定义了"React 组件库 + Storybook"的标准骨架。下面逐项说明每个目录/文件的职责:
├── __tests__ # 测试用例(vitest) ├── .storybook # Storybook 配置目录 ├── config # 工程配置(如 rush-project.json) ├── src │ ├── assets # 公共静态资源(react.svg / rspack.png) │ ├── components # 公共组件 │ ├── hooks # 公共 hooks │ ├── index.tsx # 对外统一出口:可导出 component / hook / util / typing │ ├── modules # 模块集合:按业务模块划分子目录;index.tsx 导出的资源均来自 modules │ │ └── query-trace │ ├── services # 请求 api 封装 │ ├── styles # 公共样式 │ ├── typings # 公共类型 │ ├── typings.d.ts │ └── utils # 公共工具库 ├── stories # 文档(Storybook stories) ├── .eslintrc.js ├── .stylelintrc.js ├── OWNERS ├── package.json ├── README.md ├── tsconfig.build.json ├── tsconfig.json └── vitest.config.ts几个关键设计意图值得展开:
modules是业务代码的唯一归属地:README 特别强调"index.tsx 中导出的资源都是来自于 modules 目录"。这意味着src/components、src/hooks、src/utils等仅存放跨模块复用的基础能力,而具体业务(如 query-trace)必须以模块为单位整体沉淀在modules/<业务名>/下。components、hooks、services、styles、typings、utils各目录下都有一份 README.md,用于沉淀该层级的约定。单一出口原则:外部只能通过
index.tsx使用本包,避免内部实现细节泄漏。工程文件齐全:
tsconfig.json采用 TypeScript Project References 结构——根配置仅声明composite: true并引用 tsconfig.build.json 与tsconfig.misc.json,exclude: ["**/*"]让实际编译工作由两个子项目承接(一个面向构建产物,一个面向 eslint/vitest 等杂项任务),这是大型 monorepo 中常见的加速增量编译手段。Rush 集成:config/rush-project.json 声明了
test:cov(输出coverage)与ts-check(输出./dist)两个操作的构建产物目录,用于 Rush 的增量构建缓存。
统一出口:index.tsx实际上导出了什么
值得注意的一个细节是:README 中的结构树写的是src/index.tsx,而当前仓库实际落地为 src/index.ts,内容完全遵循"统一出口"约定,目前对外导出:
export { TraceFlamethread, TraceTree, useSpanTransform, } from './modules/query-trace';也就是说,当前版本对外暴露的公共能力全部来自query-trace模块的三大件:火焰图组件TraceFlamethread、追踪树组件TraceTree、数据转换 hookuseSpanTransform。而query-trace模块自身的 index.ts 则导出得更为完整,构成了该模块的"内部门面",包括:
- 可视化组件:
TraceFlamethread、TraceTree、TopologyFlow、基础版Flamethread与Tree(后者同时导出MouseEventParams鼠标事件参数类型); - 数据转换 hook:
useSpanTransform; - 类型体系:
CSpan、CTrace、CSpanSingle、CSPanBatch以及按 Span 类型细分的CSpanAttr*系列(如CSpanAttrLLMCall、CSpanAttrWorkflow、CSpanAttrPluginTool、CSpanAttrKnowledge等),外加StreamingOutputStatus枚举; - 配置映射:
spanTypeConfigMap、botEnvConfigMap、spanCategoryConfigMap、streamingOutputStatusConfigMap(定义在 config/cspan.ts); - 工具函数:
isBatchSpanType、isVisibleSpan、checkIsBatchBasicCSpan、getTokens、getSpanProp、span2CSpan、fieldItemHandlers等; - 枚举:
DataSourceTypeEnum(数据源类型,来自 typings/graph.ts)。
query-trace 模块:追踪可视化的数据管线
query-trace是@coze-devops/common-modules最具技术含量的模块,其目录划分本身就是模块内再分层的范本:
modules/query-trace ├── components/ # 可视化组件(flamethread / topology-flow / trace-flamethread / trace-tree / tree) ├── config/ # Span 类型、状态、分类的展示配置映射 ├── hooks/ # use-span-transform 数据转换 hook ├── typings/ # cspan / graph / config 类型定义 ├── utils/ # cspan / cspan-transform / cspan-graph / field-item-handler / format-time ├── constant.ts └── index.ts核心数据模型:从原始Span到CSpan
可视化组件不直接消费底层观测 API 返回的Span(其字段分散在attr_user_input、attr_llm_call、attr_workflow等三十余个attr_*字段中),而是先转换为统一的CSpan(custom span)结构。类型定义集中在 typings/cspan.ts:
type CSpanCommonProp = Pick< Span, 'trace_id' | 'id' | 'parent_id' | 'name' | 'type' | 'status' > & { start_time: number; // 原始 Int64 转 number,便于前端计算 latency: number; // 原始 Int64 转 number category?: SpanCategory; // 仅当 Meta 加载失败时为空 input_tokens_sum?: number; // 扩展字段:子树 input_tokens 求和 output_tokens_sum?: number; // 扩展字段:子树 output_tokens 求和 };在此基础上,CSpan分为两类:
CSpanSingle:单节点 span,由GenCSpan<T>泛型生成,extra携带各类型专属属性(LLM 调用的 model/tokens、插件的 tool 信息、知识库检索详情等),共覆盖CSpanAttrUserInput、CSpanAttrInvokeAgent、CSpanAttrLLMCall、CSpanAttrWorkflow、CSpanAttrCode、CSpanAttrCondition、CSpanAttrPluginTool、CSpanAttrKnowledge、CSpanAttrChain以及工作流批处理(BW*)系列等三十余种;CSPanBatch:批量节点,把同一工作流节点下多次执行的同类型子 span 聚合为一个spans数组,并记录workflow_node_id;批量内的子项类型收窄为CSpanSingleForBatch(LLM 批调用、插件批调用、代码批调用等)。
此外CTrace(一次完整追踪)以CSpanAttrUserInput为基底,额外携带dialog_round(对话轮次)与model等聚合信息。
转换实现:span2CSpan与spans2CSpans
转换逻辑位于 utils/cspan-transform.ts,核心是span2CSpan:通过一连串??空值合并,把原始 Span 的attr_user_input、attr_llm_call、attr_workflow、attr_plugin_tool、attr_knowledge、attr_bw_*等字段统一归并到extra属性,同时把start_time、latency由 Int64 转为 number,并按spanCategoryMap补齐category。
批量聚合则分两步(spans2CSpans→aggregationBatchSpan):
- 先按
span.id去重(uniqBy(spans, 'id')); - 普通 span 与批量类型 span 分流:调用
isBatchSpanType(见 utils/cspan.ts)识别LLMBatchCall、PluginToolBatch、CodeBatch等 6 种批量类型; - 批量 span 按
type + workflow_node_id分组,组内按start_time排序,再依据task_index(任务序号)切分聚合,最终通过genBatchSpan生成CSPanBatch——其中合法性校验值得注意:若同一组内task_total(任务总数)不一致,则判定数据非法,放弃聚合。
genBatchSpan对聚合结果的规约策略也很典型:status取"任一子项 Error 则整体 Error"的保守判定;start_time取子项最小开始时间;latency取max(start + latency) - min(start)的总跨度;spans按task_index升序排列。
useSpanTransform:一次追踪的完整数据管线
hooks/use-span-transform.ts 是连接原始数据与可视化组件的枢纽 hook,其处理管线依次为:
- 转换:
spans2CSpans(orgSpans, spanCategoryMeta)将原始 Span 数组转为CSpan[]; - 虚拟起始节点:
appendVirtualStart检查是否存在category === SpanCategory.Start的根节点,若缺失则调用genVirtualStart生成一个以全量 span 时间跨度为latency、状态为Unknown的虚拟根节点(virtualStartSpanId),保证调用树始终有根; - 服务端状态回填:
appendTraceAdvanceInfo把traceAdvanceInfo中的整体状态与 tokens 覆盖到 UserInput 根节点上(根节点以服务端统计为准); - 构建调用树:
buildCallTrees(spans)(实现于 utils/cspan-graph.ts)按parent_id组装树;若存在多个根节点且传入messageId,则按extra.message_id过滤,实现多消息追踪场景下的精确切割; - 取根节点并增强:
appendRootSpan从 InvokeAgent 节点中提取dialog_round与model回填到根节点; - 子集过滤:仅保留根节点可达的 span;
- tokens 汇总:
appendSpans对调用树做后序遍历,递归累加各节点子树的input_tokens_sum/output_tokens_sum,使每个节点都能展示"含子树的累计 token 消耗"(批量节点的 tokens 由getCSpanTokens对各子项求和)。
整个计算被useMemo包裹,依赖[orgSpans, traceAdvanceInfo, spanCategoryMeta, messageId],保证仅在数据变化时重算。getTokens与getSpanProp(见 utils/cspan.ts)则提供了对CSpan/CTrace统一取值的能力:批量节点优先读自身字段、其次读首个子项的extra。
可视化组件族:同一份数据,多种呈现视角
query-trace/components下提供了四种互补的可视化组件,它们共享同一套CSpan数据模型:
trace-tree/tree:树形列表视图。TraceTree 支持两种数据源(DataSourceTypeEnum.SpanData直接传入spanData,或TraceId由getSpanDataByTraceId(traceId)拉取),将 span 数据经spanData2treeData转换为通用Tree的TreeNode结构,支持selectedSpanId选中态、hover 联动(onHoverChange)、缩进禁用等;尤其实现了与工作流的深度联动——通过usePageJumpService的jump方法,点击节点可携带workflowID、executeID、workflowNodeID、workflowVersion、subExecuteID等参数在新窗口跳转到对应工作流执行现场,这正是"追踪可视化"与"调试平台"打通的关键一环;trace-flamethread/flamethread:基于@visactor/vgrammar实现的火焰图(flamegraph),以横向时间条叠加层级,直观呈现各 span 的耗时占比与嵌套关系,InteractionEventHandler提供交互事件回调;topology-flow:基于reactflow+@dagrejs/dagre的拓扑图视图,包含custom-nodes(自定义节点)与custom-edges(自定义边)两套扩展体系,适合展示 Agent/工作流节点之间的调用拓扑而非单纯的时间轴。
工程化配置:monorepo 内的标准组件库姿势
该包在工程化层面与 Coze Studio 的 Rush monorepo 体系(rush.json+ workspace 协议)完全对齐:
- 单元测试:vitest.config.ts 直接复用
@coze-arch/vitest-config的webpreset,脚本test使用vitest --run --passWithNoTests,test:cov生成 coverage; - Lint:
eslint ./ --cache走@coze-arch/eslint-config;样式侧配置stylelint; - 构建:
build脚本当前为exit 0(该包以源码形式被消费,由构建链路按需处理),类型检查由ts-check完成并通过tsconfig.build.json输出dist; - Rush 缓存:config/rush-project.json 声明
test:cov与ts-check的产物目录,供 Rush 增量构建复用。
小结:从这份 README 能学到什么
@coze-devops/common-modules的 README 虽仅有一张目录结构树,但它浓缩了 Coze Studio 前端中"公共业务模块"的组织哲学,配合仓库源码可以提炼出四条可迁移的工程经验:
- 分层纪律:
modules/<业务>/承载业务,components/hooks/utils/services/typings/styles承载可复用基础件,index.ts(x)作为唯一对外出口; - 数据与视图解耦:
query-trace用useSpanTransform把原始Span归一为CSpan(含批量聚合、虚拟根节点、tokens 汇总、messageId 过滤),让四种可视化组件只面向统一模型编程; - 深度产品联动:追踪树不只是"展示",通过页面跳转服务可直达工作流执行现场,这决定了数据模型必须携带
workflow_node_id、execute_id等上下文; - 工程规范内建:tests、lint、stylelint、Rush 缓存配置齐备,使新业务模块可以"开箱即用"地加入同一工程体系。
对于希望在自己的 React 组件库/业务模块仓库中沉淀公共能力的开发者,这份 README 与其背后的源码实现,是一份可以直接参照的目录规范与数据管线范本。
【免费下载链接】coze-studioAn AI agent development platform with all-in-one visual tools, simplifying agent creation, debugging, and deployment like never before. Coze your way to AI Agent creation.项目地址: https://gitcode.com/GitHub_Trending/co/coze-studio
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考