最贵的 Agent 事故,往往从一个"看起来很健康"的仪表盘开始。请求还在返回,worker 还在忙,只是队列在悄悄变长。然后某个模型或工具慢下来,这条等待线就变成了超时、重试、重复劳动,以及一个看起来卡死的聊天窗口。
缺的那一环通常不是再加几个 worker,而是AI Agent 背压:一份明确的契约,让系统不再接收超出"有用期限内能做完"的工作量。这份契约要覆盖交互式和后台两类 Agent 工作流,包括租户公平、队列上限、重试规则,以及诚实的用户可见状态。
队列不等于背压
队列是生产者和 worker 之间的存储。背压改变的是:当存储满了、或下游容量掉了,系统该怎么办。
没有背压,API 会接收每一个请求,每个 Agent 再扇出成模型调用和工具调用,provider 一慢,worker 就一直在重试。系统表面上一直可用,直到大部分请求已经等得太久、失去意义。长队列不是韧性,是延迟的拒绝。
Agent 比普通请求处理器更吃这一套,原因有四条:
- 一个客户请求可能生成大量模型、检索和工具调用;
- 一个慢依赖占住并发的时间,远长于典型 API 调用;
- 重试会在容量最低的时刻把负载成倍放大;
- 一次批量导入可以吃掉服务交互用户的同一份模型配额。
近期的开发者讨论也反映了这种区分:限流是下游 provider 发出的信号,背压是应用自己的决定——在堆积形成之前,选择排队、延后、降级还是拒绝。AWS 的 Agent 编排指引同样要求在 workflow、agent、tool、model 各层都设控制。跨层设计才是真正的缺口:光有 token 预算或一个持久队列,并不能告诉 API 容量耗尽时该做什么。
先定过载契约,再写 worker
先决定每一类工作在压力下允许做什么,别让某个实现细节替你做这个决定。
关键问题是:这个请求如果等下去,还能产生价值吗?答案是否,快速回复比转圈更友善;答案是能,就返回一个任务引用,并展示排队、运行、暂停或失败状态——永远不要给一个假的百分比。
给每次运行一个统一的截止时间,从准入那一刻开始算,而不是从第一次模型调用开始。一个五分钟的工作流在队列里等了四分钟,只剩一分钟可执行。把这个截止时间传给每个阶段,才能防止过期任务继续消耗新鲜容量。
准入结果可以定义成四种:已准入(带 runId 和截止时间)、已排队(可带位置提示)、延后(带重试秒数)、拒绝(带重试秒数和原因)。
给每一处会堆积的地方设上限
Agent 系统往往不止一个队列:HTTP 连接池、进程内信号量、任务 broker、模型 provider、工具客户端、数据库连接池。只给 broker 设上限,过载只是换个地方堆。
限制要落在四个范围:
- 全局并发,保护共享的 provider 和数据库;
- 按租户并发,防止一个吵闹的客户吃掉所有槽位;
- 按工作流并发,防止一个扇出计划同时发起五十个调用;
- 按依赖并发,把慢浏览器、搜索 API 或模型路由与健康工作隔离。
队列长度同样要设上限。大输入文件和原始网页不要放进队列,任务记录里放对象引用即可。有界队列应该装够重启工作所需的信息,而不是无限增长的载荷。
一个刻意做小的准入函数大致是这样:设最大运行数 24、最大排队数 200;某租户已在运行 3 个,就返回延后、30 秒后重试;运行数已满,就排队或拒绝;排队数也满了,直接拒绝并给出重试秒数。生产环境里,这些计数器要原子化并跨副本共享,比如通过数据库、Redis 脚本或队列原生原语。
重试也要被信号量包住,包括重试决策的边界,这样无限重试就绕不过并发限制。对有副作用的工具,还要配上幂等键和对账;一次成功写入之后的超时,不能盲目重放。
延迟了就诚实地说
流式输出会掩盖过载。如果聊天连接一直开着,而真正的任务还在 worker 队列里等,用户看到的是空响应,只会以为模型在思考。
应该发的是状态迁移:已接受、已排队、运行中、等待依赖、等待审批、已完成、失败。文案要事实化:"正在等待容量,将自动重试至 10:42"是有用的,"快好了"不是。
对等不起的请求,在流开始之前就拒绝,返回稳定且有文档的错误载荷,包含错误码、重试秒数、请求 ID 和是否可安全重试。客户端应遵守这个延迟,不要每次重试都新建一个 run;复用幂等键,别让一次网络抖动把一次点击变成一堆排队任务。
盯住那些暴露坏承诺的信号
CPU 和模型延迟不够用。要按模型路由、工具、租户层级和工作类别分别追踪:
- 准入、排队、延后、拒绝、完成的运行数;
- 队列深度和最老排队时长;
- 从准入到首个有用输出的时间;
- 执行时间与排队等待时间的对比;
- 重试次数、重试原因、截止时间之后的重试;
- 取消数和执行前被移除的任务数;
- 并发利用率和依赖错误率;
- 完成率和每个已完成工作流的成本。
告警要看组合,不看单个数字。队列深度上升叠加最老排队时长上升,说明需求超过服务能力;队列深度平稳但执行延迟上升,指向下游依赖;队列满而 worker 空闲,多半是调度、租约或分区出了 bug。
做一次简单的演练:让一条模型路由变慢,灌入混合租户流量,再恢复。验证交互用户拿到的是快速回答或快速拒绝,批量工作停止扩张,重试没有尖峰,队列排空后没有第二波涌来。
上线计划别给用户惊喜
先只观察。算出每个请求本来会被准入、排队还是拒绝,但先不执行,再拿这个结果和真实排队时长、完成数据对照。
然后给一个非关键的后台功能加上小的全局上限和一个按租户上限。在拒绝变成常态之前,先把明确状态加进 UI 和 API。最后,在摸清正常容量和降级容量之后,再加优先级预留和按依赖的限制。
把契约写给客户端看:哪些错误可重试、等多久、任务何时会排队、如何轮询或订阅状态。背压成功,是调用方改变了行为;背压失败,是所有调用方同时重试。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.