引言:协调者不是多Agent的附加品
当一个系统里只有一个Agent,你把它管好就行了。当系统里有三个Agent,你开始感受到协调的痛苦。当你有十个Agent分布在不同机器、不同平台、不同任务流水线里——你突然发现,最大的瓶颈不是任何一个Agent的能力,而是它们之间谁来拍板、谁来仲裁、谁来承担跨Agent的决策责任。
这个角色,在多Agent系统里通常叫「协调者」(Coordinator)。但很多系统在设计时,协调者是被当作事后补丁加上去的——就像给一个快速增长的组织临时安插一个没有实权的「项目经理」,名字写在组织架构图上,但谁也不听他的。
本文的核心论点是:多Agent系统的协调者困境,本质上是一个权力边界问题,而不是一个技术实现问题。技术选型(用消息队列、共享状态机、还是LLM路由)只是表象,真正的困境在于:协调者应该拥有哪些权力?这些权力在什么情况下会被绕过?被架空之后,系统会走向哪里?
单Agent到多Agent:失控是从哪里开始的
在单Agent场景下,所有的决策链路都在Agent内部:感知→推理→行动→反馈。Agent对自身状态的掌握是完整的,错误也好、异常也好,都发生在同一个上下文中。
多Agent则打破了这种完整性。假设你有一个「写作Agent」负责生成内容,一个「发布Agent」负责多平台分发,一个「审核Agent」负责内容合规审查。在理想情况下,这三个Agent通过有序的消息传递完成任务。但现实是:
比如写作Agent发出「内容就绪」信号时,发布Agent已因等待超时自行启动,跳过了审核步骤,最终导致未通过审核的内容被直接发布。
这是一个典型的竞态条件——但不是在代码的线程层面,而是在Agent之间的通信协议层面。问题的根源不在于任何单个Agent的实现有bug,而在于没有一个统一的视角来观察「当前整体任务的进度」。
这时,协调者的价值就出现了。
协调者的三种典型角色
在实际系统中,我观察到协调者承担的角色大致可以分为三类,每一类对应不同的权力边界。
第一类:路由器(Router)
路由器型协调者的职责是根据任务类型,把请求分发到对应的Agent。比如收到一条用户消息,判断是「写作」「搜索」还是「发布」,然后路由到相应的专业Agent。这是最低侵入性的协调角色——它只负责决策「谁来做」,不介入「怎么做」和「做完了怎么衔接」。
路由器的局限在于:它不持有任务状态。当一个任务跨越多个Agent时,路由器无法回答「这个任务现在做到哪一步了」。如果某个中间步骤失败,路由器要么重新发送请求(可能重复执行前面的步骤),要么让整个任务陷入未知状态。
第二类:状态管理器(State Manager)
状态管理器型协调者持有全局任务状态。每个Agent完成后,向协调者报告而非直接通知下一个Agent,由协调者更新状态并触发下一步。这类设计基于状态机,每个完成事件驱动状态转移。
这种模式解决了任务进度的可见性问题,但引入了新的问题:状态管理器和Agent之间的通信延迟。如果Agent完成了一个耗时很长的操作(比如生成一篇文章),状态报告需要等到整个操作结束才能发出。在这个窗口期内,协调者的状态是「执行中」,它不知道Agent是正常运行还是卡死了。
第三类:仲裁者(Arbiter)
仲裁者型协调者不仅管理状态,还持有决策权。当多个Agent对同一资源有冲突需求时,由协调者决定谁能获得访问权,通常需要实现锁或优先级机制。
仲裁者是最接近「真正的协调者」概念的角色,但也是最难实现的。它的核心困境是:仲裁者本身也是一个Agent——那谁来仲裁仲裁者? 如果协调者崩溃了,整个系统的协调工作也随之停止,这是一个单点故障。
协调者被架空的三个典型路径
在实践中,我见过太多协调者名义上存在、实际上被架空的设计。以下是三条最常见的架空路径。
路径一:Agent之间的直接通信绕过协调者
最常见的架空方式。两个Agent发现协调者的路由延迟太高,直接建立点对点通信来提速。写作Agent直接通知发布Agent「写完了」,而不是通过协调者更新状态。效率短期提升了,但系统状态迅速碎片化——协调者认为任务还在「写作」阶段,发布Agent已经把它标记为「已完成」。效率压力会腐蚀协调协议,这是绕过行为最常见的根源。
路径二:超时重试导致的状态分裂
Agent等待协调者响应时超时,触发重试。如果响应只是延迟而非丢失,同一任务被执行两次,而两次调用大模型API的结果可能不同。协调者没有机制判断哪个结果是「正确」的。要让协调者安全处理重试,每个Agent的操作必须是幂等的——但写文件、发送消息这类操作天然非幂等,强行幂等化会大幅增加实现复杂度。
路径三:优先级反转
高优先级任务(紧急内容审核)需要协调者的决策资源,但协调者正被低优先级任务(大量例行发布)占用时,高优先级请求被阻塞。在单线程协调者设计中,长请求(比如等待某个慢Agent的响应)会阻塞所有后续请求,这种反转可能导致整个系统错失真正的关键事件。
协调者的设计原则:权力必须有边界
基于上述分析,我认为一个有效的协调者必须遵循以下设计原则,而不是试图成为一个「全能型」协调一切的角色。
原则一:协调者不执行,只协调
这是最反直觉但最关键的原则。协调者应该是一个纯粹的决策和路由节点,不应该自己执行具体的业务操作。一旦协调者开始执行操作(比如自己写文件、自己调用API),它就不再是一个协调者,而是一个混合体——既是裁判员又是运动员。混合体的结果是:当协调者执行失败时,你无法判断是「决策错误」还是「执行错误」,问题排查变得极其困难。
原则二:协调者的决策必须是可审计的
每一次协调决定(路由到哪个Agent、授予或拒绝哪个请求),都应记录到不可篡改的日志中。这让协调者的行为可被审查——当Agent质疑「为什么把任务分配给A而非我」,一份完整的决策日志比任何口头解释都更有说服力。
原则三:协调失败应该有明确的降级策略
协调者不可能永远正常工作。当协调者不可用时,系统应有预定义的降级策略:保守策略(停掉非关键任务)、激进策略(Agent独立决策但设操作上限)、高可用策略(切换备用协调者实例)。策略选择取决于业务场景:内容发布适合保守(不发布比错误发布好),搜索系统可用激进(允许一定程度不一致)。
原则四:协调者的权力必须被明确声明,不能靠默契
在很多团队的实现中,协调者的权限是隐式的——「大家知道协调者说了算」。三个Agent时能工作,十个Agent时必然崩溃。正确做法是在系统设计阶段用配置文件明确声明协调者拥有哪些权力,如「只有协调者有权修改任务状态」「只有协调者有权决定执行顺序」「只有协调者有权终止运行中的任务」。
没有明文授权的协调者,在利益冲突时一定会被绕过。
案例:一个内容发布系统的协调者重构
我曾参与一个多Agent内容发布系统的重构。原始设计:写作Agent完成后直接通知发布Agent,由发布Agent自主决定发布时间和目标平台。
症状显而易见:经常出现「发布了还没审核的内容」「同一篇内容被发布到同一平台两次」「平台A成功、平台B失败,但系统状态显示全部成功」。
重构引入了一个职责明确的协调者,只做三件事:持有任务状态(「写作中」→「审核中」→「发布中」→「已完成」)、接收各Agent的事件报告并更新状态、在状态转移时触发对应的Agent。
关键决策:禁止任何Agent之间直接通信。写作Agent不通知发布Agent,只向协调者报告;发布Agent不从写作Agent获取文件,只从协调者获取路径。这看起来多了一层,但解决了所有问题:状态始终准确,失败路径可追踪,发布Agent不再收到未审核内容。
结论:协调者的本质是信任协议
多Agent系统中的协调者,不是代码中的一个模块,不是一个可以随意开启或关闭的功能开关。协调者是一套信任协议——它定义了:在多Agent的环境中,谁有权做决定,谁有权访问共享资源,谁在冲突时优先。
技术实现(消息队列、状态机、LLM路由)只是这套协议的具体载体。真正重要的,是在这套协议被破坏时,系统会发生什么。
好的协调者设计,是让系统在协调者正常工作时保持高效,同时在协调者失效时,有明确的安全降级路径。当你开始设计一个多Agent系统时,先问自己:如果协调者下一秒就消失,这个系统还能做什么? 答案决定了你的协调者设计是否真的有效。
协调者设计的反模式清单
在结束之前,我整理了一份常见的协调者反模式清单,可以作为自查清单。
反模式一:协调者承担业务逻辑。协调者不应该自己写文件、调API、生成内容。一旦协调者开始执行具体操作,它就从"裁判员"变成了"运动员",决策和执行的边界模糊,问题排查变得困难。正确做法是协调者只做路由和状态管理,具体操作由专业Agent执行。
反模式二:状态分散存储。协调者维护状态,但状态同时存在于多个地方:协调者的内存、Agent的本地文件、外部数据库。这种多副本状态必然导致不一致。正确做法是状态有唯一的权威来源,其他地方通过查询获取。
反模式三:隐式的权限约定。"大家都知道协调者说了算"不是权限设计,是定时炸弹。三个Agent时能靠默契,十个Agent时必然出乱子。正确做法是明确定义协调者的权限边界,写进配置文件或代码,而不是靠人的记忆。
反模式四:没有超时和降级机制。协调者等Agent响应时无限等待,一个Agent卡死就拖垮整个系统。正确做法是为每个操作设置超时,超时后触发降级策略(重试、跳过、或人工介入)。
反模式五:协调者单点不可用。协调者是系统的核心节点,但没有备份机制。协调者一挂,整个多Agent系统瘫痪。正确做法是为协调者设计高可用方案(主备切换、多活部署),或者至少设计无协调者时的安全降级模式。
协调者与被协调Agent的接口设计
协调者和Agent之间的通信协议,是多Agent系统稳定性的基石。以下是几个接口设计原则:
幂等性是必须的。Agent接收到的每条消息都应该可以安全地重复处理。因为网络故障、超时重试、协调者切换都可能导致同一消息被发送多次。如果Agent的操作不是幂等的(比如"发送消息"而非"记录消息已发送"),重复处理就会导致数据重复或状态错乱。
状态变更要有版本号。协调者告诉Agent"你的状态现在是X",但这个指令可能因为延迟而过时。正确做法是每个状态带上版本号或时间戳,Agent收到指令时检查版本,旧版本指令被拒绝。
心跳与健康检查要分离。心跳是"我还活着",健康检查是"我能正常工作"。一个Agent可能心跳正常但已经处于异常状态(比如内存耗尽、依赖服务不可用)。协调者应该区分这两种信号,不要因为心跳正常就认为Agent一切OK。
错误要有明确的分类。Agent报告错误时,要区分"可重试的错误"(网络超时)和"不可重试的错误"(参数不合法)。协调者根据错误类型决定是重试、跳过、还是报警。所有错误都当作同一种处理,会导致无限重试或误报警。
从单协调者到多协调者的演进
当一个多Agent系统规模扩大,单个协调者可能成为瓶颈。这时需要考虑多协调者架构。
分区协调是最常见的方案。把Agent按业务域分组,每组有自己的协调者。写作相关Agent一个协调者,发布相关Agent另一个协调者。跨域操作通过协调者之间的通信来完成。这种方案的优点是故障域隔离,一个协调者挂了不影响其他域;缺点是跨域操作需要额外的协调机制。
主备协调者是提高可用性的方案。正常情况下主协调者工作,备用协调者待命。主协调者故障时,备用协调者接管。这个方案的关键是状态同步:备用协调者需要实时获取主协调者的状态,否则切换时会丢失信息。状态同步通常通过共享存储(如Redis)或日志复制来实现。
去中心化协调是更激进的方案。没有中心化的协调者,每个Agent都可以参与协调决策。这种方案通常基于共识算法(如Raft),优点是没有单点故障,缺点是实现复杂度高,性能不如中心化方案。对于大多数应用场景,中心化协调者加主备就足够了。
协调者设计的决策树
综合全文的分析,以下是一个协调者设计的决策树,可以作为设计新系统时的参考:
-
是否需要协调者?
- 单Agent系统:不需要
- 多Agent但操作独立:不需要
- 多Agent且有共享资源/依赖关系:需要
-
协调者承担什么角色?
- 只需要路由:路由器型
- 需要追踪任务状态:状态管理器型
- 需要处理资源冲突:仲裁者型
-
协调者应该有什么权限?
- 读取所有Agent状态:必须
- 修改任务状态:必须
- 终止运行中的任务:根据业务需求决定
- 直接操作业务数据:禁止
-
协调者故障时怎么办?
- 低可用要求:人工介入恢复
- 中等可用要求:主备切换
- 高可用要求:多活部署或去中心化协调
-
如何防止协调者被架空?
- 明文定义权限边界
- 禁止Agent之间直接通信
- 记录所有协调决策的审计日志
- 定期检查是否有绕过行为
这个决策树不能覆盖所有情况,但可以作为思考的起点。每个系统的具体情况不同,但核心原则是一致的:协调者是一套信任协议,它的有效性取决于权力的边界是否清晰、破坏时是否有后果、故障时是否有降级方案。