为什么 Agent 必须有观测和 Tracing
文章目录
先说结论
普通软件没有日志很难排查,Agent 没有观测就几乎没法维护。
因为 Agent 不只是跑一次函数,它会:
- 读上下文
- 做判断
- 调工具
- 写结果
- 再继续下一步
这就意味着,你光看最终输出,往往根本不知道它中间哪一步跑偏了。
所以 Agent 一旦要上生产,观测和 tracing 就不是锦上添花,而是基本盘。
为什么日志不够
很多人一开始会说:我把输入输出记下来不就行了?
问题是,Agent 的问题通常不在最后一步,而在中间很多步。
比如:
- 检索结果错了
- 工具参数错了
- 上下文丢了
- 某一步重试太多次
- 某个失败没有触发降级
这些都不是"看最终答案"能发现的。
Tracing 的意义就在于,把每一跳都记下来,让你知道它到底在哪一跳变形了。
该记录什么
真正有用的观测信息,通常不是一堆杂乱日志,而是这些:
- 任务目标
- 每一轮输入
- 每一步工具调用
- 工具返回结果
- 失败原因
- 重试次数
- 最终是否达到停止条件
这样你回头看一条轨迹,就能知道:
- 它当时想干什么
- 它实际做了什么
- 它为什么停在这里
Agent tracing loop This diagram shows how a traced agent records the goal, tool calls, outputs, failures, and retry decisions for debugging and evaluation. Trace 工具 Agent 用户 Trace 工具 Agent 用户 #mermaid-svg-QLemEFqmFzJeV2A0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-QLemEFqmFzJeV2A0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-QLemEFqmFzJeV2A0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-QLemEFqmFzJeV2A0 .error-icon{fill:#552222;}#mermaid-svg-QLemEFqmFzJeV2A0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QLemEFqmFzJeV2A0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-QLemEFqmFzJeV2A0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QLemEFqmFzJeV2A0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QLemEFqmFzJeV2A0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-QLemEFqmFzJeV2A0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QLemEFqmFzJeV2A0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QLemEFqmFzJeV2A0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QLemEFqmFzJeV2A0 .marker.cross{stroke:#333333;}#mermaid-svg-QLemEFqmFzJeV2A0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QLemEFqmFzJeV2A0 p{margin:0;}#mermaid-svg-QLemEFqmFzJeV2A0 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-QLemEFqmFzJeV2A0 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-QLemEFqmFzJeV2A0 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-QLemEFqmFzJeV2A0 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-QLemEFqmFzJeV2A0 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-QLemEFqmFzJeV2A0 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-QLemEFqmFzJeV2A0 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-QLemEFqmFzJeV2A0 .sequenceNumber{fill:white;}#mermaid-svg-QLemEFqmFzJeV2A0 #sequencenumber{fill:#333;}#mermaid-svg-QLemEFqmFzJeV2A0 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-QLemEFqmFzJeV2A0 .messageText{fill:#333;stroke:none;}#mermaid-svg-QLemEFqmFzJeV2A0 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-QLemEFqmFzJeV2A0 .labelText,#mermaid-svg-QLemEFqmFzJeV2A0 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-QLemEFqmFzJeV2A0 .loopText,#mermaid-svg-QLemEFqmFzJeV2A0 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-QLemEFqmFzJeV2A0 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-QLemEFqmFzJeV2A0 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-QLemEFqmFzJeV2A0 .noteText,#mermaid-svg-QLemEFqmFzJeV2A0 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-QLemEFqmFzJeV2A0 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-QLemEFqmFzJeV2A0 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-QLemEFqmFzJeV2A0 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-QLemEFqmFzJeV2A0 .actorPopupMenu{position:absolute;}#mermaid-svg-QLemEFqmFzJeV2A0 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-QLemEFqmFzJeV2A0 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-QLemEFqmFzJeV2A0 .actor-man circle,#mermaid-svg-QLemEFqmFzJeV2A0 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-QLemEFqmFzJeV2A0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} alt 结果不合格 结果合格 提交任务 记录目标和上下文 调用工具 返回结果 记录输出和状态 记录失败原因 重试或换工具 返回最终答案
观测能帮你看见什么
第一,成本。
哪一步最耗 token,哪一步最耗时间,一眼就能看出来。
第二,稳定性。
是不是总在同一个步骤失败。
第三,行为漂移。
今天和昨天同样的任务,为什么路径不一样。
第四,评估问题。
答案看起来对,不代表过程是对的。trace 能帮你区分这两件事。
最容易忽略的点
第一,只记结果,不记过程。
这跟没记差不多。
第二,只看单次执行,不看分布。
Agent 的问题往往是模式问题,不是单次事故。
第三,没把 trace 和评测连起来。
记录下来不是为了收藏,而是为了后续改进。
第四,观测太重。
如果每一步都记录得过于复杂,反而会拖慢系统。
结尾
Agent 和普通脚本最大的区别,不只是能做事,而是会在多步推理和多轮执行里不断变化。
这种系统如果没有 tracing,就像闭着眼开车。
你知道它到了终点,
但你不知道它中间是不是差点冲进沟里。