
1. 从单步对话到多 Agent 协作为什么“一问一答”模式撑不住复杂任务很多人第一次用 Claude Code 的时候体验路径几乎一模一样打开终端敲一句需求等它回一段代码复制粘贴再敲下一句。单文件、小脚本、临时改个 bug这种“单步聊天”模式确实够用甚至比手动写快不少。但只要任务稍微复杂一点——比如要重构一个跨十几个文件的模块、要跑通一条包含构建和测试的完整链路、要在多个子目录之间来回切换——你就会发现单步对话的上下文很快被撑爆模型开始“忘事”前一步刚确认的接口约定第三步就改得面目全非。这个问题的本质不是模型不够聪明而是单步聊天这种交互范式本身把“规划、执行、验证、修正”四个环节全压在一次对话里。一次对话的上下文窗口是有限的而复杂任务的中间状态是爆炸式增长的。你让它一边记着需求一边写代码一边还要自己检查对不对等于让一个人同时当产品经理、程序员和测试谁都干不好。多 Agent 编排要解决的就是把这个“一人分饰多角”的问题拆开。核心思路很朴素让不同的 Agent 承担不同的职责通过明确的编排逻辑把它们串起来再用闭环自愈机制保证出错能自己兜回来。这跟工厂流水线是一个道理——一个人从头做到尾效率低还容易错拆成几道工序每道工序专人负责中间加质检整体产出反而更稳。我自己的体会是判断一个任务该不该上多 Agent有个很实用的标准如果这个任务需要超过 3 次“写-验-改”的循环或者涉及超过 5 个文件的协同修改单步聊天就开始力不从心了。这时候硬扛只会得到一堆看似能跑、实则互相矛盾的代码。与其反复重开对话、手动搬运上下文不如一开始就把编排结构搭好。下面这张表是我在实际项目里总结的单步模式和多 Agent 模式的能力边界对比可以帮你快速判断自己该用哪种维度单步聊天模式多 Agent 编排模式适用任务规模单文件、小改动跨模块、多文件重构上下文压力高容易溢出分散到各 Agent压力可控错误恢复靠人工重开对话闭环自愈自动回滚重试可复用性几乎为零Routine 脚本化可反复调用调试难度低但排查靠猜高但链路可追踪典型耗时小任务快大任务崩前期搭建慢跑起来快理解了“为什么要拆”接下来就得看“怎么拆”。多 Agent 编排不是简单地把几个 Agent 堆在一起它有一套自己的架构逻辑这也是下一节要重点拆解的内容。2. 多 Agent 编排的架构骨架角色、通信与调度三层拆解2.1 角色划分不是越多越好而是职责边界要清晰刚接触多 Agent 的人最容易犯的错就是“角色膨胀”——觉得 Agent 越多越专业于是搞出规划 Agent、编码 Agent、测试 Agent、文档 Agent、审查 Agent、部署 Agent……一圈下来光协调它们之间的通信就够呛。我踩过这个坑最后发现角色数量应该由任务的“职责断层”决定而不是由你想象的“专业分工”决定。什么叫职责断层就是两个环节之间输入输出的格式和判断标准发生了本质变化。比如“把需求翻译成任务清单”和“把任务清单翻译成代码”这两者之间的产物形态完全不同前者是自然语言描述后者是可执行文件这就是一个天然的断层值得拆成两个 Agent。但“写代码”和“写注释”之间没有本质断层硬拆只会增加通信成本。一个经过实战验证的最小可用编排结构通常包含三类角色规划 AgentPlanner负责把模糊需求拆成可执行的任务序列输出结构化的任务清单每个任务带明确的验收标准。它的核心能力是“分解”和“排序”不碰具体实现。执行 AgentExecutor按任务清单逐项执行每次只聚焦一个任务产出具体的代码或配置。它的上下文里只装当前任务相关的信息避免被全局状态干扰。验证 AgentVerifier对执行结果做独立检查判断是否满足验收标准。关键在于它必须“独立”——不能和执行 Agent 共享上下文否则会陷入“自己检查自己”的盲区。提示验证 Agent 的独立性是多 Agent 编排里最容易被忽视、也最影响效果的一点。如果验证和执行用的是同一个上下文模型会倾向于认为“我刚写的肯定对”检查形同虚设。2.2 通信机制Agent 之间怎么“说话”决定了编排的上限角色分好了接下来是它们之间怎么传递信息。这里有个反直觉的结论Agent 之间的通信结构化程度越高整体效果越好。让两个 Agent 用自然语言自由对话看起来灵活实际上极不稳定——同一个意思这次说“请修改这个函数”下次说“这个函数有问题”下游 Agent 的解析逻辑就得跟着变。我现在的做法是所有 Agent 之间的通信都走固定 schema 的结构化消息。比如规划 Agent 输出给执行 Agent 的任务长这样{ task_id: T003, type: code_modify, target_file: src/parser/handler.py, description: 将 parse_config 函数的异常处理从裸 except 改为捕获具体异常类型, acceptance_criteria: [ 不再出现裸 except, 捕获 ValueError 和 KeyError 两类异常, 原有单元测试全部通过 ], depends_on: [T001, T002] }这种结构化的好处是执行 Agent 不需要“理解”一段话只需要按字段执行验证 Agent 也不需要“揣摩”意图直接对着acceptance_criteria逐条核对。通信的确定性上去了整个编排的稳定性就上去了。2.3 调度逻辑串行、并行还是条件分支调度层决定了任务按什么顺序、以什么依赖关系执行。常见的调度模式有三种各有适用场景串行调度任务一个接一个执行前一个的产出是后一个的输入。适合强依赖的链路比如“先建表结构再写数据访问层最后写业务逻辑”。优点是简单可控缺点是慢。并行调度没有依赖关系的任务同时执行。比如同时修改三个互不相关的模块。优点是快缺点是需要额外的合并逻辑冲突处理麻烦。条件分支调度根据验证结果决定下一步走向。验证通过就继续不通过就回退到执行 Agent 重做。这就是闭环自愈的调度基础。实际项目里这三种模式往往是混合使用的。一条主链路串行链路上某些节点内部并行每个节点后面挂一个条件分支做验证。调度逻辑写清楚整个编排才不会乱。3. 闭环自愈让 Agent 自己发现错误并兜回来3.1 自愈的本质把“验证-反馈-重试”做成自动循环闭环自愈这个词听起来很高级拆开看其实就三件事验证发现问题、反馈定位原因、重试修正错误。难点不在单次循环而在于让这个循环自动跑起来并且在合理的次数内收敛。我见过太多人把自愈理解成“让 Agent 自己改到对为止”结果就是无限重试烧了一堆 token 还是没结果。真正可用的自愈必须带收敛条件和升级机制。收敛条件是指“最多重试几次”升级机制是指“重试超过阈值后怎么办”——通常是降级到人工介入或者换一个策略重试。一个典型的自愈循环长这样执行 Agent 产出结果验证 Agent 按验收标准检查输出pass或fail加具体原因如果fail把失败原因结构化后回传给执行 Agent执行 Agent 基于失败原因做针对性修正而不是从头重写重复 2-4直到pass或达到最大重试次数3.2 失败原因的结构化自愈能不能收敛的关键自愈循环最容易失败的地方是反馈信息太模糊。如果验证 Agent 只说“代码有问题”执行 Agent 根本不知道该改哪里只能瞎猜重试几次还是错。所以失败原因必须结构化精确到文件、行号、问题类型和期望值。我用的失败反馈 schema 大致是这样{ task_id: T003, status: fail, failures: [ { file: src/parser/handler.py, line: 42, issue_type: exception_too_broad, current: except:, expected: except (ValueError, KeyError):, reason: 裸 except 会吞掉所有异常包括 KeyboardInterrupt } ], retry_hint: 只修改第 42 行的异常捕获不要动其他逻辑 }有了这种粒度的反馈执行 Agent 的修正就非常精准基本一次就能改对。retry_hint这个字段特别有用它能防止执行 Agent 在修正时“顺手”改了不该改的地方把问题扩大化。3.3 重试策略不是所有错误都值得重试这里有个经验教训不是所有失败都应该触发重试。有些失败是任务本身定义有问题重试一百次也没用有些失败是环境问题重试一次可能就好了。如果不加区分地重试就是浪费资源。我的做法是把失败分成三类分别处理失败类型典型表现处理策略可自愈失败语法错误、逻辑小 bug、格式不符自动重试最多 3 次需调整失败验收标准本身矛盾、任务依赖缺失回退到规划 Agent 重新拆解不可自愈失败环境缺依赖、权限不足、外部服务不可用直接中断报告人工这个分类逻辑要写进调度层让它在收到失败反馈时先判断类型再决定动作。判断依据可以是失败原因里的issue_type字段也可以是简单的规则匹配。注意重试次数不要设太大。我实测下来同一个任务重试超过 3 次还没过基本就是任务定义或环境有问题继续重试的边际收益极低。这时候果断中断比硬撑更省时间。4. Routine 脚本化把编排逻辑固化成可复用的资产4.1 为什么要把编排脚本化多 Agent 编排搭好之后如果每次用都要手动敲一遍角色配置、通信 schema、调度逻辑那这套东西的价值就大打折扣。编排的真正价值在于它能被固化成 Routine反复调用。所谓 Routine就是把一整套编排流程写成一个可执行的脚本或配置文件下次遇到同类任务直接调用就行。这跟做菜是一个道理。第一次做一道复杂的菜你要查菜谱、备料、一步步试做熟了之后你把它写成标准操作流程下次照着做又快又稳。Routine 就是多 Agent 编排的“标准操作流程”。4.2 Routine 的组成配置、模板与钩子一个完整的 Routine通常包含三部分配置部分定义这次编排用哪些 Agent、每个 Agent 的角色和模型参数、通信 schema 的版本。这部分是声明式的改起来方便。模板部分预置的任务拆解模板、验收标准模板、失败反馈模板。有了模板规划 Agent 的输出质量会稳定很多不会每次都不一样。钩子部分在关键节点插入的自定义逻辑比如“任务开始前拉取最新代码”“验证通过后自动提交”“失败超过阈值时发通知”。钩子让 Routine 能对接外部系统而不只是一个封闭的循环。我常用的 Routine 配置大概长这样routine_name: refactor_module version: 1.2 agents: planner: model: claude-sonnet role: task_decomposition executor: model: claude-sonnet role: code_modify verifier: model: claude-sonnet role: independent_check scheduling: mode: serial_with_retry max_retry: 3 on_exceed: escalate hooks: pre_run: git_pull_latest post_pass: auto_commit on_escalate: notify_channel这份配置读起来一目了然改起来也简单。想换个模型改一行想调整重试次数改一个数字想加个钩子加一段配置。这就是脚本化的好处——把编排逻辑从“脑子里的经验”变成“文件里的资产”。4.3 从一次性编排到 Routine 的演进路径不是所有编排一开始就值得脚本化。我的建议是分三步走第一步手动跑通一次。先用最原始的方式手动配置 Agent、手动传递消息、手动判断结果把整个流程走一遍。这一步的目的是验证流程本身是否成立别急着自动化。第二步半自动化。把重复的部分抽出来做成模板比如任务拆解的 prompt、验收标准的格式。这时候还是手动触发但每次不用从零开始。第三步完全脚本化。当流程稳定、模板成熟之后把它固化成 Routine加上钩子和调度逻辑做到一条命令跑完全程。跳过前两步直接上第三步是很多人的通病。结果就是脚本写了一堆流程本身还没跑通调试起来极其痛苦。先跑通再固化这个顺序不能反。5. 实战中的坑多 Agent 编排最容易翻车的几个地方5.1 上下文污染Agent 之间“串味”了多 Agent 编排里最隐蔽的坑是上下文污染。本来规划 Agent 和执行 Agent 应该各管各的但如果它们共享了同一份上下文执行 Agent 就会“看到”规划阶段的纠结过程然后开始怀疑任务定义甚至自作主张改需求。我遇到过一次典型的情况规划 Agent 在拆解任务时纠结了很久某个功能该不该拆成两个任务最后决定拆。这个纠结过程如果被执行 Agent 看到它执行第一个任务时就会想“这个任务是不是本来不该单独存在”然后擅自把两个任务的代码合并了导致验证失败。解决办法很简单每个 Agent 的上下文严格隔离只传递结构化的消息不传递过程性的思考。规划 Agent 的纠结过程留在它自己的上下文里对外只输出最终的任务清单。执行 Agent 只看到任务清单看不到纠结过程。5.2 验证 Agent 被“带偏”独立性怎么保证验证 Agent 的独立性说起来容易做起来难。最常见的带偏方式是验证 Agent 看到了执行 Agent 的“解释”。比如执行 Agent 在产出代码时附了一句“这里我用了 X 方案因为 Y 原因”验证 Agent 看到这个解释就容易顺着执行 Agent 的思路去检查而不是独立判断。我的做法是验证 Agent 只接收两样东西产出物本身和验收标准。执行 Agent 的任何解释、注释、说明都不传给验证 Agent。验证 Agent 要做的就是拿着验收标准一条条对着产出物核对对不上就报 fail。这样虽然有时候会“误伤”一些合理的实现但整体上保证了验证的有效性。5.3 重试放大错误越改越乱的死循环自愈循环如果设计不好会出现“越改越乱”的情况。执行 Agent 收到失败反馈后如果理解偏了可能会改错地方引入新问题下一轮验证发现新问题再反馈执行 Agent 再改又引入更新的问题……几轮下来代码面目全非。防止这种情况的关键是限制每轮修正的范围。我在失败反馈里加的retry_hint字段就是干这个的——明确告诉执行 Agent“只改这里别动其他”。另外每轮修正前执行 Agent 应该基于上一轮的产出做增量修改而不是从头重写。从头重写会让之前改对的部分也丢掉风险极大。提示如果连续两轮重试失败原因都在变化且没有收敛趋势基本可以判定是任务定义有问题应该中断并回退到规划阶段而不是继续重试。5.4 调度层的“隐形依赖”任务顺序错了全盘皆输调度层最容易出的问题是任务之间的依赖关系没理清。规划 Agent 拆任务时如果漏掉了某个隐式依赖执行时就会出现“后一个任务依赖前一个任务的产出但前一个任务还没跑”的情况。比如一个重构任务规划 Agent 拆成了“修改接口定义”和“更新调用方”两个任务但没标注后者依赖前者。调度层按并行处理结果调用方更新时接口还没改直接报错。解决办法是在规划阶段强制要求显式声明依赖。每个任务必须有depends_on字段哪怕是空数组也要写。调度层在执行前先做一次依赖检查发现循环依赖或缺失依赖就报错别等到执行时才炸。6. 从编排到落地一套可复制的搭建思路6.1 先定验收标准再拆任务很多人拆任务的顺序是反的先想“要做哪些事”再想“怎么算做完”。正确的顺序应该反过来——先定验收标准再拆任务。因为验收标准决定了任务的边界边界清晰了拆出来的任务才不会重叠或遗漏。比如要重构一个模块先定验收标准“所有原有测试通过”“圈复杂度下降 20%”“无裸 except”。有了这三条标准任务拆解就有了依据哪些改动能满足这些标准就拆成任务满足不了的就不拆。这样拆出来的任务每个都有明确的“完成定义”验证 Agent 也有据可依。6.2 小步快跑任务粒度控制在“一次能验证”任务粒度是个需要反复调的东西。太粗验证 Agent 没法判断对错太细任务数量爆炸调度开销大。我的经验值是一个任务应该小到“一次执行 一次验证”就能完成大到“不需要再拆”。具体来说如果一个任务的产出物超过 3 个文件或者验收标准超过 5 条就说明它太粗了应该再拆。如果一个任务的产出物只有一行改动验收标准只有一条那可能太细了可以合并到相邻任务。6.3 日志与可观测性出问题时能查到哪一步多 Agent 编排跑起来之后最怕的是出问题查不到原因。所以从第一天起就要把日志和可观测性做好。每个 Agent 的输入、输出、耗时、token 消耗每次验证的结果和失败原因每次重试的触发和结果都要记录下来。我用的日志格式是结构化的 JSON每条记录带task_id、agent_role、event_type、timestamp和payload。这样出问题时可以按task_id把整条链路串起来看一眼就能定位到是哪一步出的问题。{ task_id: T003, agent_role: verifier, event_type: verification_result, timestamp: 2025-01-15T10:23:45Z, payload: { status: fail, failure_count: 1, failures: [exception_too_broad] } }有了这套日志排查问题的效率会高很多。不用猜直接查。6.4 渐进式引入别一上来就全自动最后一条也是最重要的一条别一上来就追求全自动。多 Agent 编排的全自动模式在流程没跑通之前就是个灾难。我的建议是渐进式引入第一阶段人工触发每个 Agent人工传递消息人工判断结果。这个阶段的目标是验证流程逻辑。第二阶段自动传递消息自动判断结果但人工触发和监控。这个阶段的目标是验证自动化逻辑。第三阶段全自动运行人工只在异常时介入。这个阶段的目标是稳定性和效率。每个阶段跑稳了再进下一个别跳级。我见过太多人跳过前两个阶段直接上全自动结果就是一堆莫名其妙的失败查都不知道从哪查起。这套东西搭下来前期确实比单步聊天麻烦但一旦跑通后面同类任务的效率提升是数量级的。我现在处理跨模块重构这类任务基本就是调一个 Routine然后去喝杯咖啡回来验收结果。这种“把重复劳动固化成资产”的感觉才是多 Agent 编排真正的价值所在。