3
0

给 Agent 工具调用加日志时,我会先做一条可回放事件流

最近给一个内部自动化 Agent 补工具链日志时,我发现最耗时间的部分并非接入模型或注册工具,而是失败之后很难复盘。用户只看到“任务没做完”,控制台里只剩一段模型返回和几条工具报错。真正需要回答的问题更细:模型为什么选了这个工具,入参从哪里来,工具返回了什么,重试有没有改变现场,下一轮提示词又消耗了哪些结果。

Agent 工具调用事件流与回放调试流程图

从用户请求、模型规划、工具调用、事件存储到回放调试的可观测链路示意图 来源:Codex image generation

问题背景

这个 Agent 负责把需求拆成小任务,再调用文件搜索、代码读取、Gmail 草稿和日历查询这类工具。OpenAI 的 function calling 文档把工具调用描述为让模型访问应用提供的数据和动作,并要求工具输出能对应到具体的 call_id。这给了我一个很直接的提醒:工具调用本身就是一条业务事件,不能只当成一次普通函数执行。

早期实现只有两类日志,一类是模型原始响应,一类是工具函数内部打印。它们各自有时间戳,却缺少统一的 trace_id、轮次编号和父子关系。问题一旦跨过两三个工具,排查就会变成手工拼图。更麻烦的是,很多工具入参包含用户文件名、邮件摘要或内部路径,不能把原文无脑写进日志系统。

关键难点

第一个难点是事件粒度。只记录“工具成功”没有价值,至少要拆出 tool.requestedtool.startedtool.succeededtool.failedmodel.completed。第二个难点是关联。OpenTelemetry 文档里把 span 视为一次工作单元,并说明上下文传播可以把不同位置产生的 span 组装成一条 trace。Agent 工具链也需要同样的骨架,否则模型轮次、工具执行和前端展示会散在三套上下文里。

第三个难点是回放。可回放并不等同于重新访问真实外部系统。邮件、日历和文件写入这类工具都有副作用,直接重跑可能制造新的状态。我更倾向把工具输出分成两份:一份脱敏摘要用于检索,一份加密或本地受控保存用于调试回放。回放时默认使用录制结果,只有开发者显式打开开关才会重新调用真实工具。

解决思路

我把每次 Agent 运行抽象成一条只追加的事件流。入口层生成 trace_idrun_id,每一轮模型调用生成 turn_id,每个工具调用生成 step_id,并保留 parent_step_id。事件公共字段包括 event_typetool_nametool_call_idschema_versionstatusstarted_atended_atduration_msinput_hashinput_previewoutput_summaryerror_code

这里我没有把 OpenTelemetry 当成唯一存储。它适合连接分布式链路,W3C Trace Context 也已经定义了通过 HTTP header 传播上下文的标准方式。但 Agent 调试还需要业务语义,例如工具 schema 版本、模型轮次和脱敏后的入参摘要。所以我会同时做两层:OTel span 用于跨服务定位耗时和错误,JSONL 事件流用于产品侧回放和问题归档。

关键步骤

落地时我先封装一个 AgentEventRecorder。模型请求前写入 model.started,响应后写入 model.completed,如果模型发起工具调用,就把每个 call_id 映射到内部 step_id。工具执行器只接受带上下文的调用对象,禁止直接调用裸函数。这样工具内部即使失败,也能通过统一拦截器补齐状态、耗时、错误摘要和可展示的输入预览。

第二步是做脱敏策略。入参先按字段类型处理,邮箱、token、路径和长文本只保留 hash、长度和少量可读片段。第三步是做回放面板。前端按 trace_id 拉取事件流,左侧显示轮次和工具树,右侧显示模型摘要、工具入参预览、输出摘要和错误栈。LangSmith 的 trace 视图文档里也强调,查看 agent thread 时应能看到模型响应、工具调用和工具结果,这和我想做的排查入口很接近。

可复用经验

Agent 工具链的日志要尽早设计成产品能力。等线上出现复杂失败,再补字段通常会漏掉关键上下文。我的经验是先稳定三件事:统一 trace id,统一事件 schema,统一脱敏边界。只要这三件事存在,后面无论接 OpenTelemetry、LangSmith,还是自建一个轻量回放页,都有可用的数据底座。对 AI 应用来说,可观测性不是额外装饰,它直接决定团队能不能把一次失败变成下一次迭代的材料。

主要来源

OpenAI Function Calling

OpenTelemetry Traces

OpenTelemetry Baggage

W3C Trace Context

LangSmith View Traces

评论