症状与误诊
集群事故很少以调度问题的面目出现。它通常以推理问题的面目出现。某个 Agent 陷入循环,两个 Agent 互相矛盾,三个 Agent 用略有差异的 prompt 产出同一份产物,于是事后复盘便滑向模型:规划器太含糊,子 Agent 误解了指令,评审者不够挑剔。
追踪检查通常会讲出另一个故事。循环发生在某个队列的下游。一次工具调用——一次缓慢的搜索、一个被限流的 API、一个决定变得哲学化的数据库——耗时超过了调用方的超时时间。调用方重试。由于这次重试是一个全新任务,而不是对同一工作单元的重新认领,它再次扇出。此前一直在等待同一个上游结果的兄弟 Agent 现在也超时了,它们也重试。每次重试都携带相同的上下文,于是事故的 token 成本超线性增长,而实际完成的工作量毫无增长。
这些追踪中的推理质量往往是合格的。Agent 正在产出合理的中间输出;它们只是把同样的输出产出了好几遍,顺序错了,依据的是过时的假设。缺失的不是更好的规划器,而是一种卸载或推迟负载的机制。
这一区分很重要,因为两种诊断指向相反的修复方向。如果问题是推理,修复手段是 prompt 工程和模型选型。如果问题是排队,修复手段是架构性的:准入控制、背压、幂等性,以及一个清楚自身极限的调度器。
把准入控制作为第一项设计决策
任务图中的每一条扇出边都需要两个声明式数字:最大宽度和最大深度。宽度是允许同时处于执行中的子任务数量。深度是允许进行多少代委派,之后图必须返回结果。两者都是设计期常量,在图规格中声明,而不是在生产环境中盯着账单才发现。
一条有用的准入规则是合取式的:只有当 worker 槽位和预算切片同时可用时,任务才被准入。worker 槽位约束并发。预算切片约束成本和挂钟时间暴露。任一耗尽,任务就不启动。它要么带着截止时间进入队列,要么带着记录在案的原因被丢弃。
丢弃是一种正当结果。一个无法拒绝工作的调度器不是调度器,而是漏斗。静默的无界扩张才是失败模式,而它之所以静默,恰恰是因为系统中没有任何东西被允许说不。

一个具体机制:把编排器的状态表示为账本,而不是对话。每个被准入的任务持有一份租约——(task_id, worker_slot, budget_slice, deadline)。租约在完成时、显式失败时或到期时释放。调度器每个 tick 的工作,就是把队列中的任务与空闲租约进行匹配。这并不光鲜,但这就是全部。
Agent 之间的背压
子 Agent 应当能够发出“现在不行”的信号,而不是先吸收工作、再迟延失败。迟延失败代价高昂:工作已经消耗了上下文、token 和时间,而失败暴露的时点上,父级已经丢失了低成本恢复所需的信息。
有两种机制让提前拒绝变得安全。
第一,带可见性超时的共享队列。一个任务在有限时间内只被一个 worker 认领。如果 worker 在该时段内没有完成或续租,认领即过期,任务重新可见。这防止两个 Agent 认领同一个工作单元——这是那些看起来互相矛盾的集群中,重复输出最常见的来源。它们并非意见不合;它们只是在做同一件事。
第二,为每一个有副作用的操作加上幂等键。当重试携带与原始尝试相同的键时,下游系统可以据此去重,而不是执行两次。正是这一点让背压可以激进。没有幂等性,激进的拒绝与重试是危险的,因为重试可能造成双重写入。有了幂等性,拒绝工作既廉价又安全,系统就可以被调校为尽早卸载负载,而不是吸收负载然后崩溃。
这个权衡是真实存在的:幂等性需要图中每一个工具、每一个外部服务的配合,而其中一些不会提供。在它们不提供的地方,调度器必须要么串行化对该工具的访问,要么接受至多一次语义并显式处理其中的缺口。假装问题不存在,正是集群获得一类只在负载下才出现的 bug 的方式。
该埋哪些点
按任务类型做四项测量,就能覆盖大部分诊断场景:

- 队列深度——有多少工作在等待,随时间采样。
- 等待时间——准入延迟,从入队到授予租约。
- 认领到完成时间——执行延迟,与等
放大系数是最有用的单一信号。当它接近一时,系统大致把每份工作做了一次。当它攀升时,集群正在把容量花在重新推导它已经拥有的结果上,再多的 prompt 打磨也压不下来。
一次运行应当可以被重建为一条准入时间线——任务入队、授予租约、续租、租约过期、任务完成、任务进入死信——而不是一列消息。消息日志告诉你 Agent 说了什么。准入时间线告诉你系统做了什么,而只有后者能解释一次事故。
对放大系数告警,而不是对 Agent 数量告警。Agent 数量是一个虚荣指标,在健康的突发流量中和在级联故障中都会平滑上升。放大系数能把两者区分开。
一条设计规则
把编排器当作一个由三部分组成的调度器:调度器、预算账本、死信路径。调度器负责准入。账本负责成本与并发核算。死信路径负责一切耗尽重试的工作,让失败可见、可检查,而不是被静默地永远重新入队。
规划器的输出应当是一张声明了宽度和深度的任务图,而不是自由形式的委派。一个输出“调研市场并综合发现”这类散文的规划器,产出的是一个愿望,不是一张图。一个输出带有有界扇出、显式依赖和逐节点预算上限的节点的规划器,产出的才是调度器能执行、预算账本能强制执行的东西。
用负载下的吞吐量和完成率来衡量集群,而不是用它对话的优雅程度。对话质量是一个代理指标,在演示中与成功相关,在生产中则与成功脱钩。固定并发预算下的吞吐量、固定截止时间下的完成率,以及放大系数,才是预测系统能否经受真实流量冲击的数字。
令人不适的推论是:一个推理平庸但调度出色的集群,会胜过推理出色但没有准入控制的集群,因为后者把容量花在重做已经做过的工作上。调度不是系统里无趣的部分。它决定了有趣的部分究竟能不能跑起来。
封面照片:panumas nikhomkhai / Pexels。
