首页 / 文章

当控制面板显示正常而代理却出错时:状态追踪

控制面板显示为绿色,但代理的判断有误:故障隐藏在正常步骤之间传递的状态中。需要记录哪些追踪信息、路由记录以及评估数据。

发布者:REACTAPP.TOP阅读约 12 分钟2749 词

来源: When the Dashboard Is Green and the Agent Is Wrong: Tracing Multi-Step Failures Past the LLM Call

绿色的控制面板与错误的答案

调试人工智能代理时有一个令人恼火的特性:监控界面会显示一切正常。模型调用已完成,工具也运行结束,API返回了200状态码,延迟值在正常范围内,令牌使用量也符合预期。从基础设施的角度来看似乎没有任何问题,但最终结果却可能完全错误。

这并非那种模型编造荒谬内容的明显错误类型。这类故障相对容易处理,因为至少你知道从何处入手。更棘手的是那种每一步看起来都合理,没有技术上的崩溃,且答案足够可信,以至于有人可能会据此采取行动的错误类型。

随着系统从单纯的LLM调用演变为智能体与多步骤工作流,这一问题愈发严重。在响应生成之前,相关数据可能已经经过多个模型、工具、API、转换环节和路由处理,因此最终模型处理的或许已是五步之前就已出现错误的状态。这一方面的智能体可观测性亟需更多关注。

无人察觉的架构变更

以一项常规的客户成功任务为例:智能体需要找出那些续费时间在30天内的客户,标记出可能流失的账户,并为成功团队起草报告。在此过程中,它可能需要查询CRM系统、计算风险评分、获取最近的客服记录、检查产品使用情况,最后由LLM来撰写报告。

现在假设CRM系统更改了其响应架构。昨天的数据格式是这样的。

{
  "health_score": 42
}

今天它看起来是这样的。

{
  "health": {
    "score": 42
  }
}

API仍在运行,请求依然成功,JSON也能正常解析。根据集成代码的不同,可能根本无需抛出任何异常。真正的问题出现在后续阶段:标准化层不断查找health_score,而最终得到的却是null。

也许风险评分机制会将缺失的值视为中性,又或者说明要求使用手头现有的任何数据。无论哪种情况,工作流程都会继续进行,最终生成一份看似合理的报告,却遗漏了团队需要了解的信息。

人们往往只盯着最终生成的结果,便轻易将模型视为罪魁祸首,于是开始重写提示词、更换模型或调整温度参数,却从未触及真正的根本原因。一个更好的问题是:状态究竟在何时首次出现错误?有了这个疑问,调试智能体就会变得完全不同。

成功事件并不能证明理解能力

一篇关于网络逐渐演变为智能体 API 的最新文章指出,软件的功能正在从单纯报告信息转变为为用户执行操作。文章认为,将工具暴露给模型只是其中的一部分,因为一旦智能体开始实际执行操作,意图、权限、运行时控制以及可审计性就变得至关重要。

调试这些操作时也是如此。虽然知道某个工具被执行了很有帮助,但这并不能说明工作流中的其他部分是否理解了该工具的输出结果。试想一下包含这类信息的追踪日志吧。

crm.search_accounts
status: success
duration: 184ms
records: 47

你了解到的是CRM返回了47条记录。但尚不清楚这47条记录在后续处理时是否都完好无损。也许还存在另外六页内容,而分页仅在第一页之后结束。也有可能是金额的单位从美元换成了美分,或者UTC时间戳被误认为是本地时间。又或者枚举值的拼写从“cancelled”变成了“canceled”,又或者API在HTTP状态看似正常的响应中开始报告应用层错误。

这些都是普通的软件漏洞。而处理人工客服时,问题在于后续模型通常会不管不问地继续处理,接收看似合理的数据并对其进行分析。因此,更强大的模型也未必能解决任何问题。如果输入数据从一开始就有误,模型只不过是用更高的技巧去解决错误的问题罢了。

在关键的节点上,你应该能够查看输入数据、输出结果、对响应施加的转换操作以及下一步实际得到的内容。没有必要永久保存所有的原始数据,但为在故障发生后能够重新复现流程,需要保留足够的信息。

追踪缺失的竞争者

相关工具正在不断改进。OpenTelemetry的GenAI语义规范开始标准化模型调用和工具执行的描述方式,而像OpenAI Agents SDK这样的框架则能够追踪生成过程、工具调用、数据传递以及各种限制条件。这些都是很有用的原始数据,但当工作流已经完成,实际故障隐藏在两个正常步骤之间传递的状态中时,要让这些追踪信息真正发挥作用仍然很困难。

以图中所示的简化流程为例进行思考。

假设最终报告缺少了本应出现的竞争对手。过去的做法是打开最终提示并检查模型的响应。也许指令不够明确,或者模型忽略了部分上下文,又或者换用其他模型会表现更好。但如今这种做法已不再合适。

应反向思考。最终模型是否获取到了缺失的竞争对手?如果没有,那么是在排序阶段出了问题吗?如果在排序之前就消失了,那在提取之后还存在吗?如果在提取后出现但在标准化后消失,那就说明问题恰好出在某个特定环节。

{
  "company": "Example Corp",
  "website": {
    "url": "https://example.com"
  }
}

而标准化步骤正是期望出现这种情况的。

{
  "company": "Example Corp",
  "website": "https://example.com"
}

整个过程并无什么戏剧性之处。进行到一半时,某个对象发生了形态变化,还有一个人在处理时出了差错,但周边的大多数操作看起来依然正常。这类故障值得深入追踪,因为如果不这么做,责任就会落在最显眼的那个组件上,而不管上游发生了什么。

实际得到的教训并不是必须使用某种特定的可观测性工具,而是追踪机制应该能让人们了解工作流中的状态变化,而不仅仅是列出哪些组件被执行了。仅仅知道第4步被执行了,与知道第5步从它那里接收了什么,之间存在着巨大差异。

计划偏移这一概念似乎合理

一旦发现工具边界故障,情况通常比较明确。而计划偏差则更难处理,因为智能体可能通过每一步都看似合理的操作偏离原始任务。想象一下,有个智能体被要求调研五家供应商,比较它们的价格和可靠性并撰写推荐报告,同时还被要求不得与这些供应商联系。

智能体找到了这些供应商并开始收集数据。其中两家没有公布价格,于是它设法寻找其他解决办法。最终它发现了一个可用的邮件工具。它的逻辑并不荒谬:需要价格信息,而这些价格又未公开,给供应商发消息就能解决这个问题。不过这样做也违反了任务中最重要的一条规则。

当这条规则仅位于不断扩展的上下文窗口顶部的一句文字时,一切都取决于在数千个搜索结果、工具输出及中间状态的内容堆积之后,模型是否仍会将其视为重要信息。那些会带来实际后果的约束应当以明确的形式呈现。

{
  "objective": "Compare suppliers and prepare a recommendation",
  "constraints": [
    "Do not contact suppliers"
  ],
  "completed_steps": [
    "discover_suppliers",
    "collect_public_pricing"
  ],
  "next_action": "request_missing_prices",
  "requested_tool": "send_email"
}

现在,该应用在执行操作前有了可以检查的内容。它可以选择拒绝工具调用、要求人工审批,或者让智能体寻找其他路径。正确的响应方式取决于工作流程,但关键在于约束不再完全依赖于提示语的表述。

诸如消费上限、“仅起草勿发送”或“绝不可触碰生产环境”之类的规则运作方式也是如此。通俗的语言有助于表达用户的意图,但那些重要的权限与限制也应体现为运行时的控制措施。

其他领域的软件也都是这样处理的。没人会只在注释里写“请勿让未经授权的用户删除数据库”就称之为访问控制,智能体也不应因为其指令是用英语写的就享有例外待遇。

模型路由设置了界限

路由也会引发类似问题。一旦需要在生产系统中权衡质量、成本、延迟、工具使用情况以及不同模型的功能,选择模型就不再只是一个简单的配置值,而路由决策也会成为调试时所需的追踪信息的一部分。

假设第6步通常在模型A上运行。在实时运行过程中,服务提供商的调用频率受到限制,于是路由器会切换到模型B。这正是按设计实现的备用方案,因为工作流程依然能够继续,而不会失败。不过模型B对传递给下一个工具的结构化参数的处理方式略有不同。这些参数依然有效,工具也能正常运行,但有一个字段的读取方式改变了后续的处理结果。

如果可观测性报告仅显示工作流中配置的模型,那么当实际出问题的请求是由模型B处理的时,人们可能会花费数小时试图在模型A上重现该故障。因此,追踪信息应当记录被请求的模型、实际响应的模型、任何备用方案、当前的路由策略,以及该调用是否为重试操作。这些信息虽不引人注目,但大多数实用的生产环境调试工具也是如此。除了演示之外,大部分工作就在于发现那些未被注意到的细微变化。

追踪状态,而不仅仅是事件

现在的代理工具能够很好地展示运行过程的形态,通过越来越实用的追踪视图呈现模型调用、工具使用、任务传递、重试以及其他各类事件。但一个错误观念是认为记录更多事件就能自动提升可观测性。即便有十个经过精心设计的监控节点,如果无法了解这些节点之间的状态变化,依然会陷入困境。

面对异常运行情况,列出几个关键问题会有所帮助:用户最初的需求是什么?有哪些约束条件?系统遵循了什么流程?每个工具返回了什么结果,下一步又接收到了什么?是哪个模型做出了每个决策?外部环境是否有任何变化?输出结果从何时开始不符合预期?

回答这些问题所需的数据量远少于全部数据,而试图记录所有内容又会带来诸多问题。提示词、工具参数及工具响应可能包含客户的隐私数据、凭证或其他敏感信息,这些内容不应未经考虑就上传到可观测性平台中。OpenTelemetry的GenAI指南指出了这一点,其详细的跨度规范要求对模型输入和输出的记录需用户主动选择,而非默认启用。

因此,目标应是让运行过程中的相关部分能够被重新构建,而非记录全部内容。有时只需处理后的响应即可,有时需要方案版本加上对象ID,还有些情况下由于其他方式无法重现该运行过程,必须对中间结果进行快照保存。需有明确的目的性,避免因事故导致仅保留status: success这样的信息。

这对评估意味着什么

轨迹可以解释发生了什么,但无法说明结果是否良好,因此仍需进行评估。Anthropic在其关于智能体评估的文章中也提出了相同观点。与单次回复相比,智能体更难评分,因为它们需要多轮交互、调用工具、改变状态,并根据之前的情况做出调整。

有些结果无需额外模型即可验证。如果被要求不要发送邮件的智能体却发了邮件,那就说明它失败了;而本应返回27条记录的提取任务只返回了11条,显然也存在偏差。其他一些情况则更难以界定:研究报告是否足够详尽?所用资料的质量如何?客服的回复是否解决了客户的问题?对于这类问题,可能需要人工审核、用户反馈、数据集或基于模型的评分工具来辅助判断。

真正的价值在于将评估与追踪过程相结合。存储的最终答案旁仅有一个“不满意”的标记,只能说明用户不喜欢它。而当这一信号与整个运行过程相关联时,就能让你查看所获取的资料、使用的工具、涉及的模型以及状态发生变化的具体位置。

一旦找到真正的故障原因,那次生产运行在事件发生后依然具有价值,因为它可以作为一个评估案例,用于防止在未来的提示词、模型或工作流程发生变化后再次出现同类问题。这远比逐一修复错误的答案并寄希望于其他部分不会出问题要好得多。

不要只从最终提示词开始分析

在调试人工智能系统时,最大的变化或许就在于此。在那些会给出错误答案的简单大型语言模型应用中,查看提示词与响应是可行的,因为问题几乎不可能出在其他地方。但随着系统规模扩大,这种做法的效果越来越差。试想一个包含多个模型、检索工具、搜索工具、外部API、路由器以及验证循环的流程:最终的错误很可能只是早期问题最终显现出来的结果而已。

RAG早已给出了教训:当检索系统将错误的文档放入上下文窗口时,更大的生成模型也无法修复这一问题,必须回溯去修正检索环节。智能体遵循相同的逻辑,只是多了更多约束条件。检索结果正常吗?看看最终输出如何。这也正常吗?再看看下一个决策。选对了工具吗?查看其参数与输出结果。状态仍然正确吗?持续推进,直到出现与预期不符的第一处偏差。

理论上这很简单,但人们却容易忘记,因为最终呈现的响应就在眼前,而且它通常是最容易被指责的对象。

整个流程的可观测性

智能体只会变得越来越复杂。MCP为它们提供了更多工具,多智能体设计增加了任务委托与交接机制,路由器能够实时选择模型,而长时间运行的工作流则带来了持久状态、重试及恢复功能。在运行过程中还可能需要人工审批,此外,通过浏览器或计算机运行的智能体还能对系统进行远超简单对话范围的修改。所有这些都会提升智能体的能力,但同时也让状态管理更容易出错,即便各个组件都报告成功也是如此。

正因如此,可观测性必须超越单纯的LLM指标。延迟、token数量、错误以及成本都很重要,仪表板当然应该能在智能体陷入循环或在凌晨2点耗尽API额度时发出警告。不过,这些数据主要只能说明系统是否在正常运转。多步骤智能体还需要一种方法来确认其处理流程仍符合用户的任务要求。

在实际操作中,这意味着要追溯最初的意图、关键约束条件、真正被使用的工具与模型、各步骤之间传递的状态以及最终结果。一旦出现错误结果,就应该能够回溯到状态首次与现实偏离的节点。具备这种能力后,一次失败的运行就会变成一个普通的工程问题,可以对其进行调查、复现和测试。如果没有这种能力,就只能盯着最终答案猜测系统中是哪个部分 earlier 出现了故障。

相关阅读

  • LangGraph多智能体系统:监督节点、子图与Send机制 — 从单个过载智能体扩展到多个智能体:监督节点路由、辐射式与汇聚式结构、子图、基于Send的映射归约,以及LangGraph中的完整多智能体研究工具。
  • 追踪检索步骤:六种可观测性工具在单个RAG智能体上的对比 — 通过Opik、MLflow、Langfuse、Phoenix、AcruxCore和Helicone对同一RAG流程进行工具化处理,比较各类装饰器、OTel、代理以及跨度类型词汇表的表现。
  • AI何时应该使用其记忆?关于持久记忆与阿谀奉承的实验 —— 获取记忆与让记忆影响答案并非同一回事。针对类型化记忆及影响控制器的小型实验显示,这些方法能在一定程度上减少阿谀奉承现象。
  • 工具集、循环、图结构:大多数生产环境中的智能体故障背后的三大层面 —— 为何在生产环境中失效的智能体很少是模型本身的问题:需要区分工具集、循环的停止条件以及图结构拓扑,并为每一部分指定负责人。
  • 实用指南:代理循环应在何时停止?DeepSeek Harness与Pi Give — 详细讲解实用指南《代理循环应在何时停止?DeepSeek Harness与Pi Give》:为采用该模式的团队提供的合同模板、检查清单及可直接插入的代码片段。
  • 代理审计日志需要12个字段:六大框架实际记录了哪些内容 — 对六大代理框架在12字段审计追踪草案中的覆盖情况进行的统计:平均覆盖率为12项中的5项,且没有任何框架能记录篡改证据或信任等级。
  • 当RAG以0.89的相似度检索到错误文档时:接近度与相关性之争 —— 为何高余弦值仍可能指向错误内容,欧几里得几何如何影响层级与时间关系,以及哪些缓解方法有效:混合搜索、重新排序、图结构。
  • 当AI智能体失败时,该责备谁?故障溯源指南 —— 为何“模型产生了幻觉”这一说法不够准确:从意图与检索到工具使用、重试与追踪的完整故障溯源过程,以及需要观察的关键点。