一句话定义
Agent 可观测性是记录每次运行的完整轨迹(trace:每轮的输入上下文、模型输出、工具调用与结果、成本时延)并让它可搜索、可回放、可归因的工程——传统软件看日志,Agent 看 trace;因为 Agent 的 bug 是分布与轨迹的 bug,不是单行堆栈的 bug。
为什么重要
调试一个"100 次里失败 8 次"的 Agent,你手里唯一的东西就是那 8 次的轨迹(kp-024 的失败用例归因全靠它)。没有 trace 时,开发者只能复现碰运气(采样随机性让复现困难),或者盲改提示祈祷。有 trace 时,"8 次失败里有 6 次发生在第 14 轮调用 read_file 返回空之后"这样的模式一眼可见。trace 还是上一层的供血系统:审批策略修订(kp-023)、安全审计(kp-026)、成本核算(kp-027)都消费它。
前置知识
kp-012(ReAct 轨迹结构)、kp-024(评测循环里的归因环节)。
核心概念
Trace 的层级结构
trace(一次用户任务,run_id)
├── span: LLM 调用 #1
│ ├── 输入:messages 摘要 + token 数
│ ├── 输出:文本/tool_use + stop_reason
│ └── 属性:模型、温度、延迟、成本、缓存命中率
├── span: 工具调用 get_weather
│ ├── 输入参数 / 输出(截断存储)/ 耗时 / 成功与否
├── span: LLM 调用 #2 …(循环 N 轮)
└── span: 子 Agent(嵌套 trace,kp-019)
└── (其内部又是一棵树)
记录的黄金清单
- 每轮的完整消息边界(哪个消息进、什么出来)——最少要存摘要+哈希,敏感场景全文落加密存储
- 工具的输入输出(截断 + 指向外部全文的指针,kp-022 思想)
- stop_reason 与终止方式(自然完成 / 步数上限 / 异常)
- 成本与延迟按 span 累计——哪个工具最贵、哪一轮最慢
- 版本戳:提示版本、工具集版本、模型版本——否则跨版本对比失真
三层观测面板(问三个问题)
- 这次为什么失败?(单 trace 回放——展开每轮看分叉点)
- 失败集中在哪?(聚合分析——按步骤/工具/用户分群统计失败率,找热点)
- 系统健康吗?(运行时指标——成功率、p95 延迟、token/任务、审批拦截率、注入尝试次数)
调试工作流(与评测闭环咬合)
评测发现失败用例 → 打开 trace → 找"分叉 span"
(首个使后续走向错误的决策/观察)→ 三选一定位:
a) 上下文问题(该看的信息没看到/被淹没)→ kp-003/022
b) 工具问题(描述/返回误导)→ kp-010
c) 模型能力问题(看到了还是选错)→ 换模型/加 few-shot/上反思
→ 修复 → 评测回归
原理与机制
为什么 Agent 必须用 trace 而不是日志行?两个结构性原因:执行是树形的(子 Agent、并行工具、重试产生嵌套与分叉,平面日志无法表达因果);故障是轨迹性的(第 14 轩的失败种子可能埋在第 3 轮的错误观察里——必须看整条路径才能归因,kp-012 的案例已经演示过)。
技术栈事实标准:OpenTelemetry GenAI 语义约定(2024-25 推进中)统一了 span 命名(gen_ai.xxx),LangSmith、Langfuse、Braintrust 等平台与主流框架都已兼容——选型时确认 OTel 兼容性,避免锁死。自研路线 = OTel SDK + 任意后端(Jaeger 起步够用)+ 消息脱敏中间层。
一个务实的机制细节:消息体很大,trace 存储按"摘要入库 + 全文对象存储(S3)+ 指针"分层,配合采样策略(失败全存、成功抽 1%)控制成本——这本身就是 kp-022 分层思想在观测域的应用。
直观类比
传统日志是飞机的黑匣子文字稿(一串事件);Agent trace 是整个驾驶舱的飞行数据记录 + 驾驶舱录音——你不仅知道"引擎在 14:32 停了",还能回放副驾驶(模型)当时看到了哪块仪表(上下文)、说了什么(Thought)、按了哪个开关(工具)。空难调查(失败归因)需要的是后者。
实例与案例
用 trace 定位一个"偶发答案张冠李戴"的案例:
聚合面板:失败 12/150,其中 9 次集中在"多客户批量"任务
打开一条失败 trace:
span#7 tool: query_orders(customer="A公司") → 412 条
span#8 LLM: (Thought 提到"B公司的订单里…")★ 分叉点
——工具返回的是 A 公司数据,模型却开始谈 B
回看 span#7 前的上下文:B 公司名出现在 40 轮前的旧摘要里
归因:压缩摘要(kp-022)引入了陈旧实体名
修复:摘要规则加"实体名必须带时间戳/状态"
回归:该分群失败率 9/150 → 1/150
没有 trace 时,这个案例的典型结局是"无法复现,不了了之"。
常见误区
- 误区一:只记输入输出,不记中间轮。分叉点几乎总在中间——完整轮次边界不能省。
- 误区二:trace 全文入库无脱敏。用户 PII 进观测库 = 第二个合规炸点(kp-026);脱敏在写入前做。
- 误区三:版本不落戳。跨模型版本对比 trace 却不知道当时的提示版本,归因归了个寂寞。
- 误区四:只建不看。面板没人看的观测是成本不是资产——把"失败 trace 例会"(每周抽 3 条失败集体归因)固化成流程。
- 误区五:忽视成功样本。失败找病因,成功样本找"隐性最佳实践"(某次它用了意外但优秀的路径)。
自测题
- Agent 为什么必须用树形 trace 而非平面日志?
- "分叉 span"是什么?为什么调试从它入手?
- trace 记录的黄金清单五项是什么?
(参考答案:1. 执行是嵌套树形(子Agent/并行/重试),故障是轨迹性的(种子在早前轮次);2. 首个使后续走向错误路径的决策/观察——改它之前的一切都是沉没正常;3. 消息边界、工具输入输出、终止方式、成本时延、版本戳。)
与其他知识点的关系
- 评测归因 → kp-024;上下文问题的修复 → kp-003/022
- 审批与安全审计消费 trace → kp-023/026;成本分析 → kp-027
延伸阅读
- OpenTelemetry, GenAI Semantic Conventions(进行中规范)
- LangSmith / Langfuse 文档的 tracing 章节(两者免费档均可起步)