关于 Agent 可观测性的标准建议只有三个词:记录完整 trace。捕获每一次工具调用、每一个 prompt、每一条模型响应、每一次内存读写。团队照做了。接着第一个真实故障发生了,工程师打开 trace,发现它有 40 层工具调用深,20 万个 token 宽。从技术层面看,trace 是完整的;但从实践层面看,它完全不可读。
接下来是熟悉的仪式。工程师不断滚动屏幕。他们展开一个 span,看到 5 万个字符的 JSON,折叠它,再次滚动。十分钟后,他们终于找到了那个模型选错工具的回合——它被埋在 37 个完全符合预期的回合之间。原本旨在让故障清晰可见的 trace,反而增加了排查成本。
这并不是工具上的短板。任何可观测性供应商都会很乐意摄取你的 Agent span,而且 OpenTelemetry GenAI 语义约定现在已经为你提供了 invoke_agent、chat 和 execute_tool 等 span 的清晰 schema。真正的差距在于观念。我们沿用了一套对“可观测性”的定义——“我们捕获它了吗”——这对于请求-响应式服务是正确的,但在 Agent 领域却悄然失效了。对于 Agent 来说,捕获是最简单的部分。最难的部分,即决定一个故障是在 20 分钟还是两天内解决的关键,在于人类能否在故障发生的热度期内,找到那一个真正关键的关键点。
捕获的完整性不等于可观测性策略
在传统服务中,一个 trace 可能只有 5 到 15 个 span,其结构与你脑海中已有的调用图是一致的。你在看之前就知道它的形状。调试主要是按顺序读取 span,并留意哪一个是红色的。
Agent trace 打破了这三个假设。首先,它的结构是涌现的——Agent 决定采取多少步骤、调用哪些工具以及何时循环,因此在你读完之前,你并不知道它的具体形状。其次,数据量是巨大的——一个包含 8 次工具调用的运行通常会产生 5 万个 token 的日志输出,而一个携带完整 prompt 的 span 本身就可能有 20 万个字符的 JSON。最后,故障很少表现为红色的 span。Agent 并没有崩溃。它返回了 200,完成了任务,并给出了一个错误、缓慢或不再需要的答案。Trace 中没有任何部分被标红,因为从技术上讲,没有任何步骤失败。
因此,“记录一切”产生的 trace 中,关键信号(改变结果的那三个步骤)在统计学上被 37 个正常的步骤淹没了。工程师的工作变成了一个没有索引的搜索问题。在处理故障的压力下,搜索是让工程师做的最糟糕的事情,因为搜索的代价是你最稀缺的资源:在上下文变冷、值班工程师转移注意力之前的宝贵时间。
这里还有第二个、更隐蔽的失败。有关 AI 可观测性成本的行业报告指出,团队在接入 Agent 工作负载后,账单增加了 40% 到 200%,因为思维链(chain-of-thought)trace 产生的遥测数据是同等 API 调用的 10 到 50 倍。因此,“记录一切”的直觉并不是免费的。你正在为庞大且不断增长的存储账单买单,而这些数据在你真正需要它的那一刻,首要作用却是拖慢你的速度。这是一种奇怪的优化方向。
决策主干:人类最先真正需要什么
当工程师在故障期间打开 Agent trace 时,他们并不是在问“Agent 做了什么”。他们问的是一个更窄的问题:“哪里出错了”。这个问题的答案几乎从不隐藏在 token 级别的细节中,而是在决策中——Agent 追求的目标、它选择的工具、以及它本可以走两条路却选择了其中一条的分歧点。
我们称之为决策主干(decision spine)。它是运行的骨架:一份简洁、有序的列表,记录了 Agent 决定了什么以及为什么要这么决定,去除了 prompt 主体和工具负载。一个包含 40 次调用的 trace,其决策主干可能只有 20 行长。它可以完整地显示在一个屏幕上。工程师可以在 15 秒内读完它并提出假设——“它在第九步用空查询调用了 search_orders,这就是偏差所在”——而无需展开任何一个 token 级别的 span。
Token 级别的细节仍然重要。当你需要它时,你需要它的全部。但它是参考资料,而不是首页。架构上的转变是将“主干”和“细节”渲染为两个独立的层,以主干为默认视图,细节则一键即达。目前大多数可观测性工具都把这个关系倒置了:它们向你展示完整的 trace 树并让你钻取(drill in)。对于 15 个 span 的服务 trace,钻取没问题;但对于 40 个 span 的 Agent trace,钻取只是增加了额外步骤的滚动问题。
构建主干并非没有成本,但相对于它节省的成本来说,它是廉价的。每个模型回合都已经声明了它的意图——gen_ai.response.finish_reasons 字段会告诉你它是否停下来调用工具,工具名称和简短的参数摘要就在 span 中。在摄取时或首次打开时对 trace 进行一次简短的摘要处理,就能将“已做出的决策”转化为一行可读的文字。昂贵的不是生成主干,昂贵的现状是——每一位工程师每次都要通过不断滚动,在自己的脑海中重新构建那个决策主干。
跳转到分叉点
决策主干告诉你会发生了什么。它本身并不能告诉你运行是在哪里偏离轨道的。这是两个不同的问题,后者值得拥有专属的功能支持。
大多数 Agent 运行都有一个预期轨迹——即正常路径(happy path)的大致形状。一个支持 Agent 会对工单进行分类、查找账户、检查相关政策,然后起草回复。当运行失败时,几乎总是因为它在一个可识别的点偏离了那个形状:它跳过了账户查找,或者在分类上循环了四次,或者调用了一个正常路径从未触及的工具。可观测性工具能做的最有价值的事情就是指向那个分叉点并说:就是这里。
实现这一点并不需要任何深奥的技术。如果你拥有一系列成功的 trace 样本——你确实拥有,因为成功的情况占绝大多数——你就可以推导出每种任务类型的预期步骤分布。一个通常需要 4 步完成的任务类别,如果某次运行出现了 14 步,那么它就在发生分叉。如果一次运行调用了一个在成功 trace 中出现概率仅为 2% 的工具,它也在发生分叉。如果一次运行使用相同的参数重复访问同一个工具,它就是在循环。检测这些都不需要模型;它们只需要将一个 trace 与其他 trace 的形状进行对比,这是一个查询操作,而不是一个研究项目。
这样做的好处是,工程师可以停止滚动屏幕并直接从答案开始。工具不再是说“这里有 40 个步骤,祝你好运”,而是说“这次运行在第 9 步偏离了常态——它调用了 search_orders 且查询语句为空,这在成功的 trace 中从未出现过。”这句话本身就是整个调查结果,在工程师阅读任何内容之前就已经呈现出来了。Salesforce 最近在 Agent 平台 trace 方面的工作也押注了类似的思路:只有当工具能将你引导至关键节点,而不是把整棵树都扔给你时,trace 树才是有用的。
严重程度属于事件模型,而非日志级别
让 trace 变得难以阅读的第三个原因是,每个事件看起来都同样重要。内存读取、常规工具调用,以及模型幻觉出一个不存在的 API 的那次轮次,都只是 span。trace 格式对于调查人员应该首先查看哪一个没有倾向性。
解决办法是将严重程度(severity)作为事件模型的一等字段(first-class field),在事件生成时即分配,而不是作为一个事后补救的 log.level 字符串。有些事件是常规的,默认应该折叠:成功的工具调用、返回预期数据的内存读取。有些是值得注意的,应该可见:工具返回空结果、一次重试、或者模型轮次忽略了工具的输出。有些则是决定性的,绝对不容错过:触发了护栏(guardrail)、Agent 掩盖了工具错误、运行中途置信度骤降。
当严重程度成为一个真实的字段时,trace 查看器就可以完成工程师目前手动完成的工作。它可以先显示三个决定性事件,然后是值得注意的事件,并将占大多数的常规事件折叠在“显示全部”开关后面。工程师在看到噪音之前就能看到失败的轮廓。信息一直都在 trace 中;标记严重程度只是为了拒绝让步,不再强迫人类在压力之下每次都重新推导这些信息。
这所需的规范位于可观测性工具的上游。Agent 框架或插桩层(instrumentation layer)必须在事件发生的那一刻知道它是常规的还是决定性的。对于每个事件来说,这只是一小部分工作,但对于每次事故处理来说,这都是巨大的杠杆。这与选择合适的异常类型而不是通用的 Error 是同一个道理:在抛出点的小额投入,可以节省下游所有人的猜测成本。
保留策略:失败需要高保真,成功只需摘要
一旦你接受了决策主干承载了大部分调试价值,你的保留策略就不必再是“将所有内容保留 30 天”。这种策略是两头不讨好——它很昂贵,因为完整的 trace 非常庞大;它又没用,因为你保留的数据没人读得懂。
更好的策略是不对称的。对于失败的运行——以及你为评估(eval)和回归基准保留的一小部分成功样本——保留完整的高保真数据:每个 prompt、每个 payload、每个 token。这是深度调查所需的材料,且失败只占总量的一小部分,因此成本是受控的。对于绝大多数成功的运行,保留决策主干,并在短时间后丢弃 token 级别的正文内容。你依然保留了计算轨迹常态、分摊成本和发现偏移的能力,同时去掉了增长最快的存储开销项。
这颠覆了通常的直觉,即在统一的 TTL 删除它们之前,将所有 trace 一视同仁。它们并不平等。一个成功的运行主要在宏观统计上有价值——作为正常行为分布中的一个数据点。而一个失败的运行则在个体上具有完整价值,因为有人会去逐行阅读它。把你的存储预算花在有人真正会去阅读的字节上。
瓶颈已经转移,而工具尚未跟上
对于请求-响应式服务,可观测性确实曾是一个采集问题。如果你记录了 trace,你就能读懂它,因为 trace 的体积很小且结构已知。整个行业的直觉——监控一切、保留一切、在需要时深入挖掘——都是针对那个世界进行校准的,而且行之有效。
Agent 打破了这种平衡。现在的 trace 变得足够大、足够具有涌现性,且失败时足够“安静”,以至于采集不再是难点。难点在于时间压力下的可读性:在故障发生的时刻,一个注意力窗口正在关闭的具体的人,能否找到那个最关键的步骤。一个在回答“我们记录了吗”时信心满满地给出肯定答案,但在回答“你能找到问题吗”时却需要滚动页面十分钟的 trace,是不具备可观测性的。它只是一个披着可观测性外衣的只写日志。
解决方法既不是增加采集,也不是减少采集。而是在你已有的采集之上增加第二层:将“决策主干”作为默认视图,使用“分歧检测器”让工程师直接从答案开始,将“严重程度”设为真实字段以便让决定性事件优先浮现,并采用非对称保留策略,将精度花在有人会去阅读的地方。这些都不需要新的基础设施。它们需要你把那个在凌晨 2 点打开 trace 的人,视为可观测性技术栈的真正用户——并诚实地自问,你捕获的 trace 是为他们构建的,还是仅仅为了填满存储桶。
会员专享
余下内容仅对会员开放。
会员可读完整内容 —— 每一个公开发布的观点背后,那些框架、决策与推理的全貌。
- —完整文章,包含未公开存档的部分
- —可落地的工作框架,附带权衡与决策依据
- —新文章抢先看,先于公开发布
随时取消 · 一次订阅,畅读全部