我接手过不少多智能体协作的项目最近踩的坑尤其典型。企业内部有个自动化场景总共四个 Agent 参与客服工单接入、粗分类、方案推荐、用户回访话术起草。第一版设计图省事直接把四个 Agent 拉进一个虚拟讨论组让它们自由发言谁有想法就说一句看起来特别前沿。实际跑了不到一周工单处理时长的中位数涨了将近一倍有的工单被两个 Agent 重复认领还有的工单因为中间有人反问一句就卡住了。最后团队成员看到 Agent 在群里互相 第一反应不是觉得智能而是心里发毛这活儿到底听谁的后来我才彻底想明白一句话多 Agent 不该在群里开会。企业任务里的协作依赖的不是自由讨论而是边界、状态和汇聚结果这三件套。这篇文章就是从这次的教训出发给同样在搞多 Agent 系统的朋友捋一套可以直接落地的协作框架重点聊聊每个 Agent 的职责边界怎么划、状态怎么同步、结果怎么汇聚适合正在设计多智能体任务编排、或者考虑把 Agent 接入业务流程的团队参考。1. 问题先摆出来多 Agent 开会为什么越来越乱1.1 我差点被“让 Agent 们拉个群聊”的方案坑了最开始接到这个任务时需求方其实讲得挺模糊希望工单进来之后多个智能体各自处理一部分最后自动生成处理建议。我一开始想到的方案很自然给每个 Agent 一个发言窗口让它们围绕工单内容“讨论”出结论。为了让 Agent 之间互相理解我甚至在系统提示词里写了一句话你可以看到其他人的发言需要时可以直接回复。听起来像是一个大人际场面的线上会议室对吧实际上跑起来完全不是那么回事。几个 Agent 不会像人一样遵守发言顺序也不会主动收敛话题。客服分类 Agent 发了一条“该工单属于账单问题”方案推荐 Agent 紧接着说“建议优先退款”而接入 Agent 又插进来补一句“用户情绪偏激动”。信息是有了但没有人负责把这些信息变成统一的结论。更糟糕的是因为每个 Agent 都以为别人会做收口最终输出里常常出现互相矛盾的内容一边说不符合退款条件一边又建议发起退款流程。那次失败让我意识到一件事人类开会能收敛是因为我们默认存在会议主持人、议程和最终决策机制。Agent 群聊里如果不显式设置这些规则那不叫协同叫信息广场。1.2 群聊式协作的本质缺陷三个失控我把这种自由发言式协作的毛病总结成三个失控点简化说要害。第一是上下文失控。群里每个 Agent 都维护自己的体会当消息数量一多它们对同一份工单的理解会出现偏差。A 理解成用户要求开发票B 理解成用户投诉发票迟迟未收到最后两个 Agent 都在围绕“发票”展开但处理方向完全不同。第二是状态失控。自由讨论里没有谁在记录“这件事现在进行到哪一步”没有明确的状态归属。结果就是同一个工单被重复处理或者所有 Agent 都在等别人先动形成死等。第三是结果失控。即使大家七嘴八舌讲了很多因为没有明确的汇总规则最终的结果经常是“谁最后发言谁定”。这不是基于事实做决策而是顺序和采样偏差在替你定结论。群聊不是不能用但它只适合探索型任务像是头脑风暴出点子。可企业任务往往要求确定性的流程闭环谁来干、干到什么程度、产出物交到哪里。这恰恰要求我们用更工程化的方式约束 Agent。2. 让每个 Agent 守好自己的边界2.1 边界是什么任务口径、数据权限、输出契约我后来重新设计协作框架时第一件事不是画架构图而是给每个 Agent 划边界。边界这个词听上去抽象落在工程里其实就是三样东西任务口径、数据权限、输出契约。任务口径指的是这个 Agent 只负责哪一段任务不负责什么。比如分类 Agent 只输出工单类型标签它不负责判断该不该退款更不负责联系用户。有了口径之后Agent 不会随便越界去“好心帮忙”。数据权限解决的是 Agent 能读什么、不能读什么。还是拿工单举例分类 Agent 只需要读到工单正文和用户ID不需要看到历史账单明细而退款方案 Agent 则需要访问订单流水、优惠券记录。这个限定既是为了信息隔离也是在减少无关上下文对模型的干扰。输出契约是边界里最容易被忽略的部分。每个 Agent 对外输出的信息必须遵循固定结构比如 JSON 里有哪些字段、字段取什么值范围、拿不到信息时怎么表达缺失。这样后续汇聚层才能稳定读取。没有契约Agent 写一段自然语言总结看起来智能实际上没法被下游程序可靠处理。2.2 边界怎么落地角色定义 任务卡片我在代码里用一版很直接的数据结构来承载边界定义本质上就是把每个 Agent 当成一个“有职责的岗位”而不是一个自由角色。agent_role { agent_id: triage_agent, scope: classify_ticket_and_extract_customer_intent, read_permissions: [ticket_text, customer_id], write_permissions: [ticket_category, priority_score], input_contract: {ticket_text: string, customer_id: string}, output_contract: { ticket_category: enum[账单, 技术故障, 退货退款, 投诉], priority_score: float[0.0, 1.0], summary: string, 不超过50字 }, escalation_rule: 如果用户情绪词命中[愤怒, 极度不满], 标记为高优先级 }注意这里有个关键词叫“escalation_rule”意思是边界里还应该写清楚这个 Agent 遇到什么情况可以升级以及升级给谁。因为我们不能让一个分类 Agent 在处理不了时就胡思乱想它必须有一条显式的安全通道。另外我在实际操作里会把每个 Agent 的角色定义写进系统提示词同时把任务卡片作为每条任务实例的输入前缀。任务卡片本质上就是一次具体任务的边界实例化当前任务编号、当前 Agent 的职责、允许读取的字段、输出格式要求。这样做的收益很直接Agent 不再需要依赖对其他 Agent 的“理解”来行动它只需要专注自己的那一小块工作做完交活就行。调试验证时也方便谁没按契约输出一眼就能看出来。3. 状态唯一可信的事实来源3.1 为什么状态管理比“互相通知”更重要有了边界之后Agent 各自干各自的活但一个新问题出现了它们之间如何知道彼此的进度很多人的第一反应是建立通知机制A 干完了就告诉 B。但我建议把重心放在共享状态上而不是消息传递上。原因是消息通知天然是异步且易丢失的。A 发了消息B 没在线消息就丢了或者 A 发了两条消息B 只处理了后一条状态就错乱了。这就像团队协作里靠“口口相传”管理任务总有人漏听。共享状态的核心思路是所有 Agent 不直接通信而是读写一个共享的任务状态对象。状态对象记录当前任务的全生命周期信息包括任务编号、当前阶段、负责人、产出物、异常标记。任何 Agent 想了解进度只需要查看这个对象不需要去问别人。3.2 状态机的设计待处理、执行中、受阻、已完成状态不能是自由字符串必须是有限状态。我给这个工单任务设计了四态虽然简单但已经能应对大多数企业流程pending任务已创建等待被领取处理running有 Agent 正在执行blocked任务受阻需要人工介入或等待外部输入completed所有必要步骤完成产出物已提交可能有人觉得四态太简单了实际上复杂系统的状态不是数量多而是转移规则清晰。我把状态转移逻辑显式放在编排层Agent 无权随意修改状态只能通过上报动作让编排层决定下一步。这样不会出现两个 Agent 同时把状态改成 running 的情况。一个典型的流转是这样的接入 Agent 创建工单状态置为 pending分类 Agent 认领后置为 running分类完成并写入类别编排层把状态切回 pending但这时候开始等待方案 Agent。方案 Agent 拉起后状态又变为 running。如果某个 Agent 发现自己需要用户补充信息它就上报 blocked等到外部输入到达后再恢复。我在系统里专门写了一个状态变更记录表每次转移都留下日志。后面排查问题变得特别轻松只要看状态记录就能还原整个任务过程不需要再猜 Agent 到底经历了什么。3.3 状态同步机制事件驱动与共享存储状态管理不能光靠一个公共变量工程上我推荐“共享存储加事件通知”的组合。共享存储可以是一个简单的 Redis 键值结构也可以是一张数据库表关键是它是唯一的事实来源。事件通知负责在状态变更时提醒订阅方让下游 Agent 能及时被唤醒。具体流程就是某个 Agent 完成任务后编排层更新共享状态同时发布一个事件事件内容带上任务ID和新状态。等待队列里的下游 Agent 收到事件后开始工作。这个过程简单但可靠因为即使事件丢失我们依然可以从共享状态里恢复进度相反如果只有通知没有共享状态事件一丢整个流程就断了。在实现上我会写一个很薄的编排函数核心逻辑只有三件事更新状态、存储产出物、发布事件。所有 Agent 都必须通过这个函数上报不允许旁路直写。这个约定虽然基础但能挡住前期项目里一大半的协作事故。4. 汇聚结果最后的收口动作4.1 从“大家讨论”到“结构化汇总”边界和状态解决了过程协作的问题最后一步是把多个 Agent 的产出合并成一份可用的结果。这一步我称之为汇聚结果。群聊式方案里没有汇聚这个动作大家讨论完结论靠“感觉”。而企业任务不能靠感觉必须有一个显式的收口机制。汇聚动作一般发生在一个协调 Agent 或一段编排代码里。它负责三件事收集所有子 Agent 的结构化产出检测彼此之间是否有冲突然后按预置规则合并出最终结论。为了让这个步骤可靠前面提到的输出契约就显得至关重要了只有结构化数据才能稳定地做冲突检测和合并自由文本永远无法保证。4.2 冲突检测与合并策略冲突检测是汇聚层最容易忽略的环节。多 Agent 协同处理同一件事出现矛盾几乎是常态。比如分类 Agent 把工单标为“退货退款”而方案 Agent 基于同一份工单建议“补偿优惠券而不是退货”这不算冲突因为一个是分类一个是具体动作。真正需要检测的是同一指标上出现的不一致。我在系统里预设了几类常见冲突规则同一工单是否同时被标记为不同优先级是否同时出现“通过”和“拒绝”两种状态是否出现金额不一致的退款额度检测到冲突之后我并不会立刻让某个 Agent 重新跑一遍而是进入人工决策分支因为自动纠错容易掩盖根源问题。合并策略我通常采用等级制有些字段以某个 Agent 的输出为准有些字段以另一个 Agent 的输出为准。比如工单分类以分类 Agent 为准推荐方案以方案 Agent 为准而最终汇总的简报由汇总 Agent 基于上下文重新生成。这就像团队里不同角色各司其职最终文档由主笔人统一润色而不是所有人往同一份文档里填内容。4.3 结果验收与人工兜底汇聚结果完成后不能直接认为万事大吉。我会在整条链路里保留一个验收环节校验最终输出是否符合交付模式必填字段是否齐全数值范围是否合法。这些规则都是提前定义好的代码不复杂但能挡住很多低级错误。另外人工兜底通道必须存在。企业任务和实验性任务不一样一旦面向真实用户错误是有成本的。我在系统里专门留了一个“人工复核队列”凡是冲突检测不过、置信度偏低、或者用户情绪标记为严重不满的工单都进入这个队列。设计的时候可能会觉得这是退步但实际运行下来发现这个兜底通道反而让整个系统更敢于自动执行因为团队知道有最后一道网在。5. 一个完整实操示例客服工单自动处理5.1 任务定义与边界划分这一节我完整还原一个模拟项目 X 的实现过程方便你对照设计。这个项目用四个 Agent 处理客服工单接入 Agent、分类 Agent、权益方案 Agent、回访话术 Agent。为了让流程能跑通我对每个 Agent 的职责做了非常细的划分。agents { intake_agent: { scope: 解析工单文本提取用户id和主诉, inputs: [ticket_text], outputs: [customer_id, complaint], }, triage_agent: { scope: 判断工单类型、优先级和风险等级, inputs: [customer_id, complaint], outputs: [ticket_category, priority, risk_level], }, benefit_agent: { scope: 根据用户权益和历史订单给出可执行处理方案, inputs: [customer_id, ticket_category, priority], outputs: [suggested_action, refund_amount], }, reply_agent: { scope: 生成面向用户的回访或答复话术, inputs: [customer_id, complaint, suggested_action], outputs: [reply_text], }, }注意 reply_agent 的输入里没有 refund_amount这是我刻意做的隔离设计话术 Agent 只需要知道处理动作的方向不需要接触到具体金额数值。这样可以避免它在生成话术时替用户做“值不值得”的判断。5.2 状态流转实现定义好边界后我实现一个极简的编排函数。它接收当前任务对象和一个 Agent 上报的产出更新状态然后决定下一步。代码不复杂但把状态转移规则显式化了。def handle_agent_report(task, agent_id, output): task.progress[agent_id] output if agent_id intake_agent: task.stage triage task.status pending emit_event(task.id, triage_ready) elif agent_id triage_agent: if output.get(risk_level) high: task.stage manual_review task.status blocked else: task.stage benefit task.status pending emit_event(task.id, benefit_ready) elif agent_id benefit_agent: task.stage reply task.status pending emit_event(task.id, reply_ready) elif agent_id reply_agent: task.stage done task.status completed save_task(task)这里面有个细节想强调高风险工单在这里被直接拉到 manual_review不让权益方案和回访话术自动生成。因为真实业务里高风险工单往往需要人工先确认用户情绪和背景直接放 Agent 去生成回复容易火上浇油。这条规则看起来很简单但在初期设计时很容易因为“追求全自动”而忽略掉。5.3 结果汇聚与最终输出四个 Agent 跑完后最终输出由一段汇聚代码而不是某个 Agent 完成。因为汇聚逻辑需要确定性交给大模型自由发挥反而容易失控。我用代码把关键字段拼装成标准结果格式。def aggregate_result(task): triage task.progress[triage_agent] benefit task.progress[benefit_agent] reply task.progress[reply_agent] conflict check_conflict(triage, benefit) if conflict: enqueue_for_manual_review(task.id, reasonconflict) return final_result { ticket_id: task.id, category: triage[ticket_category], priority: triage[priority], action: benefit[suggested_action], refund_amount: benefit.get(refund_amount), reply_text: reply[reply_text], review_required: triage[risk_level] medium, } return final_result我在这个项目里还加了另一个合并规则回复话术里提到的退款金额必须和 benefit_agent 给出的金额一致。如果 reply_agent 里写了一个数字而结构化的 refund_amount 是另一个数字最终展示给用户之前就会被拦截下来。这类校验肯定不是 AI 能做好的事用规则代码反而更稳。6. 常见问题与排查经验6.1 典型故障现象与定位多 Agent 系统一旦进入生产问题就千奇百怪。我汇总了几类特别常见的现象根因排查思路任务卡在 pending 不动状态流转事件丢失或下游 Agent 没有订阅查看状态变更日志确认是否发出事件多个 Agent 重复处理同一任务缺少认领机制两个消费者同时拉取在状态里加 owner 字段原子性地做认领最终结果出现相互矛盾字段输出契约未严格校验在汇聚前加 schema 校验强制枚举有效性Agent 输出“我不知道”但任务标记为 completed输出契约里缺少缺失值表达增加字段 unknown_reason检测后转入人工队列某个 Agent 长期占用任务不释放缺少超时机制为每个状态加超时阈值超时自动置为 blocked第一类问题出现频率最高。事件驱动系统的经典毛病就是事件发出后订阅者没收到或者还没来得及消费任务就永远停在那里。我会在状态变更日志里加一个“should_have_consumed”字段每次发布事件时把预期消费者写进日志排查时直接看谁没消费省去了大量问询时间。6.2 几个必须留意的显式规则除了排查故障我在几次项目里总结出几条写进系统提示词和代码注释的规则虽然不是复杂算法但实战价值非常高。第一Agent 之间不直接对话。任何信息传递都通过状态对象和事件完成禁止在系统提示词里鼓励 Agent 互相参考对方的最终输出。一旦逻辑上允许 Agent 直接引用另一个 Agent 的产出汇聚层就很难判断数据来源可信度。第二每条任务必须有一个唯一的负责人字段。这个 owner 可以是单个 Agent也可以是“人工”。当多个 Agent 都有权处理某一步时必须在编排层加锁或者用原子认领而不是靠 Agent 自觉。第三状态必须支持回滚。我在本地用“状态快照加 append-only 日志”来实现回滚一旦后续发现某个 Agent 的产出有问题可以回到任务上一个稳定点而不是推倒重来。第四给 Agent 设置“不做权”。边界定义里不要只写它做什么更要写它不做什么。比如分类 Agent 不评价退款合理性权益方案 Agent 不直接回复用户。这个“不做权”能减少 Agent 在信息不足时强行发挥的冲动。6.3 什么时候才可以“开会”讲到这里并不是说多 Agent 交流一无是处。在实际测试里我把群聊式方案保留给了两个特殊场景任务前期的目标对齐和任务完成后的复盘总结。目标对齐阶段多个参与 Agent 在还没有具体任务输入时先对目标、约束、优先级达成共识。这个共识会作用到后续每个 Agent 的提示词里。复盘阶段在任务已经完成、结果已经确定之后让多个 Agent 聚在一起回顾过程、提炼经验帮助优化下一轮提示词和规则。这两个场景的共同点是低频、低风险、结果不直接面向用户。至于任务执行过程中群聊式交流我还是建议彻底禁用。你把群聊当成离线评审工具没问题别把它当成在线执行引擎。6.4 对这套协作方式的持续迭代思考边界、状态和汇聚结果这三件套不是一个一次性设计而是需要跟随业务持续迭代。我在实际运营中发现业务方常常会提出新的字段需求工单要增加“是否是会员”维度、方案要增加“多方案对比”、回访要增加“渠道偏好”。每次新增字段都要顺着边界定义、状态数据结构、汇聚校验三个位置同步修改漏掉任何一环都会在运行期暴露问题。所以我会在项目里额外维护一份变更清单每次接口调整时强制走一遍三个层面的关联检查。这样做看起来增加了工作量但能省掉后续大量定位成本。多 Agent 系统不怕改怕的是改不完整最后状态里存着一堆没人消费的字段或者汇聚出来的结果有一半是空的。我个人在这些项目里最大的体会是多 Agent 协作的工程难度不在于每个 Agent 本身聪明不聪明而在于你敢不敢用工程手段去约束它们。群聊式方案之所以诱人是因为它看起来接近人类协作但企业软件真正需要的不是拟人化而是可预期、可观察、可拦截。给每个 Agent 画好边界把状态显式地放在一起让结果收口在确定的汇聚逻辑上这套框架几乎可以平移到任何企业任务里。下次再有人跟你说“让 Agent 们自己商量着办”你可以先把这篇文章甩给他然后问他那出了分歧听谁的