跳到主要内容

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

· 阅读需 12 分钟
Tian Pan
Software Engineer

内部 API 依赖于一种默契而存在:没人会写下契约,因为每个人都已经心知肚明。那些碰巧存在的字段、调用者在暗地里解析的报错、返回空列表而非 404 的 200 响应 —— 这些都是关键的承重行为。而维系这些行为的基础是,你可以叫出每个调用者的名字,并在做出任何更改之前通过 Slack 联系他们。这种安排一直有效,直到它失效的那天。

当你将一个智能体(Agent)连接到该 API 的那天起,这种默契就失效了。这并非因为智能体怀有恶意或粗心大意,而是因为智能体是一个你无法触及的调用者。它没有 Slack 账号。它没有阅读你的迁移说明。它依赖于从示例载荷或 Schema 快照中吸收的响应形态,并且在你早已更新版本后,它仍会长期依赖这些形态。

一个令人不安的事实是,“内部”从未是 API 本身的属性。它其实是调用者列表的属性。将列表缩减到你认识的人,API 就是内部的;一旦增加一个你无法协调的参与者,API 就是公共的 —— 这意味着你需要承担“公共”一词所暗示的所有严谨规范,尽管你并没有构建任何本应具备的基础设施。

海勒姆定律一直都是正确的 —— 只是智能体让它变得显而易见了

海勒姆定律(Hyrum's Law)指出,只要有足够多的用户,系统的每种可观测行为都会有人依赖,无论契约中承诺了什么。大多数内部团队都在悄悄违反这一定律并得以蒙混过关,因为他们的用户数量很少且触手可及。你更改了一个字段名,构建失败了,下午就会有人修复它。依赖关系是真实的,但反馈循环足够快,以至于人们从未觉得这是一种契约。

智能体调用者同时从两个方面打破了这一循环。首先,它扩大了被依赖的可观测行为的范围。人类集成者阅读你的文档并使用文档中描述的三个字段。而智能体则会吸收整个响应,并可能根据其中任何内容做出下一个决策 —— 数组的顺序、可为空字段的存在与否,或是状态字符串的精确措辞。那些你从未考虑作为接口一部分的行为,现在都成了接口的一部分。

其次,它消除了快速反馈。当人类集成出现故障时,会抛出异常,测试变红,或者触发警报。而当智能体集成出现故障时,智能体通常不会崩溃。它会做一些更糟糕的事情:它会自我调整。它看到一个不再符合预期的响应,然后临场发挥 —— 尝试使用不同的参数重试、选择不同的工具,或者幻觉出一个看似合理的路径。你发布的 API 变更不会产生错误。它会导致该智能体下游所有内容的质量出现缓慢且无声的下降,而且没有任何堆栈跟踪(stack trace)能追溯到你的那次提交。

这就是核心危险所在。你不仅仅是增加了一个新的调用者。你增加了一个会将你的破坏性变更从“大声报错”转变为“悄无声息的失败”的调用者。

无法触及的调用者改变了每一次变更的经济账

想想在内部 API 上,协调实际上为你带来了什么。它让你能以低廉的成本进行破坏性变更。你可以重命名字段、收紧类型或删除端点,因为这样做成本只是发个消息和占用别人一个下午的时间。非正式契约之所以可行,正是因为重新协商的成本很低。

失去了协调的能力,这种经济计算就会反转。每项破坏性变更现在都带有无穷且无法诊断的成本,因为你无法列举谁依赖这些行为,也无法提前告知他们。智能体对你响应形态的依赖是在它上次看到你的 Schema 时确定的 —— 可能是几周前,也可能是在一个缓存的工具定义中,而智能体自那以后就没刷新过。LLM 客户端会激进地缓存工具和 Schema 定义;即使在你的服务器更新之后,智能体也可能继续发送符合旧契约的参数,直到有某种机制强制其重新获取。

这就是为什么智能体调用者会对一个从未获得“公共”地位的服务强加公共 API 的严谨规范。这并非因为有人决定将该 API 公开,而是因为原本支撑你跳过这些规范的“低成本协调”假设已经不成立了。你现在需要的规范正是公共 API 一直以来所需的:

  • 显式契约。 智能体依赖的行为必须是你写下来的行为,而不是碰巧存在的行为。如果不在 Schema 中,就不在承诺范围内 —— 并且你需要一种方法来检测智能体何时依赖了未承诺的内容。
  • 版本控制。 破坏性变更必须是一个新版本,而不是对现有版本的变动。旧的调用者在迁移之前会一直使用旧的形态。
  • 弃用窗口。 “我们改了它”不是智能体能响应的事件。“这已弃用,这是替代方案,它将在 N 个月后消失”才是一个足够长的窗口,足以让你无法控制的迁移得以完成。
  • 稳定的错误语义。 智能体会根据你返回的错误来推理失败原因。如果你的 429 有时表现为 500,或者你的“未找到”有时表现为空的 200,智能体就无法在其上构建可靠的策略。

这些都不是新鲜事。这是标准的公共 API 策略。唯一的新鲜事是,你现在必须将这些策略应用到一个 README 中仍然写着“内部”的服务上。

工具 Schema 即契约 —— 请像对待契约一样对待它

加载中…
References:Let's stay in touch and Follow me for more thoughts and updates