☰
astron-agent Trace 日志配置解析:TraceLogs Config 的统一入口、类型体系与时间/树形处理机制
2026/10/14 15:50:35 网站建设 项目流程
  • 人工智能
  • AI Agent
  • Agent 工作流
  • RPA
  • 后端
  • 前端
  • 工具调用

【免费下载链接】astron-agent

An enterprise-ready AI agent development platform combining intelligent RPA, enabling agents to not only think but also act—automating workflows across digital and desktop environments. 这是一个镜像仓库,有issue、pr欢迎去github提交。

项目地址:https://gitcode.com/ifly_opensource/astron-agent
点击查看免费下载

在 astron-agent 的前端控制台中,"发布管理 → Trace 日志"页面负责按智能体维度检索、查看与导出 Trace 调用记录。本文以 TraceLogs 配置说明文档 为主体,结合 config/index.ts、config/utils.ts、config/type.d.ts 以及页面入口 trace-logs/index.tsx 的源码,完整讲清这套配置模块的文件结构、每类配置的取值、时间范围与列表参数的生成规则,以及 Trace 数据如何被转换为可交互的调用树。读完后,你可以理解该页面所有交互(预设时间范围、列管理、套餐权限、导出)背后的参数链路,并能在维护或复用该模块时快速定位每一处配置的定义点。

一、模块定位与文件结构

Trace 日志页面位于console/frontend/src/pages/release-management/trace-logs/,其配置被集中收敛在同级的config/子目录中。按文档描述的目录结构如下:

config/ ├── index.ts # 统一入口文件,导出所有配置、工具函数和类型 ├── type.d.ts # 类型定义文件 ├── utils.ts # 工具函数文件 └── README.md # 说明文档

同级目录下还有消费这些配置的三个组件:列表页入口 index.tsx、点击行后展示调用树的 CheckModal(内含 TreeNode 与 ContentDisplay 子组件)、以及导出按钮组件 ExportBtn。整个页面作为懒加载组件挂入发布管理路由,见 release-management/index.tsx 中的React.lazy(() => import('./trace-logs'))。

二、index.ts统一入口:常量、表格配置与函数封装

2.1 分隔符常量SEPERATOR

入口文件第一个导出是时间范围字符串的分隔符:

export const SEPERATOR = '~';

Trace 页面内部用<起始时间>~<结束时间>这种字符串(即searchValue)贯穿"预设范围 → RangePicker 回显 → 生成查询参数"的整个流程。所有需要解析或生成该格式字符串的工具函数都显式接收SEPERATOR参数,而index.ts中重新封装的函数则替调用方预设了它,因此页面代码只需要导入封装版本即可。

2.2 预设时间范围timeRangeMap

timeRangeMap定义了四个预设时间档位,键为'0'~'3',每项包含unit、amount、展示label以及用于下拉选项的图标与样式:

键unitamount展示文案图标
'0'day5最近5天无
'1'day15最近15天diamond-blue.svg
'2'day90最近3个月diamond-yellow.svg
'3'year1最近一年diamond-orange.svg

从源码结构看,'1'、'2'两项保留了unit: 'month' / 'year'的注释,说明该档位曾按月/年计,后统一改为按天(15 天、90 天),标签文案则维持"最近15天/最近3个月"的表述。这些档位被 trace-logs/index.tsx 映射为Select的下拉选项,并且页面通过监听用户套餐等级(orderTraceAndIcon,取自 order-store)过滤可用档位:

  • 套餐等级 0:仅可查"最近5天";
  • 等级 1:5 天 / 15 天;
  • 等级 2:5 天 / 15 天 / 90 天;
  • 等级 3:全部四档。

选择超出套餐权限的档位时,会触发checkTimeRangeInPackagePermission返回false,页面随即eventBus.emit('showComboModal')弹出套餐引导,而不会发起查询——这就是index.ts中导出checkTimeRangeInPackagePermission的用途。

2.3 表格列配置columnsMap、requiredOptions与checkboxOptions

columnsMap是"列名 → antd Table 列定义"的映射,页面通过"列管理"Popover 中的复选框动态组装表格列:

列键dataIndex宽度特殊渲染
StatusstatusCode100render返回{ props: { color }, children }:statusCode === 0为 success/成功,否则 error/失败,文案随语言切换
SIDsid200超长省略
Questionquestion230超长省略
Answeranswer230超长省略
Durationduration100utils.durationToSeconds(duration, true),统一换算为秒展示
StartTime/EndTimestartTime/endTime200超长省略
QuestionTokens/PromptTokens/TotalTokensquestionTokens/promptTokens/totalTokens200可选列,仅在sub === 'workflow'时由usage字段填充

三个配套配置共同约束列的行为:

  • requiredOptions:['Status', 'SID', 'Question', 'Answer', 'Duration', 'StartTime', 'EndTime'],这 7 列必选且不可取消;
  • checkboxOptions:列管理弹窗的复选框数据,前 7 项带disabled: true,其余三个 Tokens 列可自由勾选;
  • 输入/输出字段优先级:INPUT_FIELD_PRIORITY = ['input', 'prompt', 'text', 'AGENT_USER_INPUT']、OUTPUT_FIELD_PRIORITY = ['output', 'data'],供详情弹窗按优先级取节点输入输出内容。

页面侧的组合逻辑在 trace-logs/index.tsx 中可见:handleCheckboxChange始终先铺满requiredOptions,再追加用户勾选的非必选列;processColumnsForRender会把Status列的 render 结果二次包装成 antdTag组件。表格序号列则按(current - 1) * pageSize + index + 1计算,保证翻页后序号连续。

2.4 工具函数封装与直接导出

index.ts将utils.ts中的函数分两层导出:

  • 带预设参数的封装:searchValueFormat(value)、convertSearchValueToRange(value)、createDateRangeValidator(searchValue, rangeValue)、generateListParams(searchValue, pagination, format?, extraParams?)、checkTimeRangeInPackagePermission(value, options),它们内部统一注入timeRangeMap与SEPERATOR,调用方无需感知分隔符细节;
  • 直接透传:isValidJson、parseJsonValue、durationToSeconds、transformTraceData、convertToTree、findFieldByPriority,以及类型TraceData、TraceNode。

文档推荐的统一入口用法即:

import { SEPERATOR, timeRangeMap, columnsMap, searchValueFormat, isValidJson, convertToTree, type DataType, } from './config';

三、type.d.ts类型定义

type.d.ts导出两个接口:

DataType描述列表表格的一行数据:

interface DataType { status: boolean; sid: string; uid: string; question: string; answer: string; duration: number; startTime: string; endTime: string; questionTokens?: number; answerTokens?: number; totalTokens?: number; traceId?: string; input?: string; output?: string; tokens?: string; inputTokens?: string; outputTokens?: string; latency?: string; latencyFirstResp?: string; spanId?: string; trace?: any[]; statusCode?: string; }

其中trace字段是后端返回的原始 Trace 节点数组,列表页在处理数据时会先用convertToTree(trace, rootData)转成树形结构再挂到行数据上,行点击后 CheckModal 直接读取record.trace渲染调用树。

TimeOption描述时间范围选项(key、label、value),被checkTimeRangeInPackagePermission用于套餐权限判断。TraceData/TraceNode两个接口定义在 utils.ts 内并经由index.ts转出,用于树形转换。

四、utils.ts工具函数详解

4.1 JSON 处理:isValidJson与parseJsonValue

isValidJson通过JSON.parse的 try/catch 判断字符串是否合法 JSON。parseJsonValue(jsonStr, fieldName?)在其之上做了两件事:指定fieldName时直接取该字段;未指定时返回对象第一个值;解析失败或缺失时返回'-'。

列表页handleTraceData是典型调用方:

const statusCode = parseJsonValue(status, 'code'); // 从 status JSON 中提取 code const question = parseJsonValue(rest?.question); // 取第一个值 const answer = parseJsonValue(rest?.answer);

这解释了为什么DataType中同时保留了status(原始串)与statusCode(解析出的码值)。

4.2 时长换算durationToSeconds

export const durationToSeconds = (duration: number, isAllToSeconds = false): string => { ... }

规则为:0返回0.00s;空值返回'-';小于 1000 且未强制转秒时返回xxxms;否则返回秒并保留 2 位小数(≥1000ms)或 3 位(<1000ms 但被强制转秒)。columnsMap.Duration传入true强制以秒展示,保证表格时长列口径一致。

4.3 Trace 转换与树构建:transformTraceData、convertToTree

transformTraceData针对单条 Trace 数据做归一化:

  • 按::拆分func_id,拆出func_code(第一段)与func_id(第二段),例如node-start::123中func_code = 'node-start';
  • 用durationToSeconds(..., true)计算展示用executionTime。

convertToTree(data, rootData?, showEndNode = true)是核心的树形转换算法,要点如下:

  1. 索引与查找:先把所有节点transformTraceData后存入id → TraceNode的 Map;findNodeByLogId优先精确命中,未命中则退化为id.includes(logId)的模糊匹配,容忍日志 ID 前后缀差异。
  2. 递归建树:buildTree沿next_log_ids链接子节点,用visited集合防环,并用父key_节点id_后缀生成全局唯一key供 antd Tree 使用;showEndNode为false时可过滤func_code === 'node-end'的收尾节点。
  3. 根节点判定:遍历寻找func_id以node-start::开头的节点作为根;找不到则返回空数组。根节点的data可注入调用方传入的rootData——列表页正是借此把question/answer组装成{ input: { input }, output: { output } }挂到根上,使树的第一层就能展示整次对话的输入输出。
  4. 迭代节点分组:attachIterationGroups处理iteration::前缀的循环节点——根据data.config.IterationStartNodeId(或iterationStartNodeId)把所有同 ID 的迭代运行包装成"第 N 次"的虚拟节点(isVirtual: true、selectable: false),并插在原有 children 之前。CheckModal 中collectExpandedKeys也据此跳过node_type === 'iteration-option'的虚拟组节点,避免默认展开过深。

4.4 时间处理三件套

  • searchValueFormat(value, timeRangeMap, SEPERATOR):若value是预设档位键('0'~'3'),计算now - amount×unit作为起点(取当日 00:00:00)、当前时刻作为终点,拼成YYYY-MM-DD 00:00:00~YYYY-MM-DD HH:mm:ss;非预设值原样返回。
  • convertSearchValueToRange(value, SEPERATOR):把上述字符串拆回[dayjs(start), dayjs(end)],供 RangePicker 回显;非法输入返回null。
  • createDateRangeValidator(searchValue, rangeValue, SEPERATOR):返回 antddisabledDate回调,将可选日期限制在"当前选择范围的当日起始日 ~ 当日结束"之内,实现自定义时间不得超出预设范围的选择约束。

页面中的使用顺序是:searchValue(档位键)→searchValueFormat→convertSearchValueToRange同步rangeValue;而generateListParams直接消费格式化后的字符串。

4.5 列表参数生成generateListParams

该函数把searchValue拆成起止时间并按format参数做"时间补全":

  • 无时间部分时,起始时间补00:00:00(或00:00/00),结束时间补23:59:59(或23:59/23);
  • 时间部分不完整时(如只有HH或HH:mm),按:分段补齐,起始方向补00、结束方向补59,最终裁剪到期望段数。

返回对象为:

{ startTime: 'YYYY-MM-DD HH:mm:ss', endTime: 'YYYY-MM-DD HH:mm:ss', page: pagination.current || 1, pageSize: pagination.pageSize || 10, ...extraParams, // 如 { botId: 'xxx' } }

页面在"搜索、重置、翻页、切换预设范围"四个入口都调用它并附带{ botId },最终传给 services/trace.ts 的getTraceList(GET /trace/getTrace)。注意handleRangeChange(自定义范围场景)使用format = 'YYYY-MM-DD HH:mm',此时参数按分钟粒度补全,与列表默认的秒粒度形成对照。

五、配置在页面链路中的完整数据流

把上述零件串起来,Trace 日志页的一条完整请求链路为:

  1. 初始化:useEffect中用convertSearchValueToRange(searchValueFormat(searchValue))初始化 RangePicker 值,并立即search()发起首次查询;同时按orderType过滤availableOptions,若当前档位不在权限内自动切到第一个可用档位。
  2. 查询:searchValueFormat产出范围字符串 →generateListParams生成{ startTime, endTime, page, pageSize, botId }→getTraceList请求GET /trace/getTrace。
  3. 数据加工:handleTraceData解包pageData/totalCount,逐行用parseJsonValue提取statusCode/question/answer,dayjs格式化起止时间,sub === 'workflow'时补 Tokens 三列,convertToTree生成行级调用树。
  4. 详情查看:点击行打开 CheckModal,左侧 antd Tree 以func_name为标题、key为键渲染调用树,选中节点后右侧用findFieldByPriority按INPUT_FIELD_PRIORITY/OUTPUT_FIELD_PRIORITY取输入输出内容,并展示running_status、func_id(带复制按钮)、func_type、executionTime、start_time等状态信息。
  5. 导出:ExportBtn 先调GET /trace/count预估数据量,超过maxDownloadCount = 100000条时提示缩小时间范围并禁用导出;确认后调GET /trace/download(responseType: 'blob')下载 Excel,从Content-Disposition解析文件名,并支持AbortController中途取消。

六、这套组织方式带来的收益

文档归纳了五点优势,结合源码可以具体对应到实现上:

  1. 统一管理:常量(SEPERATOR)、表格配置(columnsMap/requiredOptions/checkboxOptions)、工具函数全部经 config/index.ts 单一出口;
  2. 清晰分类:utils.ts内部按"数据处理 / 时间处理 / 参数生成 / 权限校验"分区组织,注释标明每个函数的参数与返回值约定;
  3. 类型安全:DataType、TimeOption由type.d.ts统一导出,TraceData/TraceNode由utils.ts导出,表格Table<DataType>、弹窗record?: DataType | null等位置均获得类型约束;
  4. 易于维护:例如调整时间档位只需改timeRangeMap一处,下拉选项、范围格式化、RangePicker 回显与日期校验四者自动一致;
  5. 简化导入:页面、弹窗、导出组件的import均指向./config统一入口,无需关心函数定义在index.ts还是utils.ts。

七、小结与扩展方向

这套 config 模块展示了 astron-agent 前端处理"检索类列表页"的完整范式:预设档位与自定义范围共用一条searchValue数据流,列展示配置与列管理 UI 解耦,树形转换算法对next_log_ids链接、循环节点分组、ID 模糊匹配与环防护都做了防御性处理。若后续需要扩展,可关注三个方向:为convertToTree增加单测覆盖环路与虚拟节点场景;将columnsMap的文案接入i18n(当前status/sid/question等标题为硬编码英文);以及把ExportBtn中finally里标注为 mock 的setIsModalVisible(true)清理为异常分支下的明确提示。所有相关实现均可在 console/frontend/src/pages/release-management/trace-logs/ 目录与 console/frontend/src/services/trace.ts 中继续深入阅读。

  • 人工智能
  • AI Agent
  • Agent 工作流
  • RPA
  • 后端
  • 前端
  • 工具调用

【免费下载链接】astron-agent

An enterprise-ready AI agent development platform combining intelligent RPA, enabling agents to not only think but also act—automating workflows across digital and desktop environments. 这是一个镜像仓库,有issue、pr欢迎去github提交。

项目地址:https://gitcode.com/ifly_opensource/astron-agent
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询