多Agent上生产的第一课:日志、轨迹、回放与责任归因
单Agent出了问题,你打开对话记录从头看一遍就知道哪里错了。
多Agent出了问题,你可能连是哪个Agent干的都不知道。Lead Agent说它已经把任务分发下去了,Sub Agent A说它完成了自己的部分,Sub Agent B也说完成了。但最终结果是错的。谁的锅?
我在生产环境跑多Agent踩过这个坑。排查了两个小时,最后发现是Sub Agent A的输出格式跟Sub Agent B的预期不匹配,Lead Agent没有做格式校验就直接传递了。三个Agent都没报错,但结果就是废的。
从这件事之后,我把可观测性放到了多Agent系统的第一优先级。
01 第一层:日志
日志是最基础的。每个Agent的每次操作都要留痕。
一条合格的Agent日志至少包含这些字段:时间戳、Agent ID、动作类型(工具调用/LLM请求/消息传递)、输入参数、返回结果、耗时、token消耗。
很多人写日志只记"Agent调用了什么工具",不记参数和返回值。这在排查问题时几乎没用。你知道Agent调了一次文件读取,但不知道它读了哪个文件、拿到了什么内容。等你要回头查的时候,文件可能已经被改过了。
一个我在用的日志格式:
{
"ts": "2026-02-10T14:32:01Z",
"agent_id": "code-reviewer",
"action": "tool_call",
"tool": "read_file",
"params": {"path": "src/api/handler.ts"},
"result_length": 2847,
"duration_ms": 120,
"tokens_in": 0,
"tokens_out": 0
}
LLM请求的日志要单独存。因为prompt内容通常很长,跟其他日志混在一起会导致日志文件膨胀到不可读。我的做法是主日志里记一个请求ID,详细的prompt和response存到独立的文件里。需要时按ID去查。
02 第二层:轨迹
日志是一条一条的记录。轨迹是把这些记录串成一条线,还原一个任务从开始到结束的完整路径。
一个典型的多Agent任务轨迹:
- 用户发起任务:"给这个API加上分页功能"
- Lead Agent分析任务,决定拆成两个子任务:修改数据库查询层、修改API响应格式
- Lead Agent把子任务1分发给Agent A(数据库专家)
- Agent A读取了当前的查询代码,调用了3次工具,生成了修改方案
- Agent A把结果返回给Lead Agent
- Lead Agent把子任务2和Agent A的结果一起发给Agent B(API专家)
- Agent B基于Agent A的修改,调用了4次工具,完成API层的修改
- Agent B返回结果
- Lead Agent汇总,返回给用户
轨迹要记录每一步之间的数据流。步骤3里Lead Agent发给Agent A的具体指令是什么?步骤5里Agent A返回的具体内容是什么?步骤6里Lead Agent有没有对Agent A的结果做二次加工?
没有这些信息,你在出问题的时候只能看到起点和终点,中间的传递过程是黑盒。
03 第三层:回放
能不能用同样的输入重现同样的执行路径?
理论上,如果你完整记录了每一步的输入输出,应该可以回放整个执行过程。实践中很难做到。
第一个障碍是LLM的非确定性。即使temperature设为0,同样的prompt在不同时间点跑出的结果也可能不同。模型供应商的服务端可能更新了权重、调整了推理参数,这些对你是透明的。
第二个障碍是外部状态。Agent在执行过程中读取了文件系统、调用了API、查询了数据库。回放时这些外部状态可能已经变了。你不能回到任务执行时的文件系统快照。
我的折中方案:不追求完美回放,追求"可解释的回放"。记录每一步的实际输入和实际输出,回放时用这些记录来还原逻辑链路,而不是真的重跑一遍。这样至少能回答"当时发生了什么",即使不能"重现当时的情况"。
对于关键任务,可以更进一步:在执行时把外部依赖的快照也存下来。Agent读了某个文件,就把那个时刻的文件内容存一份。Agent调了某个API,就把API的响应存一份。空间换可追溯性。
04 第四层:责任归因
出错时能定位到具体的Agent和具体的步骤。
这需要两个前提。第一是清晰的任务边界。每个Agent负责什么,输入是什么,输出是什么,要在任务分发时就定义清楚。如果Lead Agent给Sub Agent的指令是模糊的"帮我处理一下这个文件",出了问题你分不清是指令不清楚还是执行不到位。
第二是审计日志。不只是记录Agent做了什么,还要记录Agent为什么做这个决定。LLM在生成工具调用之前通常会有一段推理文本(thinking),这段文本对责任归因很有价值。它能告诉你Agent是基于什么判断选择了这个操作。
GitHub上有一个社区项目dylan-gluck/cc-dev-team,它做多Agent协作开发,里面提到了几个做法:实时可观测性、状态管理、智能hook。状态管理这一点我觉得说得好——每个Agent在执行过程中的状态变化(空闲→接收任务→执行中→等待依赖→完成)都应该被追踪。状态的异常变迁(比如从"执行中"直接跳到"空闲",跳过了"完成"状态)往往就是问题的信号。
05 Anthropic团队自己怎么做
Anthropic在他们的博客里提到过,内部安全团队用多Agent做生产问题诊断,问题诊断速度提升了3倍。
3倍提升的前提是他们有完整的观测体系。安全团队的多Agent系统能接入内部的日志平台、监控仪表盘、告警系统。Agent不是在黑盒里工作,而是在一个充分透明的环境里。
对于我们普通开发者,没有那么完善的基础设施,但思路可以借鉴。让Agent的执行环境尽可能透明。它读了什么、调了什么、判断了什么,都应该有记录。
06 一个最小可行的观测方案
如果让我推荐一个成本最低的方案,三个东西。
结构化日志。用JSON格式写日志,每条包含时间戳、Agent ID、动作、参数、结果。不要用纯文本日志,纯文本在后续分析时解析成本很高。
执行轨迹文件。每个任务生成一个轨迹文件,把这个任务涉及的所有Agent的所有操作按时间排列。文件名用任务ID命名,方便按任务检索。
错误快照。每次任务失败时,自动把当时的完整上下文存一份:所有Agent的日志、任务的输入、每个Agent的输出、失败时的错误信息。这些失败样本积累起来就是一个案例库。下次遇到类似的失败,先去案例库里搜一下,可能有现成的解决方案。
三样东西加起来,写代码大概一到两天的量。但它能把排查时间从"两小时翻聊天记录"缩短到"五分钟查日志"。
多Agent系统的可观测性投入,回报率远高于在prompt上反复调优。prompt调得再好,出了问题看不到执行过程,还是得靠猜。
参考链接:
- dylan-gluck/cc-dev-team项目:https://github.com/dylan-gluck/cc-dev-team
- Anthropic团队如何使用Claude Code:https://www.claude.com/blog/how-anthropic-teams-use-claude-code
- Claude Code多Agent团队文档:https://code.claude.com/docs/en/agent-teams
- Anthropic多Agent系统构建指南:https://claude.com/blog/building-multi-agent-systems-when-and-how-to-use-them