跳到主要内容

工具结果验证缺口:为什么 AI Agent 盲目信任每一个 API 响应

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的智能体调用一个工具,获取响应,并立即将其视为真理进行推理。没有 Schema 检查。没有新鲜度验证。没有针对响应预期形式的健全性测试。这是每个主流智能体框架的默认行为,它悄无声息地导致了一整类传统监控永远无法捕获的生产环境故障。

工具结果验证缺口是指“工具返回了某些内容”与“工具返回了正确内容”之间的地带。大多数团队痴迷于确保工具调用正确——选择正确的工具、生成有效的参数、处理超时。几乎没有人验证返回的内容。

工具结果失败的三种类别

并非所有糟糕的工具结果看起来都一样。理解这些分类很重要,因为每个类别都需要不同的防御措施。

**模式违规(Schema violations)**是最容易捕获且危险程度最低的。工具返回了格式错误的 JSON、缺失字段或意外类型。例如,天气 API 将温度作为字符串而不是数字返回。数据库查询在迁移后返回了列名已更改的行。这些故障是结构性的——JSON Schema 验证器可以在 LLM 看到响应之前捕获它们。

**陈旧数据(Stale data)**则更难对付。工具成功运行,返回格式良好的数据,且每个字段都通过了验证——但信息已经过时。你的智能体查询库存系统并得到 47 个单位的数量,但在 20 分钟前,一笔批量订单已经耗尽了库存。智能体自信地告诉客户商品有货。客户下单。你的支持团队负责处理后续问题。陈旧数据故障对模式验证是不可见的,因为其结构是完美的。只有内容是错误的。

**语义错误的结果(Semantically wrong results)**是最危险的类别。工具返回了新鲜、结构良好但在事实上不正确的数据。由于查询歧义,搜索 API 返回了错误实体的内容。SQL 执行工具返回了编译并成功运行的查询结果集,但却回答了错误的问题——关联了错误的键、使用了相差一天的日期范围进行过滤,或者悄无声息地忽略了智能体认为已应用的 WHERE 子句。数据看起来是对的。类型检查通过。但答案是错的。

为什么智能体不验证(以及为什么框架没有提供帮助)

架构上的原因是显而易见的:智能体框架将工具视为受信任的函数。当你在 LangChain、CrewAI 或 Anthropic SDK 中注册工具时,你会定义输入模式。框架会验证输入参数。但没有任何东西验证输出内容。

这反映了软件工程中一个熟悉的模式。早期的 Web 框架严格验证表单输入,但隐式地信任数据库查询结果。在输出编码成为标准之前,经历了多年的 SQL 注入攻击。智能体框架目前正处于同一阶段——能够感知输入,却对输出视而不见。

还有一个激励机制问题。为每个工具调用添加验证层会增加延迟。在一个智能体需要进行 8-12 次工具调用才能完成任务的流水线中,即使每次调用增加 100 毫秒的验证时间,也会增加近一秒的端到端延迟。对于交互式应用来说,这是显而易见的。对于批处理,成本的复利方式则不同——不是体现在延迟上,而是在验证模型或确定性检查的计算开销上。

更深层次的问题是,大多数团队并不知道他们的工具结果是错误的。传统监控跟踪工具调用是否成功(HTTP 200)以及智能体是否生成了最终响应。这两个指标都无法捕捉中间结果的语义正确性。你只有在用户报告错误答案、提交支持工单,或者——在最坏的情况下——用户基于你的智能体满怀信心提供的捏造数据做出决策时,才会发现问题。

幻觉放大效应

这是让验证缺口变得真正危险的部分:LLM 可以在正确的工具结果基础之上产生幻觉。研究表明,在函数调用交互中,即使工具返回了准确的数据,模型也会捏造出与所提供上下文相矛盾的外源性幻觉。

这意味着验证必须在两个方向上进行。你需要验证工具返回了正确的数据,并且需要验证模型在响应中忠实地表达了该数据。工具返回 {"price": 42.50},模型却说“价格约为 45 美元”。这是四舍五入吗?是幻觉吗?还是用户并未要求的货币转换?如果在工具结果边界没有验证,你将无法区分这些故障模式。

在多步智能体工作流中,这种放大效应会产生复合影响。智能体 A 调用工具,获取了稍微陈旧的数据,对其进行推理,然后将摘要传递给智能体 B,智能体 B 使用该摘要作为另一个工具调用的参数。当最终响应到达用户手中时,最初的陈旧性已经过多次推理步骤的“洗白”。来源已丢失,信心却很高,而答案是错误的。

构建验证层

一个实用的验证架构分为三个层级,每一层都以不同的成本点捕捉不同类别的失败。

第一层:确定性模式 (Schema) 验证。 这是最便宜且最快的层级。为每个工具的响应定义 JSON Schema 或 Pydantic 模型。在响应进入 Agent 的上下文之前,验证其结构、类型、必填字段和取值范围。例如,-500°F 的温度值会失败;不符合 UUID 格式的用户 ID 会失败;当查询本应始终返回行时却出现空结果集也会失败。这一层可以捕捉结构性损坏和明显的数据异常。成本:亚毫秒级。每个团队都应该这样做。

第二层:特定领域的断言 (Assertions)。 这些是需要上下文但不需要 LLM 的业务逻辑检查。如果 Agent 请求过去 7 天的订单,请验证所有返回的时间戳是否都在该窗口内。如果定价 API 返回一个值,请根据缓存范围对其进行检查(此价格是否在历史平均值的 2 个标准差范围内?)。如果搜索针对 Agent 已知应该匹配的查询返回了 0 个结果,请标记它。这些断言编码了你的工程师已经知道的不变量——只是它们尚未被整合到工具响应路径中。成本:个位数毫秒级。对于任何涉及财务数据、库存或面向用户信息的工具,这都具有极高价值。

第三层:基于 LLM 的语义验证。 对于正确性比延迟更重要的高风险工具结果,将工具响应通过一个带有针对性验证提示词的更小、更快的模型进行路由。“这个搜索结果是否真的回答了所提出的问题?给定查询,这个 SQL 结果集是否合理?”验证者的范围被刻意缩小了——它不是在生成,而是在审计。这可以捕捉到确定性检查漏掉的语义失败。成本:50-200 毫秒以及额外的 Token 支出。建议保留给那些结果直接影响不可逆操作(如发送电子邮件、下订单、修改记录)的工具调用。

真正重要的成本与准确度权衡

直觉会让你想在第三层验证所有内容。别这么做。对于大多数工具调用,延迟和成本的计算并不支持这种做法。

相反,你应该根据后果对工具进行分类。输入到中间推理的只读工具通常仅靠第一层验证即可生存。Agent 可能会通过额外的工具调用来交叉检查信息。但写入工具——任何发送电子邮件、创建记录、扣费或修改外部状态的操作——至少值得进行第二层验证,且在操作不可逆时应进行第三层验证。

这种分类直接对应于审批门禁文献中的一种模式:自动 (AUTO)、记录 (LOG) 和需要审批 (REQUIRE_APPROVAL)。将其扩展到验证领域:AUTO 工具接受第一层验证;LOG 工具接受第二层验证;REQUIRE_APPROVAL 工具接受第三层验证,且验证结果将成为人工审核员看到的审批上下文的一部分。

计算结果往往比大多数团队预期的要好。在一个典型的 Agent 工作流中,60-70% 的工具调用是读取(搜索、查询、获取);20-30% 是低后果的写入(日志记录、状态更新);只有 5-15% 是高后果的写入。仅对这 5-15% 的调用应用第三层验证,在覆盖了错误会导致实际损害的操作的同时,对整体工作流延迟增加的开销微乎其微。

验证-重试循环

当验证失败时,Agent 需要一条恢复路径。幼稚的方法——重试相同的工具调用——对瞬时故障有效,但会使系统性故障变得更糟。如果 SQL 查询在语义上是错误的,重试只会返回相同的错误结果。

一个更好的模式是将失败类别与恢复策略分开:

  • 模式 (Schema) 违规:重试一次(可能是瞬时的序列化错误)。如果再次失败,将原始错误呈现给 Agent 并让其重新构思。
  • 检测到陈旧数据:不要重试。相反,在 Agent 的上下文中注入一个新鲜度注释:“此数据是 20 分钟前的。请谨慎操作或从实时源获取。”
  • 语义不匹配:将验证失败作为 Agent 可以推理的工具结果呈现。“搜索结果似乎没有回答原始查询。请考虑重新组织语言或使用不同的工具。”

核心见解是,验证失败是信息,而不仅仅是错误。一个知道工具结果已陈旧的 Agent 可以调整其置信度。一个知道搜索未命中的 Agent 可以尝试不同的方法。而一个盲目信任每个响应的 Agent 则没有这种选择。

无需重构技术栈即可实现

你不需要自定义框架来添加工具结果验证。实现方式是在每个工具周围添加一个包装函数 (wrapper function),在响应到达 Agent 之前对其进行拦截。

在最简单的层面上,用一个验证器包装你的工具函数,根据模式和一组断言检查响应。当验证通过时,正常返回响应。当验证失败时,返回一个 Agent 可以解释并采取行动的结构化错误消息——而不是一个导致工作流崩溃的异常。

对于第三层验证,使用一个带有聚焦提示词的小型模型(如 Haiku 级别)。提示词应包括原始工具调用(请求了什么)、响应(返回了什么)以及一个特定的验证问题(响应是否回答了问题?)。验证者返回通过/失败以及一句简短的解释。每次验证的总 Token 成本通常低于 500 个 Token——与主 Agent 的上下文窗口相比微不足道。

记录每一个验证结果。汇总数据会告诉你哪些工具不可靠,哪些查询产生了陈旧结果,以及你的 Agent 在哪里产生了错误的置信度。这就是大多数团队缺失的可观测性层——不是“工具调用成功了吗?”,而是“工具调用返回了 Agent 应该信任的东西吗?”

当你不再信任工具时会发生什么变化

增加工具结果验证的团队一致报告了两个结果。首先,他们发现有 5-15% 的工具结果存在错误,并以静默方式传播给了用户。其次,他们发现验证层兼作调试工具 —— 当智能体产生错误答案时,验证日志能立即将搜索范围缩小到具体是哪个工具结果导致了根本原因。

更广泛的原则很简单:在智能体系统中,每一个数据边界都是一个信任边界。你的智能体不信任用户输入(你会对其进行清理)。你的智能体不信任它自己的输出(你有护栏)。但目前,你的智能体几乎肯定会信任它接收到的每一个工具结果,而这正是那些最难调试的生产环境故障所在的间隙。

References:Let's stay in touch and Follow me for more thoughts and updates