- 人工智能
- 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提交。
在 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以及用于下拉选项的图标与样式:
| 键 | unit | amount | 展示文案 | 图标 |
|---|---|---|---|---|
'0' | day | 5 | 最近5天 | 无 |
'1' | day | 15 | 最近15天 | diamond-blue.svg |
'2' | day | 90 | 最近3个月 | diamond-yellow.svg |
'3' | year | 1 | 最近一年 | 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 | 宽度 | 特殊渲染 |
|---|---|---|---|
Status | statusCode | 100 | render返回{ props: { color }, children }:statusCode === 0为 success/成功,否则 error/失败,文案随语言切换 |
SID | sid | 200 | 超长省略 |
Question | question | 230 | 超长省略 |
Answer | answer | 230 | 超长省略 |
Duration | duration | 100 | utils.durationToSeconds(duration, true),统一换算为秒展示 |
StartTime/EndTime | startTime/endTime | 200 | 超长省略 |
QuestionTokens/PromptTokens/TotalTokens | questionTokens/promptTokens/totalTokens | 200 | 可选列,仅在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)是核心的树形转换算法,要点如下:
- 索引与查找:先把所有节点
transformTraceData后存入id → TraceNode的 Map;findNodeByLogId优先精确命中,未命中则退化为id.includes(logId)的模糊匹配,容忍日志 ID 前后缀差异。 - 递归建树:
buildTree沿next_log_ids链接子节点,用visited集合防环,并用父key_节点id_后缀生成全局唯一key供 antd Tree 使用;showEndNode为false时可过滤func_code === 'node-end'的收尾节点。 - 根节点判定:遍历寻找
func_id以node-start::开头的节点作为根;找不到则返回空数组。根节点的data可注入调用方传入的rootData——列表页正是借此把question/answer组装成{ input: { input }, output: { output } }挂到根上,使树的第一层就能展示整次对话的输入输出。 - 迭代节点分组:
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 日志页的一条完整请求链路为:
- 初始化:
useEffect中用convertSearchValueToRange(searchValueFormat(searchValue))初始化 RangePicker 值,并立即search()发起首次查询;同时按orderType过滤availableOptions,若当前档位不在权限内自动切到第一个可用档位。 - 查询:
searchValueFormat产出范围字符串 →generateListParams生成{ startTime, endTime, page, pageSize, botId }→getTraceList请求GET /trace/getTrace。 - 数据加工:
handleTraceData解包pageData/totalCount,逐行用parseJsonValue提取statusCode/question/answer,dayjs格式化起止时间,sub === 'workflow'时补 Tokens 三列,convertToTree生成行级调用树。 - 详情查看:点击行打开 CheckModal,左侧 antd Tree 以
func_name为标题、key为键渲染调用树,选中节点后右侧用findFieldByPriority按INPUT_FIELD_PRIORITY/OUTPUT_FIELD_PRIORITY取输入输出内容,并展示running_status、func_id(带复制按钮)、func_type、executionTime、start_time等状态信息。 - 导出:ExportBtn 先调
GET /trace/count预估数据量,超过maxDownloadCount = 100000条时提示缩小时间范围并禁用导出;确认后调GET /trace/download(responseType: 'blob')下载 Excel,从Content-Disposition解析文件名,并支持AbortController中途取消。
六、这套组织方式带来的收益
文档归纳了五点优势,结合源码可以具体对应到实现上:
- 统一管理:常量(
SEPERATOR)、表格配置(columnsMap/requiredOptions/checkboxOptions)、工具函数全部经 config/index.ts 单一出口; - 清晰分类:
utils.ts内部按"数据处理 / 时间处理 / 参数生成 / 权限校验"分区组织,注释标明每个函数的参数与返回值约定; - 类型安全:
DataType、TimeOption由type.d.ts统一导出,TraceData/TraceNode由utils.ts导出,表格Table<DataType>、弹窗record?: DataType | null等位置均获得类型约束; - 易于维护:例如调整时间档位只需改
timeRangeMap一处,下拉选项、范围格式化、RangePicker 回显与日期校验四者自动一致; - 简化导入:页面、弹窗、导出组件的
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提交。
相关推荐
Astron Agent 前端 TraceLogs 配置模块深度解析:从统一配置入口到调用链树的可观测实践
Astron Agent 前端 TraceLogs 配置模块深度解析:从统一配置入口到调用链树的可观测实践 本文以 astron agent 控制台(conso
人工智能AI AgentAgent 编排RPA后端前端企业应用PMD 日志机制深度解析:基于 SLF4J 的统一日志体系与配置实战
PMD 日志机制深度解析:基于 SLF4J 的统一日志体系与配置实战 PMD 是采用可扩展多语言架构的静态代码分析器,其内部所有日志统一通过 SLF4J 门面(
静态分析代码质量Metro 配置体系全解:metro-config 的类型系统、默认配置与加载合并机制
Metro 配置体系全解:metro config 的类型系统、默认配置与加载合并机制 Metro(React Native 官方 JavaScript 打包器
构建工具移动开发CLI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考