你的API,AI根本用不了

你的API,AI根本用不了

上个月帮一个团队做技术评审,他们刚接入了公司内部的 AI 编程助手。一切看起来很美好,直到有一天,AI Agent 尝试帮用户”把上周的订单状态改成已发货”。

系统返回了 403。

不是由于权限不够,是由于 AI 调错了接口——它把 /api/orders/{id}/status 和 /api/orders/{id}/ship 搞混了。两个接口功能几乎一样,参数也差不多,区别只在于:前者需要传一个 status 枚举值,后者直接改状态为”已发货”并触发物流回调。

对于人类开发者来说,翻两页文档就能搞清楚。但对于一个靠语义匹配来决策的 AI Agent 来说,这两个接口看起来完全等价。

这不是 AI 的错。是你的 API 从来没想过会被一个非人类调用。

人类友善型 API 正在变成技术债

过去十年,我们设计 API 的默认假设是:调用方是一个会读文档、会理解业务上下文、会在出错时重新调试的人类开发者。

在这个假设下,我们做了许多”人性化”的设计。

列如冗余接口。同一个”修改订单状态”操作,可能有三个不同的端点,分别对应不同的业务场景。人类看到 /ship 就知道这是发货,看到 /cancel 就知道这是撤销,语义清晰,易于理解。但对于 AI Agent 来说,它要做的事情是”把订单 12345 的状态改成已发货”,它面对三个看起来都能完成这个任务的接口,只能猜。

再列如分页约定。大多数 REST API 用 page 和 size 参数,但也有用 offset 和 limit 的,还有用 cursor 游标的。人类开发者看到文档示例就知道怎么传参,AI Agent 需要遍历所有可能性才能找到正确的组合。这不是能力问题,是接口的语义不确定。

最要命的是错误信息。我们习惯返回这样的响应:

{
  "code": 10086,
  "message": "操作失败"
}

人类开发者看到 10086 会去查文档,或者直接复制错误信息扔到群里问。AI Agent 收到这个,只能告知用户”操作失败了,错误码 10086″,然后等用户自己想办法。

这不是一个小问题。当你的系统里有几百个接口、几十种错误码、各种隐式的业务规则,AI Agent 面对的不是一个 API 网关,而是一个需要大量先验知识才能穿越的迷宫。

三个沉默的架构假设在崩塌

冷静地看,当前大多数后端系统的 API 设计建立在三个默认前提上。这三个前提正在被 AI Agent 逐个击穿。

第一个前提:调用方有阅读文档的能力。

我们写接口文档时默认对方会看。所以许多关键信息——列如”这个接口幂等吗”、”传参 A 时不能同时传参 B”、”status=3 表明已撤销但不是终态”——只存在于文档的某个段落里,而不是编码在接口契约中。

AI Agent 没有阅读文档的能力。它只能靠接口返回的元数据和少量示例来推断。你的 Swagger 文档写得再详细,AI 也只能通过有限的上下文窗口来理解。更何况大多数公司的接口文档本身就不完整——那些”只有老员工才知道”的隐含规则,对 AI 来说就是黑洞。

第二个前提:调用方理解业务上下文。

一个典型的电商系统里,”撤销订单”这个操作在不同状态下有不同的含义。待支付时撤销就是关闭交易,已支付时撤销要触发退款,已发货时撤销要走退货流程。

人类开发者看到”撤销订单”这个接口名,会自然地联想到这些业务差异。但 AI Agent 不知道——它只知道这是一个 POST 请求,传一个订单 ID,然后等结果。至于背后是退款还是退货,它无从判断,也不会主动追问。

这不是 AI 不够机智。是接口的语义设计没有把业务上下文作为一等公民来对待。

第三个前提:调用方能够处理模糊性。

当接口返回 500 时,人类开发者会判断:是偶发故障还是系统性崩溃?需要重试吗?重试几次?间隔多久?

AI Agent 面对 500,最理性的行为是报告失败。但如果它负责的是一个端到端的业务流程——列如”帮我部署这个服务到生产环境”——一个中间步骤的 500 可能导致整个流程中断,而人类运维会自然地判断”这个错误可以忽略,或者重试一次就好”。

这些判断依赖的是经验、直觉和对系统整体状态的感知。AI Agent 没有这些。

案例:一次重构省下了 40% 的调试轮次

今年年初,我参与了一个内部工具平台的重构。这个平台有超过 200 个 REST 接口,原本是给前端和第三方开发者用的。团队接入了 AI Agent 之后,平均每个任务需要 7 到 8 轮调试才能跑通——大部分时间都浪费在 AI 猜错接口、传错参数、误解错误信息上。

我们没有重写整个系统,而是做了三件”向后兼容”的改造。

第一,给每个接口加了语义标签。不是在文档里加,而是在响应头里加。列如 X-Action-Type: order.cancel 和 X-Action-Type: order.refund,让 AI Agent 不需要理解接口名就能区分操作类型。同时,接口路径本身也被规范化——从 /cancelOrder、/order/cancel、/orders/{id}/cancel 这种五花八门的命名,统一收敛到 资源/操作 的动词后置模式。

第二,在接口响应里嵌入了”下一步”指引。以前返回 200 就结束了,目前每个成功响应都带一个 X-Next-Actions 头,列出当前状态下可用的后续操作。列如撤销订单成功后,系统会告知调用方:”接下来可以做这些事:查询退款状态、重新下单、联系客服。”AI Agent 不再需要自己推测下一步该调用什么,而是直接从响应里读取可用的选项。

第三,重写了错误信息的生成逻辑。不再返回 {“code”: 10086} 这种对人类友善的错误码,而是返回结构化的错误对象:

{
  "error": "ORDER_NOT_CANCELLABLE",
  "reason": "订单已进入物流环节,撤销前需要先发起退货",
  "action": "调用 /api/returns/create 创建退货单",
  "retryable": false
}

每个错误都包含三个关键信息:为什么失败、可以做什么、是否需要重试。AI Agent 拿到这个响应后,可以直接按 action 字段的指引进入下一步,而不是把问题抛回给用户。

改造完成后,AI Agent 执行任务的平均调试轮次从 7.8 降到了 4.6。更重大的是,接口对人类的可用性没有降低——这些元信息对前端开发者同样有用。

不是颠覆,是补课

说回开头那个 403 的问题。

根本缘由不是 AI 太笨,也不是接口设计太差。是我们从来没有认真思考过:当一个不具备业务直觉、不读文档、不能主动追问的调用方接入系统时,接口的契约应该有多明确。

这个问题实则不新。十年前微服务兴起时,我们就讨论过”服务发现”和”契约优先”。只不过当时”契约”的消费者是另一个微服务,而目前消费者是 AI Agent——它对契约的依赖性更强,对模糊性的容忍度更低。

好消息是,解决方案不需要推翻现有架构。语义标签、结构化错误、状态机式的响应设计,这些都是现有 HTTP 协议和 REST 规范完全可以承载的。关键在于意识转变:你设计的每一个接口,未来都可能被一个完全不理解你业务逻辑的 AI 调用。

到那时,接口文档写得好不好已经不是加分项,是生存条件。

© 版权声明

相关文章

1 条评论

none
暂无评论...