当工具撒谎时:智能体默认信任的“伪成功”失败模式
智能体自信地告诉用户:“我已经发送了确认邮件,并将退款退回到你的账户。”追踪记录很干净:两次工具调用,均返回 {"success": true},模型生成了精练的摘要,对话在 3.2 秒内结束。一周后,客户发起投诉,因为邮件从未送达,退款也从未入账。审计日志中全是绿色的勾选标记。没有任何环节失败——除了实际的工作本身。
这就是在大多数智能体技术栈中尚未被命名的故障模式:撒谎的工具。这里的“撒谎”并非恶意——它们返回了其契约规定的响应。这种谎言是结构性的。HTTP 层返回 “200 OK” 是因为请求被接受了,而不是因为操作完成了。邮件服务商返回 success: true 是因为消息进入了发送队列,而不是因为它已经发出了。数据库写入返回且无报错,是因为它写入了一个从未同步的副本。被训练成“乐于助人”且在“绿色代表完成”的示例上训练过的模型,将这些信号编织成一份自信的摘要,然后继续下一步。
这种问题难以调试的原因在于每一层都表现得如文档所述。工具报 告了它所知道的情况。智能体根据它收到的唯一信号进行推理。运行环境(harness)记录了智能体输出的内容。谎言存在于“系统接受了我的命令”与“世界按照我的要求发生了改变”之间的鸿沟中——而对于那些思维模型将工具调用视为函数返回的人来说,这个鸿沟是不可见的。
撒谎工具的剖析
智能体工具调用的词汇借鉴自 RPC,而 RPC 继承自本地函数调用,后者假设“调用返回”即意味着“工作完成”。对于分布式系统来说,这种假设本就摇摇欲坠,而对于带有异步后端的系统来说,这完全是错误的。智能体技术栈继承了所有先前的故障模式,并增加了一个概率推理器,它会按字面意思接受成功信号。
以下几种常见模式会产生虚假成功的响应:
- 接受即成功(Acceptance-as-success)。 API 接受请求,将其放入队列并返回 200。而队列工作进程已宕机、死锁,或者积压了六小时的任务。下游效果从未发生。
- 副本写入成功。 写入操作进入了一个尚未同步到只读副本的节点,而智能体随后会查询这些副本。后置条件的读取返回了旧值;模型将其解读为“写入未生效”并再次写入。
- 服务商侧的软故障。 邮件服务商返回 200 以及
accepted: true,但收件人域名的垃圾邮件过滤器已经屏蔽你的 IP 一周了。你的工具层永远看不到这个失败。 - 符合 Schema 的错误。 工具返回 200,但响应体包含一个
error字段,由于智能体的工具封 装层是在 4xx 是唯一错误路径的时期编写的,因此该字段未被暴露出来。 - 部分变更。 复合操作——“创建发票并发送邮件”——在第一步成功了,但静默地丢弃了第二步,返回一个合并了两个步骤的单一成功布尔值。
每一种模式都存在于两个系统的边界,在那里,“事情是否真的发生了”的所有权处于无人认领的状态。工具层认为 API 响应了它。API 认为队列确认了。队列认为工作进程接受了。没人掌握后置条件。
为什么模型不能作为验证层
针对这种故障模式,一种自然的反应是让模型变得更聪明——提示它“在向用户报告成功之前先验证工具是否执行成功”。这是错误的修复层级。
模型只能看到运行环境输入到其上下文中的内容。如果工具返回 success: true,模型没有独立证据去质疑它。要求模型“保持怀疑”只会产生“表演式的怀疑”——一段充满对冲语言的文字,却不会改变下一次调用的行为。更糟糕的是,在人类编写的工具文档上训练出来的模型已经吸收了 success: true 意味着完成的先验知识。用提示词指令去对抗这种先验,会对智能体行为的其他维度产生持续的拖累。
验证必须是确定性的,必须存在于技术栈中模型之下的层级,并且必须表现为模型可以推理的证据,而不是模型可以合理化掉的字符串。也就是说,在不信任工具自我报告的代码观察到后置条件之前,运行环境应该拒绝向模型返回 tool_result: success。这样模型看到的是后置条件,而不只是响应。
这是一种结构性的转变。它将智能体运行环境从“我把工具的答案转发给模型”转变为“我根据外部观察验证了工具的答案,然后转发验证后的答案”。后者是一个实时一致性层,而大多数智能体技术栈并没有这一层,因为大多数智能体技术栈是为“以读为主”的工作负载设计的,在那种情况下模型只需要信息。
后验条件模式
落地生效的准则是“后验条件验证”(post-condition verification):每一次改变状态的工具调用(tool call)之后,都紧跟着一次确定性的读取,以确认世界确实处于该调用所承诺的状态。该模式包含四个要素,各有其权衡。
- https://runcycles.io/blog/ai-agent-silent-failures-why-200-ok-is-the-most-dangerous-response
- https://medium.com/@ThinkingLoop/13-agent-eval-tests-that-catch-silent-tool-failures-79ac312d70a4
- https://stackoverflow.blog/2025/06/30/reliability-for-unreliable-llms/
- https://www.inferable.ai/blog/posts/distributed-tool-calling-message-queues
- https://stripe.com/blog/idempotency
- https://zuplo.com/learning-center/implementing-idempotency-keys-in-rest-apis-a-complete-guide
- https://composio.dev/content/ai-agent-tool-calling-guide
- https://arize.com/blog/common-ai-agent-failures/
- https://dev.to/temurkhan13/5-silent-failure-patterns-i-keep-finding-in-production-ai-systems-4fl0
- https://medium.com/@2nick2patel2/llm-tooling-in-prod-retries-guards-and-timeouts-850241b6bf60
- https://fast.io/resources/ai-agent-idempotent-operations/
- https://dzone.com/articles/idempotency-in-ai-tools-most-expensive-mistake
