跳转到主要内容

Postel 法则在工具边界是一种负担

阅读需 2 分钟Tian PanTian Pan

1980 年,Jon Postel 在 TCP 规范中写下了一句话,这成为了互联网的奠基原则:“对自己发送的内容要保守,对接收的内容要宽容。”四十年来,工程师们将其应用到各个角落——容忍尾随逗号的解析器、将 "10" 强制转换为 10 的 API、静默修复错误标记的 HTML 渲染器。可以说,万维网之所以存在,是因为浏览器宽容了所有人的错误。

然而,当调用者不再是人类时,这条建议就反转了。当一个 AI Agent 调用你的工具并传入字符串类型的数字、嵌套错误的 JSON 对象,或者一个 几乎 正确的枚举值时,那个原本能节省人类开发人员 20 分钟调试时间的宽容解析器,对 Agent 来说却造成了更糟糕的后果:它确认了这个草率的调用是正确的。Agent 在循环中唯一的训练信号就是你的工具返回的反馈。接受垃圾数据,你就在教导模型——就在此时此刻,在这个会话片段中——垃圾数据是行得通的。

IETF 本身已经收回了 Postel 的主张。RFC 9413《维护稳健的协议》(Maintaining Robust Protocols)指出,健壮性原则(Robustness Principle)随着时间的推移实际上会损害协议生态系统:每一个被容忍的偏差都会成为事实上的规范,各个实现会围绕着彼此的 Bug 僵化,而你为了进化所保留的灵活性会被累积的放任所消耗。这种批评在网络协议中花了数十年才显现出来。但在 Agent 循环的工具边界上,同样的衰退在几分钟内就会发生——因为“对等实现”(peer implementation)是一个会根据你发送给它的每一条响应来更新其行为的模型。

宽容是你无意中发送的负面反馈

想想当模型发出一个“差一点就成功”的工具调用时到底发生了什么。假设你的工具期望接收 {"amount": 1050, "currency": "USD"},而模型发送了 {"amount": "1,050.00", "currency": "usd"}。你有两种选择。

严格路径拒绝该调用:amount 必须是整型的分(收到的是字符串 "1,050.00");currency 必须是大写的 ISO 4217(收到的是 "usd")。模型读取这条信息,纠正自己,而且——关键在于——纠正后的格式现在存在于该会话片段后续每一个调用的上下文中。一次失败的往返为你换来了该会话剩余部分的收敛。

宽容路径静默地去除逗号、解析浮点数、乘以 100、将货币转换为大写,并返回成功。模型通过那个畸形的调用完全得到了它想要的结果,因此畸形的调用反而得到了强化。循环中的每一个后续调用都会携带同样的草率,因为没有任何东西告诉模型这样做是不对的。而你的强制转换逻辑现在成了“关键承载”:哪天它遇到一个正在处理欧洲发票的模型发来的 "1.050,00" 时,它会静默地猜错,而代价是之前的 100 倍。

这就是核心的反转。对于人类调用者,验证错误是摩擦,而自动转换是一种恩惠。对于模型调用者,验证错误是 循环内的训练信号,而自动转换则是关于契约实际位置的谎言。事实证明,当 Agent 获得可操作的错误信息时,它们能够自我修正——整个现代 Agent 循环设计的实践都依赖于此。像 LangChain 这样的框架围绕这一机制构建了重试解析器:将失败的输出连同错误信息反馈给模型,第二次尝试的成功率就会飙升。而静默转换让你完全退出了这种机制。

草率会累积,然后蔓延

单个被强制转换的参数听起来无害。问题在于 Agent 循环会迭代,在人类工作流中只是一次性烦恼的错误,在 Agent 集群中会变成分布。

考虑债务是如何积累的:

  • 在会话片段内:模型成功但草率的调用作为示例存在于其自身的上下文中。模型会模仿自己最近的输出;一个被接受的“差一点”会招致另外十个。
  • 在你的 Schema 之间:一旦模型了解到你的解析器会宽容某个字段的类型错误,它就没有理由相信任何字段是严格的。对 amount 的放任会侵蚀对 account_id 的规范。
  • 跨工具:Agent 会泛化。一个了解到“这个平台会进行自动转换”的集群,在调用平台上的每个工具时都会变得更加草率,包括那些 严格 的工具——而这些工具现在会以模型预料之外的方式失败。
  • 进入你的数据:最坏的情况不是调用失败,而是错误的调用成功了。经典的单位 Bug——在存储分的地方存入了元——正是这种宽容边界会放过的错误,因为这两个数量级孤立来看都显得合理。

这种结局有一个名字:海勒姆定律(Hyrum's Law)。随着调用者足够多,你系统的每一个可观察行为都会变成一种依赖,无论你承诺了什么。当调用者是每小时进行数千次调用的模型时,“足够多的调用者”瞬间就会到来。你对错误嵌套 JSON 的偶然容忍,现在成了一种 API 承诺,并以机器速度运行,你永远无法在不破坏那些你从未听说过的集群的情况下将其移除。

现实世界的基础设施 Bug 也呈现出同样的形态。LiteLLM 曾遇到过一个问题,模型发出的畸形工具调用参数被静默丢弃而不是显现出来——Agent 永远看不到失败,因此无法纠正,而损坏会级联到后续请求中,直到整个对话失败。边界上的沉默并不能遏制错误。它是在洗白错误。

会员专享

余下内容仅对会员开放。

会员可读完整内容 —— 每一个公开发布的观点背后,那些框架、决策与推理的全貌。

  • 完整文章,包含未公开存档的部分
  • 可落地的工作框架,附带权衡与决策依据
  • 新文章抢先看,先于公开发布

随时取消 · 一次订阅,畅读全部

参考资料

保持联系,关注我获取更多内容

阅读需 9 分钟

Agent 的端口与适配器架构:为什么你的工具 Schema 应该比供应商更长寿

供应商迁移往往在工具层而非提示词层崩溃。将工具 Schema 视为你拥有的端口 —— 为每个供应商和后端提供轻量级适配器 —— 你将免费获得确定性的 Agent 测试。

insider
ai-agents
阅读需 10 分钟

当你最大的客户端是 Prompt 时,如何弃用 API

AI 智能体不会阅读更新日志 —— 它们对你 API 的认知被冻结在 Prompt、工具 schema 和训练数据中。本文将探讨为什么关闭 v1 版本会导致重试风暴而非迁移,以及如何通过适配器、Sunset 响应头和智能体可读的错误信息来解决这一问题。

insider
api-design
阅读需 10 分钟

GraphQL 终于找到了它的客户端,而且它不是人类

AI Agent 是第一批真正能够自主构建数据需求的客户端——这正是 GraphQL 最初设计的初衷。但 Agent 也放大了导致 GraphQL 在人类客户端竞争中落败的所有弱点。目前行之有效的模式是:Agent 在开发阶段构建查询,由人类进行审核并将其固定为持久化操作。

insider
ai-agents
阅读需 10 分钟

你的内部 API 在智能体调用的那一天起就变成了公共 API

只有当你能叫出每一个调用者的名字时,内部 API 才真正属于“内部”。一旦接入 LLM 智能体,那些从未白纸黑字写下的契约就会变成负担 —— 以下是你突然需要为之付出的公共 API 维护准则。

insider
ai-agents
阅读需 9 分钟

没人使用的长尾:工具带是如何变得尾大不掉的

你给智能体增加的每一个工具,都在削弱它选择正确工具的能力。那几十个无人问津的工具正在悄悄降低那三个核心工具的被选概率 —— 本文将探讨如何保持工具目录的精简与高效。

insider
ai-agents