2026/10/21 0:56:20

多Agent集群实战:构建24小时自主运转的调度、执行与监督系统

多Agent集群实战:构建24小时自主运转的调度、执行与监督系统 1. 从单兵作战到集群协作我为什么要折腾多 Agent 系统最开始接触 Agent 这个概念的时候我和大多数人一样停留在写个提示词让模型帮我干一件事的阶段。比如让它帮我总结一篇文章、生成一段代码、翻译一份文档。这种单 Agent 模式用起来确实爽但用久了就会发现一个很尴尬的问题它本质上还是一个你问我答的被动工具你不发指令它就永远停在那里。真正让我下决心去做多 Agent 集群的是一个很具体的场景——我需要一个能在我睡觉的时候依然持续运转、自己给自己派活、自己检查自己产出质量的东西。单 Agent 的天花板其实很明显。第一它的上下文窗口是有限的你不可能把一整套复杂流程的所有信息都塞进一个对话里第二它没有分工的概念你让它同时做调研、写稿、校对它会在不同角色之间反复横跳最后每件事都做得半吊子第三它没有自我纠错机制一旦某一步跑偏后面就一路错到底。这三个问题叠加起来就导致单 Agent 只能处理一次性、短链路、低容错的任务。多 Agent 集群解决的恰恰是这三个问题。把一个大任务拆成若干子任务每个子任务交给一个专门的 Agent每个 Agent 只关心自己那一亩三分地上下文压力瞬间就下来了。Agent 之间通过消息传递来协作就像一个小团队一样有人负责调研、有人负责执行、有人负责审核。更关键的是你可以设计一个调度 Agent或者监督 Agent让它不断地给其他 Agent 派活、检查产出、决定下一步该干什么这样整个系统就能自己转起来不需要你一直盯着。我做的这个集群核心目标就是24 小时不停工作。注意这里的不停工作不是指让模型 7×24 小时满负荷烧算力那既不现实也没必要。它真正的含义是系统具备自主的任务循环能力——当没有新任务时它能自己去任务队列里找活干当任务失败时它能自己重试或者换策略当所有任务都完成时它能进入低功耗的待命巡检状态而不是直接死掉。这套东西适合谁呢适合那些手头有大量重复性、流程化工作又希望用自动化手段把它们串起来的人比如内容运营、数据整理、代码维护、监控告警这些场景。2. 集群的骨架调度、执行、监督三层结构怎么搭2.1 为什么是三层而不是两层很多人一开始设计多 Agent 系统会本能地做成一个主 Agent 一堆干活 Agent的两层结构。我一开始也是这么干的结果跑了不到两天就发现问题了主 Agent 既要负责拆解任务、又要负责派发、还要负责验收它的上下文很快就被各种任务状态撑爆了而且它一旦卡住整个系统就全停了。这就是典型的单点瓶颈。后来我改成了三层结构调度层、执行层、监督层。调度层只做一件事——决定现在该干什么它维护一个全局的任务队列和状态机根据当前状态决定下一个动作是派发新任务、重试失败任务、还是触发审核。执行层是一组各司其职的 Worker Agent每个只负责一类具体工作比如抓取、生成、转换、写入。监督层则独立于前两者专门负责质量把关和异常检测它不参与任务派发只对执行层的产出做评估把不合格的结果打回或者标记出来。这么拆的好处是每一层的上下文都变得非常干净。调度层只需要知道任务 ID、状态、优先级这些元信息不需要知道任务内容本身执行层只需要知道自己那一个子任务的输入输出监督层只需要拿到待审核的产出和对应的验收标准。三者通过一个共享的任务存储我用的是轻量的键值存储加一个消息队列来通信彼此解耦。2.2 调度层的状态机设计调度层是整个集群的大脑它的核心是一个状态机。我给每个任务定义了这么几个状态pending待处理、dispatched已派发、running执行中、reviewing审核中、done完成、failed失败、retrying重试中。状态之间的流转规则必须写死不能靠模型自由发挥否则系统会变得不可预测。具体来说调度层每隔一个固定周期我设的是 30 秒跑一次巡检循环做这么几件事扫描所有pending的任务按优先级排序后派发给对应的执行 Agent检查所有running的任务如果超过预设的超时时间还没回结果就标记为failed并进入重试队列检查reviewing的任务如果监督层给了通过信号就转done给了拒绝信号就转retrying。这个循环是集群永动的关键只要这个循环在跑系统就不会停。这里有个经验状态机的流转一定要幂等。什么意思呢就是同一个任务被重复处理多次结果应该是一样的。比如一个任务已经是done了调度层又扫到它不能把它重新派发一遍。我一开始没注意这点结果因为消息队列的重复投递同一个任务被执行了三次产生了三份重复产出。后来我在每次状态变更前都加了一个当前状态校验只有状态匹配才允许流转问题就解决了。2.3 执行层的 Agent 隔离执行层的每个 Agent 我都是独立进程跑的而不是塞在同一个进程里用多线程。为什么因为 Agent 执行过程中会调用外部接口、读写文件、占用内存一旦某个 Agent 崩了如果是同进程多线程很可能把整个进程带崩。独立进程虽然资源开销大一点但隔离性好一个挂了不影响其他调度层检测到它没心跳重新拉起一个就行。每个执行 Agent 启动时都会向调度层注册自己声明我能处理哪类任务。调度层派发任务时只派给声明了对应能力的 Agent。这就避免了让写代码的 Agent 去干翻译这种错配。Agent 的能力声明我建议用简单的字符串标签比如fetch、generate、transform、persist不要搞太复杂的本体论够用就行。2.4 监督层的验收标准从哪来监督层最难的地方不是技术实现而是验收标准怎么定义。你让一个模型去判断另一个模型的产出好不好如果没有明确的评判维度它就会和稀泥什么都说看起来不错。我的做法是在任务创建的时候就附带一份验收清单里面是若干条可判定的检查项。比如一个内容生成任务验收清单可能是字数是否在范围内、是否包含指定关键词、是否通过了敏感词过滤、格式是否符合模板。监督 Agent 逐条检查全部通过才算合格。对于无法用规则判定的主观质量我会让监督 Agent 给出一个 1 到 5 的评分并附上理由低于阈值的打回重做。这里要注意监督 Agent 的提示词里必须明确你的职责是挑毛病不是夸奖否则模型天生倾向于给好评。我甚至在提示词里加了如果你找不到任何问题说明你检查得不够仔细这种话实测下来确实能让它更严格一些。3. 让集群真正永动起来的几个关键机制3.1 心跳与自愈Agent 挂了怎么办一个 24 小时运行的系统最怕的就是某个环节悄无声息地死掉。我的做法是给每个执行 Agent 加心跳机制Agent 每完成一个任务或者每隔 60 秒就向调度层发一个心跳信号带上自己的 ID 和当前状态。调度层维护一张心跳表如果某个 Agent 超过 3 个心跳周期没上报就判定它失联把它正在处理的任务重新放回pending队列同时尝试重新拉起这个 Agent 进程。这里有个坑我踩过重新拉起进程时不能无脑重启否则如果是因为配置错误导致 Agent 一启动就崩就会陷入崩溃-重启-崩溃的死循环把系统资源耗光。我的解决办法是加一个重启计数器同一个 Agent 在 10 分钟内重启超过 5 次就把它标记为故障停止自动重启改为告警通知人工介入。这个阈值可以根据实际情况调但一定要有不能让它无限重启。3.2 任务队列的持久化集群要 24 小时跑任务队列就必须持久化不能放在内存里。我一开始图省事用了一个内存队列结果有一次进程意外退出队列里几十个任务全没了只能从头再来。后来换成了基于磁盘的持久化队列每次入队、出队、状态变更都落盘。虽然性能上慢了一点点但换来的是断电也不丢任务的可靠性这笔账怎么算都划算。持久化队列的选型上我建议用成熟的轻量级方案不要自己造轮子。核心要求就三条支持持久化、支持多消费者、支持消息确认ack。消息确认很重要它保证了一个任务在被真正处理完之前不会从队列里消失。如果 Agent 拿到任务后崩了没有发 ack队列会把任务重新投递给其他 Agent。3.3 限流与退避别把外部接口打爆集群跑起来之后执行 Agent 会频繁调用各种外部接口。如果不加限制很容易触发对方的频率限制轻则被限流重则被封禁。我在每个执行 Agent 里都加了令牌桶限流器控制单位时间内的请求数。同时对于失败的重试采用指数退避策略第一次失败等 1 秒重试第二次等 2 秒第三次等 4 秒以此类推直到达到最大重试次数。指数退避这个策略看起来简单但效果非常明显。我实测下来加了退避之后因为瞬时并发过高导致的失败率下降了大概七成。而且退避还能给外部服务一个喘息的机会避免雪崩。这里要注意退避的上限要设一个合理的值不能无限增长我一般设到 5 分钟封顶再长就没意义了不如直接标记失败走人工。3.4 空闲时的巡检与预热系统不可能一直有任务总有空闲的时候。空闲时如果什么都不做那24 小时工作就名不副实了。我的做法是让调度层在空闲时执行巡检任务检查各个 Agent 的健康状态、清理过期的临时文件、统计过去一段时间的任务成功率、预热一些常用的缓存。这些活儿不重但能让系统保持活着的状态也能提前发现潜在问题。预热这块我特别想提一句。有些 Agent 启动后第一次执行任务会特别慢因为要加载模型、建立连接、初始化缓存。如果能在空闲时提前把这些做好等真正来任务时就能秒响应。我一般会在系统启动后和每次空闲巡检时让 Agent 跑一个空任务来触发初始化这样正式任务就不会被冷启动拖慢。4. 实测中暴露的问题与我的处理方式4.1 上下文污染Agent 越跑越糊涂这是我在实测中遇到的最头疼的问题。执行 Agent 如果长时间运行它的对话历史会越来越长里面混杂着各种任务的残留信息导致它在处理新任务时经常串台把上一个任务的内容带到下一个任务里。我一开始以为是模型能力问题后来才发现是上下文管理没做好。解决办法有两个层面。第一每个任务用独立的会话上下文任务开始前清空历史任务结束后销毁上下文绝不复用。第二对于确实需要跨任务记忆的信息比如用户的偏好设置单独存到一个结构化的长期记忆里由 Agent 主动查询而不是靠对话历史携带。这么改完之后串台问题基本消失了。4.2 死循环两个 Agent 互相踢皮球有一次我设计了一个生成-审核的流程结果生成 Agent 和监督 Agent 陷入了死循环生成 Agent 产出一版监督 Agent 打回生成 Agent 改一版监督 Agent 又打回来回几十次任务永远完不成。排查后发现是因为监督 Agent 的验收标准太模糊生成 Agent 根本不知道该怎么改。后来我加了一个最大迭代次数的限制同一个任务被打回超过 3 次就强制升级为人工介入状态不再自动重试。同时监督 Agent 打回时必须给出具体的、可操作的修改意见不能只说不合格。这两条加上之后死循环就再也没出现过。这个经验我觉得很通用任何自动化的循环都必须有终止条件否则迟早会出问题。4.3 资源泄漏跑久了内存越来越高集群连续跑了大概一周之后我发现内存占用在缓慢但持续地上升。查了半天发现是几个地方在泄漏一是 Agent 处理完任务后没有释放临时对象二是日志文件没有轮转越写越大三是某些连接没有正确关闭。这些问题在短时间运行时不明显但 24 小时不停地跑累积效应就出来了。处理方式就是一条条排查给所有临时资源加显式的释放逻辑日志配置按大小和时间双维度轮转连接使用上下文管理器确保关闭。另外我还加了一个定时重启策略每个执行 Agent 每运行 24 小时就优雅重启一次把可能积累的碎片清理掉。这个策略有点笨但非常有效属于兜底手段。4.4 任务优先级反转重要任务被饿死任务队列如果只是简单的先进先出会出现一个问题大量低优先级的任务把队列占满高优先级的任务排在后面迟迟得不到处理。我一开始没设优先级结果有一次一个紧急任务等了快一个小时才被执行。后来我给任务加了优先级字段调度层派发时按优先级排序高优先级先出队。但这里又有个新问题如果高优先级任务源源不断地来低优先级任务就会被饿死永远排不上。所以我用了加权轮询的策略高优先级任务占大头但每处理若干个高优先级任务就穿插一个低优先级任务保证公平性。这个平衡点需要根据实际业务调没有标准答案。5. 从能跑到好用几个提升集群稳定性的细节5.1 结构化日志是排查问题的命根子集群跑起来之后出问题是必然的关键是出问题后你能不能快速定位。我强烈建议从第一天就用结构化日志也就是每条日志都是 JSON 格式包含时间戳、Agent ID、任务 ID、日志级别、消息内容这些字段。这样你可以很方便地按任务 ID 把所有相关日志串起来一眼看出这个任务从派发到完成经历了什么。我一开始用的是纯文本日志排查一个问题要在几千行里肉眼搜索效率极低。换成结构化日志之后配合简单的查询工具定位问题的速度提升了不止一个档次。这个投入绝对值得别省。5.2 可观测性让集群的状态一目了然除了日志我还加了一些指标采集任务总数、成功率、平均处理时长、各 Agent 的负载、队列积压量。这些指标汇总到一个简单的看板上我随时能知道集群现在健不健康。有一次我发现成功率突然从 95% 掉到了 70%一看指标发现是某个外部接口的响应时间变长了及时做了降级处理避免了更大范围的影响。可观测性这东西平时感觉不到它的价值但真出事的时候它就是你的眼睛。没有它你只能靠猜有了它你能直接看到问题在哪。5.3 灰度与回滚新 Agent 别一上来就全量每次我给集群加新 Agent 或者改现有 Agent 的逻辑都不会直接全量上线。而是先让新版本处理一小部分任务比如 10%观察一段时间确认没问题再逐步放大比例。如果发现异常立刻回滚到旧版本。这个习惯帮我避免了好几次因为新逻辑有 bug 导致的大面积故障。灰度发布的关键是能快速回滚。所以我在设计时就保证了 Agent 的版本是可切换的调度层可以根据配置决定把任务派给哪个版本。回滚只需要改一个配置项几秒钟就能生效。5.4 成本控制别让集群变成烧钱机器24 小时运行意味着持续的成本支出如果不加控制账单会很吓人。我做了几件事来控制成本一是给每个 Agent 设了每日的调用次数上限超了就暂停二是对于简单的任务用更便宜的模型只有复杂任务才用贵的三是空闲时降低巡检频率减少不必要的调用。这几招下来成本大概降了四成而系统的实际产出并没有明显减少。成本控制的核心思路是分级处理不是所有任务都值得用最好的资源。把任务按重要性分级重要的用好的不重要的用凑合的整体性价比就上来了。6. 我踩过的那些坑以及给后来者的建议6.1 别一上来就追求全自动我见过不少人一开始就想做一个完全不需要人干预的集群结果做出来的东西要么动不动就卡死要么产出质量惨不忍睹。我的建议是先做半自动让集群处理大部分流程但在关键节点保留人工确认。等系统稳定了、你对它的行为有把握了再逐步减少人工干预。全自动是目标但不是起点。6.2 提示词要当代码一样管理Agent 的行为很大程度上由提示词决定所以提示词不能随手写在代码里而应该单独管理、版本化、可回滚。我现在的做法是把每个 Agent 的提示词存在独立的文件里改动走版本控制每次改动都记录原因。这样当某个 Agent 行为异常时我能快速对比是提示词改坏了还是其他原因。6.3 测试环境要能模拟真实负载在本地跑几个任务没问题不代表在生产环境跑几千个任务也没问题。我专门搭了一个测试环境用脚本模拟高并发、任务失败、Agent 崩溃这些场景在上线前把能想到的极端情况都跑一遍。很多问题都是在这个阶段暴露出来的比在生产环境出事强太多了。6.4 文档和注释别偷懒集群这种东西隔一个月再看你自己都可能忘了某个模块是干嘛的。所以我在每个关键模块都写了注释说明它的职责、输入输出、依赖关系。另外还维护了一份架构文档画清楚各层之间怎么通信、状态怎么流转。这份文档在我后来加新功能、排查问题时帮了大忙。6.5 接受不完美持续迭代最后想说的一点是多 Agent 集群这种东西不存在一次做对的可能。它一定是在不断出问题、不断修的过程中慢慢成熟的。我现在的这个集群和最初版本相比几乎每个模块都重写过。所以别追求一步到位先让它跑起来然后在跑的过程中不断优化。能跑起来就已经赢过大多数停留在设计阶段的人了。这套集群到现在已经稳定运行了几个月期间处理了上万条任务成功率维持在九成以上。它当然不完美还有很多可以改进的地方但它确实做到了我最初想要的那件事在我睡觉的时候它还在干活。这种有个不知疲倦的帮手在替你工作的感觉是单 Agent 时代完全体会不到的。如果你也在做类似的东西希望上面这些经验能帮你少走点弯路。