跳到主要内容

34 篇博文 含有标签「api-design」

查看所有标签

智能体从未接收到的服务降级信号

· 阅读需 10 分钟
Tian Pan
Software Engineer

当下游 API 开始出现波动时,人类操作员在任何事情真正崩溃之前,就会通过十几种方式察觉到。状态页变为黄色。变更日志邮件飞进收件箱。提供商的仪表板上出现警告横幅。值班频道因有人在日志中发现 429 错误而热闹起来。队友发帖询问:“还有人看到写入变慢吗?”这些都不是对请求的响应。它们是围绕 API 的环境运行信号,人类几乎是被动地吸收了这些信号。

调用同一个 API 的智能体(agent)只收到一样东西:它刚刚发出的请求的响应。状态码、Header、Body。这就是全部的渠道。它没有收件箱,没有仪表板,没有 Slack,没有外围视野。它察觉不到最后十个调用每个耗时都是之前十个的两倍。它读不了状态页,因为没人给它 URL,它也没有查看状态页的常规指令。当依赖项降级时,智能体是系统中最后一个知情方——而且它通常是通过失败才知晓的。

这种不对称性并非模型能力问题。更聪明的模型也解决不了。智能体对运行信号是盲目的,因为底层设施(plumbing)从未传递过这些信号,而且大多数智能体架构在出厂时,甚至没人注意到缺失了这些底层设施。

你的智能体从未发送的幂等键

· 阅读需 12 分钟
Tian Pan
Software Engineer

一位客户曾因一次退货收到了三次退款。这不是因为模型幻觉出了某种政策,也不是因为人类填错了表单——而是因为退款工具超时了两次,智能体随之重试了两次,而每次重试都发起了一个全新的请求,导致支付处理器根本无法识别这其实是它处理过的工作。三个干净的 HTTP 200。三次真实的资金转移。智能体完全按照指令行事:当调用失败时,重试。

这个 Bug 不在模型中。Bug 出在一个从未发送的 Header(标头)中。

重试是智能体最自然不过的本能。工具调用返回错误,或者更糟,什么都不返回,而循环系统的直觉——无论是编码在框架、提示词还是模型自身的训练中——就是重新尝试该动作。这种直觉对于“读”操作是正确的,而对于“写”操作则是灾难性的。一个韧性十足的智能体与一个会向客户重复收费的智能体之间的区别,不在于智力高低,而在于每一次改变状态的工具调用是否携带了幂等键(Idempotency Key),以及另一端的系统是否真正履行了它。

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

· 阅读需 12 分钟
Tian Pan
Software Engineer

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

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

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

你在没告诉智能体的情况下修改了工具 Schema

· 阅读需 12 分钟
Tian Pan
Software Engineer

一位后端工程师重命名了一个字段。user_id 变成了 customer_id,因为团队终于在所有服务中统一了 “customer” 这个术语。他们还增加了一个参数 region,因为计费系统现在需要它。这次变更通过一个包含两个批准的普通拉取请求(pull request)发布。每一个调用该端点的下游服务都在同一个发布版本中进行了更新。集成测试全部通过。按照后端团队衡量的一切标准,这是一次常规且执行良好的 API 变更。

一周后,支持工单开始增加。负责下单的智能体偶尔会在没有关联客户的情况下下单,或者将其关联到错误的区域。没有人改动过智能体。没有人改动过提示词(prompt)。模型的版本与上个月完全相同。然而,智能体现在却出现了一种以前从未有过的错误。

原因既不是模型中的 Bug,也不是后端中的 Bug。而是工具 Schema(tool schema)有两个消费者,但在审查变更时,只有其中一个在场。

你无法通过邮件给模型发送变更日志:为什么当调用者是 LLM 时,API 弃用机制会失效

· 阅读需 11 分钟
Tian Pan
Software Engineer

API 弃用是一种建立在接收者具备阅读能力这一假设之上的通信协议。你发布更新日志、向注册开发者发送邮件、添加 Deprecation 标头、提前六个月发出通知,并寄希望于另一端的人类能看到警告、提交工单,并在停用日期之前完成迁移。当你的最活跃调用者变成了语言模型的那一刻,这整套工作流程就悄无声息地失效了。

LLM 不会订阅你的开发者时事通讯。它没有 Slack 频道让人转发你的迁移指南。它在每一次调用中重新发现你的 API —— 或是通过被交付的工具描述,或是通过一份可能已经过时 18 个月的文档页面,亦或是基于其训练数据中对你 API 样子的记忆。这里没有一个你可以进行版本化、通知或传呼的持久客户端。每一次请求都是与一个实体的全新博弈,而这个实体既不记得你上一次的公告,也没有义务阅读你下一次的通知。

这并非假设。随着 Agent 逐渐成为内部和外部 API 的主要消费者,后端团队沿用了 15 年的弃用策略手册正在以一种特定的、可诊断的方式失效 —— 且大多数团队只有在发现一个“已弃用六个月”的端点仍在生产环境中为 Agent 提供服务、且没有路径使其停止时,才会意识到这一点。

流式推理中的海勒姆定律:节奏、停顿和中间 Token 是未成文的契约

· 阅读需 12 分钟
Tian Pan
Software Engineer

一个团队从前沿模型升级到了其更快的后继版本。评估套件(eval suite)全绿。最终答案一致。工具调用的 Schema 完全相同。结构化输出通过了与以往一样的 JSON Schema 验证。他们发布了。不到一天,支持票据就堆积如山:“助手感觉太匆忙了”,“它不再真正思考了”,“感觉不对劲”。产品经理调取了遥测数据,发现任务完成率没有变化。工程团队反复检查了评估和 Schema,没发现任何问题。投诉是真实的,但团队定义的契约——就如团队所定义的那样——依然完好无损。

改变的是流的纹理(texture)。旧模型在调用工具前会停顿 800 毫秒,发出一句“让我查一下……”的前导词,并以每秒约 35 个 Token 的速度输出,在子句边界处有自然的节奏。新模型以每秒 90 个 Token 的速度输出,从不停顿,且完全跳过了前导词。这些都没有出现在任何文档记录的契约中。但所有这些都是不可或缺的“承重”部分。

这就是海勒姆定律(Hyrum's Law),而流式传输(streaming)让它的表面积变得巨大。系统的任何可观察行为都会被某人所依赖——而流式 AI 界面暴露的可观察行为远比团队意识到的要多。

API 文档即可靠性基础设施:文档如何决定智能体的成功率

· 阅读需 11 分钟
Tian Pan
Software Engineer

大多数工程团队将 API 文档视为开发者体验关注点——一种为了减少支持工单和入职时间而进行的改进。当你的主要消费者是在浏览器中阅读文档的人类时,这种思维方式是有道理的。但现在,这已经不再足够。

当 AI 智能体通过工具调用访问你的 API 时,你的文档就不再仅仅是指南,而是变成了运行时行为。模糊的参数描述不再是 UX 上的不便,而是对模型产生幻觉值的直接指令。缺失的错误代码不再是参考文档中的空白,而是一个模糊信号,可能导致智能体陷入没有退出条件的重试循环。你三年前为人类读者编写的文档,现在正被一个无状态的语言模型解析,无论它是否理解正确,都会自信地执行。

Agent 作为用户:当机器人成为你的主力用户时,产品分析为何失效

· 阅读需 12 分钟
Tian Pan
Software Engineer

2025 年,自动化互联网流量同比增长了 23.5%,是人类流量增速的八倍。其中,agent 驱动的交互增长了 7851%。如果你的产品处理了相当体量的 API 流量,那你的最重度"用户"很可能根本不是人类。而令人不安的事实是:你的产品分析系统对此几乎一无所知。

这不是一个机器人检测问题,而是一个埋点架构问题。当 AI agent 预订差旅、提交费用报告、查询数据库或调用你的支付 API 时,它留下的行为特征与人类完全不同——而你的会话漏斗、NPS 问卷和队列留存图,正在悄悄对你撒谎。

AI 原生 API 设计:构建智能体真正能调用的后端

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的 REST API 运行良好。文档齐全,错误码一致,每一个经过测试的人工编写客户端都能正常使用。然后你的团队接入了一个 AI 智能体,不到一小时,它就通过不断重试一个不存在的端点的各种变体生成了 2,000 次失败请求——bulk_search_userssearch_all_usersbulk_user_search——每次尝试都触发了真实的下游处理。

这不是提示词工程的失败,而是 API 设计的失败。

REST API 是为能够解析文档、遵守契约、严格调用规范的客户端而构建的。AI 智能体则不同:它们根据名称和描述推断端点可能做什么,在不追踪状态的情况下重试,并将错误信息视为指令而非诊断代码。为智能体调用方设计 API,需要重新审视大多数后端工程师从未质疑过的基本假设。

过时的工具描述是 AI Agent 最大的隐形故障诱因

· 阅读需 10 分钟
Tian Pan
Software Engineer

你交付了一个工具,让你的 Agent 可以获取用户个人资料。描述中写道:“通过用户 ID 检索用户信息。”六周后,后端团队将 user_id 重命名为 customer_uuid 并添加了一个必填的 tenant_id 字段。没有人更新工具的 Schema。你的 Agent 继续调用旧的签名,收到 400 错误,将空结果解释为“未找到用户”,并“热心地”创建了一个重复记录。

日志中没有错误。没有触发任何报警。Agent 全程都非常自信。

这就是工具文档问题:Schema 漂移将陈旧的描述变成了隐性故障向量。这可能是当今生产环境 AI 系统中最被低估的可靠性风险,而且你的 Agent 运行的时间越长,情况就越严重。

提示词弃用合约:为什么措辞清理是一项破坏性更新

· 阅读需 11 分钟
Tian Pan
Software Engineer

系统提示词(system prompt)上一个四个词的修改——用 "respond using clean JSON"(使用干净的 JSON 响应)替换 "output strictly valid JSON"(输出严格有效的 JSON)——在评估(eval)中一度没有引起任何波动。它在周四发布,却在周五凌晨 4 点被回滚,因为结构化输出的错误率从 0.3% 飙升到了 11%。提示词并没有变糟。它只是变得“不同”了,而下游解析器在无人察觉的情况下,已经固化(pinned)在了 "strictly valid" 这个词组上。

这是大多数提示词工程(prompt-engineering)团队尚未建立工具来应对的失效模式:提示词被视为作者拥有的文本,而实际上它是与作者从未见过的消费者之间的一份合约。这些消费者中,有些是逐字引用原句的其他提示词;有些是 JSON 模式(JSON schema)字段锚定在特定形容词上的工具描述;有些是其评分标准(rubrics)要求裁判(judge)检查“严格有效格式”的评估(evals);还有一些是解析器——最脆弱的一类——其正则表达式是根据模型输出的精确前导语(preamble)进行校准的。

一次“小小的措辞清理”会悄无声息地破坏解析器、导致裁判校准偏移,并使数周的评估运行失效。这些失败都不会在 PR(拉取请求)中显示出来,而是在一周后作为“偏移”(drift)出现在仪表盘上。

智能体流量不等同于人类流量:为两类调用者设计 API

· 阅读需 13 分钟
Tian Pan
Software Engineer

你两年前发布的 API 是为单一类别的调用者设计的:浏览器或移动客户端背后的人,点击一次,然后等待响应。现在,大约一半的关键端点上,这个假设都是错误的。另一半流量是智能体(Agents)——你自己的、你客户的,或者是将你的端点作为工具使用的第三方集成——它们具有不同的运行逻辑。它们会产生爆发式流量。它们会无限重试。它们会并行处理。它们会逐字解析错误字符串。它们代表人类行事,而当出现问题时,人类无法即时提供意图说明。

今年出现在复盘报告(postmortems)中的大多数生产环境异常,都可以追溯到一个架构错误:将这两类调用者视为同一种类别。为人类步调设置的频率限制(Rate limits)会被智能体的并行扇出瞬间击穿。为人类可读而设计的错误消息,会被一个在 400 错误上无限重试的智能体解析错误。人类默认会满足的幂等性假设,在智能体从恢复的检查点重试相同的负载时会被打破。身份验证日志失去了区分“用户执行了此操作”与“用户的智能体代表用户执行了此操作”的能力。

解决方法不是更智能的 WAF 或更大的频率限制桶。而是一种深思熟虑的 API 设计,它定义了两类调用者,将它们的流量视为不同的形态,并记录委托链,以便在间接层级中保持可追溯性。