跳转到主要内容

Agent 流量不是 Web 流量:面向机器客户端的准入契约

把 agent 当作更快的人类会击穿速率限制和源站服务。一份边缘准入契约——声明用途、预算、撤销——让机器客户端承担责任。

发光的承载数据的近景光纤线缆,浅景深,冷蓝色调

错配,直说

人类 Web 流量是有形状的。它是突发性的、绑定会话的、自我限制的:一个人打开页面,阅读,点击,最终停下。浏览器不会并行扇出到上千个 URL,而一个撞上 429 的人通常会放弃或等待。过去二十年的容量规划都建立在这个假设之上。

Agent 流量有另一种形状。它是并行的、持久的,且放大成本极低。单个编排器可以派生 subagent,每个 subagent 在众多源地址上镜像同一请求模式,失败后不知疲倦地重试,并在执行 retrieval 计划时让会话保持数小时。多发一个请求的成本接近于零,所以自然的均衡不是「礼貌地读完就走」——而是「重试到有东西撑不住为止」。

这种错配如今在两侧都可见。发布参考资料站点报告被行为完全不像读者的自动化客户端淹没,而另一些站点则开始用明确的条款和技术控制来限制 agent 访问。语料库展示了这一失效模式的两半:agent 压垮参考站点,以及运营方以全面限制机器访问作为回应。两种结果都不是稳定的设计。

根因不是量。而是站点完全不知道客户端在做什么,而客户端也没有义务说明。

为什么基于 IP 的速率限制假设了错误的客户端

大多数速率限制是为行为像浏览器的客户端写的。它以 IP 地址或 API key 为键,应用 token bucket,并返回带 Retry-After 的 429。对浏览器而言这是一个闭环:人看到错误,标签页停止加载,桶重新填满。

Agent 打破了这个闭环的每一环。

  • 重试无视退避意图。 把 429 当作瞬时错误的客户端库会重试,通常带有抖动指数退避,而这在 subagent 之间仍会成倍放大。
  • 扇出击穿 IP 键控。 跨地址、区域或出口池镜像的工作负载看起来像许多行为良好的客户端,而不是一个激进的客户端。
  • 镜像击穿按端点限制。 如果限制是按路径的,agent 就把工作分散到各路径。如果是按 key 的,agent 就把工作分散到各 key。限制的好坏只取决于它所绑定的身份。

更糟的是,基于 IP 的限制惩罚了错误的一方。共享 NAT、企业代理或 CI runner 可能因为其背后的某个工作负载行为不端而被限流。限制是真实的,但问责缺失。

准入契约包含什么

替代方案是:不再把 agent 请求当作匿名 HTTP,而是当作协商过的工作负载。准入契约是在第一个真实请求到达源站服务之前建立的一份简短、明确的协议。它有三部分。

Engineer reviewing architectural blueprints and technical drawings on a desk

声明用途与范围,绑定到工作负载身份

契约指明客户端在做什么,以及覆盖哪些资源。关键在于,它绑定到一个 工作负载身份——运行中作业的可验证凭证——而不是一个可被复制、共享或泄露的静态 API key。API key 标识一个租户;工作负载身份标识一个任务。这一区别很重要,因为预算、用途和撤销是任务的属性,而不是组织的属性。

范围应表达为一组允许的操作和资源前缀,而不是自由文本描述。「检索 /docs/ 下的文档」是可执行的。「研究助手」不是。

以站点的口径表达的并发与请求预算

预算必须以站点控制的单位计价,而不是客户端偏好的单位。这意味着:

  • 在途请求的最大数量,而不只是每秒请求数;
  • 契约生命周期内的总请求配额,使长时间运行的作业无法悄悄消耗无上限的容量;
  • 为改变状态的操作单独设置一份更小的配额。

以站点的口径表达预算,正是它站得住脚的原因。客户端无法争辩说它自己定义的「一次逻辑查询」应当映射为五十次上游调用。

在运行中途生效的过期与撤销

契约默认过期。更重要的是,它们可以在作业进行中被撤销,且撤销在边缘于下一个请求时生效,而不是在下一个签发窗口生效。这是大多数实现搞错的部分:它们把准入当作 token 签发时的一次性闸门,这意味着行为不端的客户端会一直保留访问权直到 token 过期。

撤销句柄是站点可以使其失效的一个短标识符,外加一个将该失效Large storage tanks at an industrial port facility by the water under clear blue skies

Server rack closeup

在边缘终结契约

准入决策属于网关或 CDN 层,位于源站服务之前。源站永远不应看到未经协商的流量;当请求到达应用服务器时,契约已被检查、预算已递减、决策已记录。这使各服务间的执行保持一致,并防止常见的失效:一个团队的源站受保护,另一个团队的没有。

边缘也是唯一拥有足够视角来执行并发限制的地方,因为它能看到某个工作负载身份的所有在途请求,无论它们指向哪个源站。

将准入决策记录为结构化事件

每一次允许、拒绝、限流和撤销都应发出一个结构化事件,包含工作负载身份、契约标识符、操作类别和原因。要点是可诊断性:滥用应当看起来像一次带有具名契约的策略违规,而不是一次需要一小时才能归因的莫名流量尖峰。

这也改变了运维对话。不再是问「流量为什么涨了?」,问题变成「哪个契约超出了预算,这是预期内的吗?」——一个有负责人、有答案的问题。

将只读检索与改变状态的调用分开

读和写有不同的风险画像,应当有不同的授权。检索契约可以宽泛、廉价且易于撤销。改变状态的契约需要更强的授权、单独的预算,最好还有一个明确的人工或策略审批步骤。把两者混为一谈,正是本应总结一个页面的 agent 最终向某个端点发帖的原因——因为它持有的凭证权限过大。

一个具体机制:从契约签发短时效、按操作限定范围的 token,并让边缘拒绝任何方法或路径落在 token 声明操作类别之外的请求,即使底层工作负载身份有效。

这解决不了什么

准入契约不会让 agent 变得可信。它让 agent 变得可问责、可叫停。一个在用途上撒谎的客户端仍会撒谎——声明是一种协调机制,不是安全边界。

这正是撤销路径比声明更重要的原因。如果不诚实的客户端与源站之间唯一的屏障是一个自报的用途字符串,那这套系统就是做戏。如果站点能在运行中途切断工作负载、把决策归因到具名契约、并在结构化日志中看到违规,那么声明就成为一个有用的信号,而不是一个承重的假设。

诚实的取舍是摩擦。协商契约增加了一个设置步骤,要求客户端携带工作负载身份,并迫使站点维护一个用于撤销的控制平面。跳过它的站点将继续把 agent 流量当作 Web 流量来吸收,并继续发现另一端的客户端不会累。

分享XLinkedIn永久链接6 分钟阅读

这能回答的问题

Why does IP-based rate limiting fail for agent traffic?

Agents retry without fatigue, fan out across many addresses and mirror requests across endpoints and keys. IP keying also punishes shared egress points like NATs and CI runners, so the limit applies to the wrong party.

What is a workload identity in an admission contract?

It is a verifiable credential for a specific running job rather than a static API key for a tenant. Budgets, purposes and revocations are properties of tasks, so binding the contract to the task makes enforcement meaningful.

Why must revocation work mid-run?

If admission is only checked at token issuance, a misbehaving client keeps access until expiry. A revocation handle propagated to every edge node lets the site stop a workload on its next request, which is what makes the contract enforceable rather than declarative.

Should read and write operations share a budget?

No. Read-only retrieval can be broad, cheap and easily revoked. State-changing calls need a stronger grant, a separate smaller budget and often an approval step, so an over-scoped credential cannot mutate data by accident.