MultiAgent生产落地:Plan模式与主子Agent协作全解析
“单 Agent 不够用”之后我们怎么把 MultiAgent 搬进生产环境先交代一下背景。我在团队里主要负责复杂任务型 AI 应用的架构设计上半年接手了一个偏“流程编排”的项目用户给一句含糊的自然语言需求系统要自动拆解成子任务、调用多个内部服务去执行、最后汇总成一份可用的交付结果。最初用单个大模型 Agent 硬扛Prompt 写了十几版效果始终不稳定——不是漏步骤就是中间状态没人管稍微复杂一点的链路模型就开始“自由发挥”。后来我们把架构切成了典型的企业级 MultiAgent 方案顶层有一个负责“规划”的主 Agent下面挂了一批负责“执行”的子 Agent整个运行过程用 Plan 模式驱动。这套体系稳定运行到现在我才敢说踩完了该踩的坑。这不是一篇讲概念的文章重点全部放在落地细节上Plan 模式到底怎么设计、主子 Agent 之间怎么分工、哪些地方最容易翻车、以及我亲手试出来的调优方法。团队正在做 Agent 项目、或者对 MultiAgent 只停留在 Demo 阶段的朋友这篇可以直接当参考。1. 企业级 MultiAgent 落地的核心思路1.1 单 Agent 为什么撑不住复杂业务先聊一个很多人都忽略的事实单个 Agent 的能力上限往往不在模型本身而在“单线程的上下文处理方式”。你让一个 Agent 同时承担“理解需求、拆分任务、调用工具、检查结果、处理异常”这五件事它很快就陷入一种尴尬境地——模型确实能输出看起来合理的下一步动作但整个链路缺少真正的“状态控制”。我举个例子你就明白了。我们内部有个数据报表生成场景用户会这样描述“把华东区最近三个月的销售和库存按周汇总找出异常波动的品类做成 PPT 格式。”单个 Agent 收到这句话后理论上应该依次执行查销售数据查库存数据按周做聚合对比异常生成 PPT但实际运行中单 Agent 经常出现的问题是两个极端。要么它把所有步骤压缩成一次“大而全”的调用某个子任务失败就得整体重来要么它在步骤之间“自我发挥”比如查到一半觉得“库存数据可能不准”就自己决定跳过对比分析。这种不确定性在 Demo 里问题不大但在企业环境里就是事故——业务方要的是稳定、可追踪、每个环节都能复核的执行过程。这就是我们决定上 MultiAgent 架构的根本原因不是追新而是单 Agent 无法提供企业级任务执行所需要的确定性和可观测性。1.2 MultiAgent 到底解决什么问题MultiAgent 架构的核心价值说起来很简单把一个复杂的任务拆成多个有明确职责边界的子任务每个子任务由独立的 Agent 负责再通过协作机制组合成最终结果。但这里有一个非常关键的区别很多人没搞清楚——MultiAgent 不等于“多个 Agent 聊天”。如果你只是让几个 Agent 互相发消息、互相传递结果那不叫架构叫“群聊”。企业级 MultiAgent 一定要有清晰的组织关系和任务流向有一个角色负责“看全局”也就是规划者Planner/主 Agent有一批角色负责“干具体活”也就是执行者Worker/子 Agent有一层机制保证任务从“规划”到“执行”再到“验收”的闭环这套设计直接带来三个单 Agent 实现不了的好处。一是分工之后每个 Agent 的 Prompt 可以做得非常“窄”。窄 Prompt 意味着更少的歧义、更稳定的输出、更容易调试。我们的子 Agent 几乎每个都只需要关注一件事情的输入输出有的子 Agent Prompt 只有几十行比原来单 Agent 数百行的“万能 Prompt”可控得多。二是任务状态可追踪。主 Agent 规划出子任务后每个子任务在系统中的执行状态都是明确的等待中、执行中、成功、失败、重试中。这个状态是系统层面的不依赖模型“记不记得住”。三是单个环节可以独立优化。某个子 Agent 效果不好直接替换那个子 Agent 的实现不影响整体链路。这在工程上的收益是巨大的——我们的报表子 Agent 迭代了四次主 Agent 一次都没改过。1.3 什么时候应该考虑 Plan 模式多 Agent 方案不是银弹我见过不少团队一上来就奔着复杂架构去结果被自己的设计拖垮。要不要用 Plan 模式、要不要上主子 Agent 协作我建议你先用下面这个标准判断任务是否包含多个明确顺序依赖的步骤任务执行过程中是否需要动态决定下一步做什么单个 Agent 的上下文是否经常被中间过程撑爆业务方是否要求每个执行环节都可见、可查这四个问题里如果命中两个以上Plan 模式就是合适的。反过来如果任务本身只有一两步、输入输出非常固定老老实实用单个 Agent 加工具调用就好不要为了架构而架构。我们最终选择的方案是主 Agent 负责任务理解与计划生成子 Agent 负责具体执行计划和执行之间通过一个明确的任务队列衔接。整个模式属于当前工业界落地性较强的“Plan-then-Execute”路线后面我详细拆。2. Plan 模式深度拆解2.1 Plan 模式的核心机制Plan 模式英文全称通常叫 Plan-and-Execute规划-执行和另一种常见的 ReAct 模式推理-行动形成鲜明对比。ReAct 是“边想边做”模型每走一步就想一下下一步干什么Plan 模式是“先想清楚再做”模型在真正执行之前先产出一份完整的任务计划然后按计划逐步执行。打个生活的比方。ReAct 模式像一个路痴开车每到一个路口停下来看一眼导航再决定往哪走。Plan 模式像一个闭环计划的工程队先由总工勘察现场、画出施工图、列出每个施工步骤和验收标准然后交给各班组按图施工。遇到图纸之外的情况再回到总工那里修订计划。在企业场景下Plan 模式的优势非常明显减少上下文漂移。执行阶段不需要反复把完整任务描述灌输给模型只需要按计划逐项执行即可。可预期性更强。计划本身可以展示给用户或业务方确认也可以在系统里留档。支持并行和重试。计划生成后多个相互独立的子任务可以并行执行某个失败也不需要重跑整个链路。从技术实现上看Plan 模式的完整生命周期是这样的用户请求输入 ↓ 主 Agent规划器分析请求 → 生成结构化的任务计划Plan ↓ 计划校验器可选检查计划是否覆盖用户需求 ↓ 任务分发根据计划逐个/并行分发子任务给子 Agent ↓ 子 Agent 执行各自任务 → 产生结果回传 ↓ 主 Agent汇总器聚合所有子任务结果 → 生成最终回复 ↓ 中途异常 → 回到主 Agent 重新规划注意这里有个细节主 Agent 实际上承担了两个角色——规划器和汇总器。在真正的工程实现里这两个角色可以共用同一个模型实例但建议在 Prompt 层面分开成两套指令避免“既要又要”导致行为混乱。2.2 Plan 的生成与结构化表示Plan 模式最关键的一步是“计划生成”。它决定了整个任务执行的走向如果计划错了后面的执行再完美都没有用。我在实践中最开始遇到的坑是让模型自由输出计划。比如直接说“请列出完成这个任务的步骤”结果模型输出的计划五花八门——有的是一段话有的是几个词。这种非结构化输出没法被程序可靠地解析和分发。后来我们定了硬性规范计划必须以严格的 JSON 格式输出并且每个计划项包含四个字段task_id任务唯一标识用于追踪状态description这个子任务要做什么描述要足够具体depends_on前置依赖的任务 ID 列表用于决定执行顺序assignee负责执行的子 Agent 名称实际的计划输出长这样{ plan: [ { task_id: task1, description: 从数据库中按华东区、近三个月条件查询销售明细数据, depends_on: [], assignee: data_fetcher }, { task_id: task2, description: 从数据库中查询同期库存明细数据, depends_on: [], assignee: data_fetcher }, { task_id: task3, description: 将 task1 和 task2 的数据按周维度聚合计算周销售额和周库存量, depends_on: [task1, task2], assignee: data_processor }, { task_id: task4, description: 分析聚合数据找出异常波动品类并生成说明, depends_on: [task3], assignee: analyst } ] }这套结构化格式带来一个额外的好处——主 Agent 生成计划后程序可以自动做依赖检测。比如发现有任务循环依赖、或者依赖了不存在的任务 ID可以及时让主 Agent 修正而不是带着错误的计划往下跑。这在复杂任务场景里非常有必要。2.3 计划执行的动态修订机制很多人以为 Plan 模式是“一条路走到黑”实际不是。企业级落地时计划是“静态生成、动态修订”的。也就是说主 Agent 先生成一份初步计划但执行过程中如果发现某项任务结果异常必须要有“回到规划层”的机制。我们当时设计的修订流程有三类触发条件执行失败重试超过阈值。比如某个子 Agent 连续重试三次都没有成功返回数据系统判定当前计划可能有问题。执行结果校验不通过。子 Agent 返回了结果但结果缺失关键字段、格式校验失败。汇总阶段发现矛盾。主 Agent 汇总多个结果时发现两份数据之间存在明显冲突无法整合。一旦触发修订系统会把当前所有中间状态已完成的任务、失败的原因、部分结果打包传给主 Agent要求它基于最新情况输出“修订版计划”。修订版的格式和初始计划完全一致只是可能增加了新的任务、修改了某个任务的目标、或者调整了执行顺序。这里有一个我强烈建议做的设计修订时保留原始计划的任务 ID 前缀只做增量变更。比如原本是 task1 到 task4修订后新增的从 task5 开始编号已经完成的 task1 到 task3 不必重新执行。这样能极大节约成本和时间也方便做执行历史审计。3. 主子 Agent 协作机制设计3.1 主 Agent 与子 Agent 的职责边界讲完 Plan 模式接下来到主从 Agent 协作的部分。这套协作机制的设计原则其实非常简单就一句话主 Agent 做决策子 Agent 做执行两者职责严格分离。主 Agent主管/Planner的工作清单理解用户原始意图判断任务类型生成初始执行计划和修订计划把子任务分发给对应的子 Agent收集子 Agent 结果并进行汇总校验在最终回复中组织语言给用户一个可读的答案子 Agent执行者/Worker的工作清单接收一个明确的、独立的子任务在自身职责范围内调用必要的工具和数据源返回结构化结果给主 Agent在执行失败时返回错误码和错误描述这种职责分离带来的最直接好处是你不必再担心“Agent 之间的上下文污染”。主 Agent 不需要知道子 Agent 内部究竟调用了什么 API、查询了什么表、传了什么参数只需要看到子 Agent 返回的标准化结果。子 Agent 也不需要理解用户的完整需求只需要聚焦在自己那一个步骤上。3.2 主子 Agent 之间的通信协议主子 Agent 之间用什么方式通信是一个被很多人低估的设计点。我见过一些项目直接让主 Agent 把任务描述用纯文本发给子 Agent然后子 Agent 也用自由文本回复。这种方式在 Demo 阶段跑得通但进入企业级就会发现自由文本通信意味着无法可靠解析无法自动校验更无法做流程追踪。我们最后定了一套“任务单 结果单”的通信协议本质上是把任务下发和结果回传都格式化成 JSON。任务单的格式{ instruction: 查询华东区近三个月的销售明细数据, constraints: { time_range: 2026-01-01~2026-03-31, region: 华东区, fields: [date, category, sales_amount, inventory] }, output_format: json_array, deadline_seconds: 30 }结果单的格式{ status: success, data: [...], summary: 共返回 1280 条销售记录覆盖 15 个品类, error_code: null, metrics: { cost: 0.032, latency_ms: 2140 } }定义清晰的协议后任何子 Agent 的替换都变得异常轻松。我们后来把一个自研的数据查询 Agent 替换成了基于某个外部服务封装的 Agent主逻辑零改动只需要让新子 Agent 符合同一个“任务单 → 结果单”协议。3.3 任务分发和并行控制企业级场景中任务的并行执行是提升整体吞吐量的关键手段。我们最初是“串行执行计划里的每个任务”效果当然正确但效率不高——用户要等十几秒才能得到结果。后来改造成“按依赖关系做并行调度”效果立竿见影。并行控制的核心是依赖图DAG调度。主 Agent 输出计划后程序先解析depends_on字段构建依赖图然后按拓扑序执行没有依赖的任务先跑依赖完成的任务随后跑。实际执行的效果是一个包含 6 个子任务的计划如果有两个任务是独立的数据查询它们可以并行执行如果有三个任务依赖同一份数据则它们必须等前面那个数据任务完成后再并行执行。不过我要提醒一句并行执行不是越多越好。我实测下来并行度设置为 3 到 4 通常性价比最高。原因很现实并行度太高底层数据源和 API 容易被并发打满并行度太高如果某个任务失败引起重试和并行任务之间的竞争关系会更难排查成本控制上并行任务的 token 计费是叠加的需要评估性价比3.4 汇总与结果整合策略子 Agent 都执行完后主 Agent 的最后一个核心动作是“汇总”。这个环节的难度经常被低估因为多个子 Agent 返回的结果之间可能存在冲突、缺失、格式不一致等问题。我在实践中把汇总策略分成两层。第一层是程序级合并。这一步不依赖模型用代码把子 Agent 返回的结果统一合并成一个结构化的总结果集。比如所有子 Agent 返回的都是 JSON 数组程序先做数组合并、字段对齐、缺失字段填充。这样主 Agent 拿到的汇总输入是规整的而不是一堆乱七八糟的原始结果。第二层是模型级汇总。主 Agent 基于已规整的结果站在“全局视角”写一个连贯的交付文本。这一步的本质是“写作”而不是“拼装”所以 Prompt 里要强调不要重复罗列所有数据要提炼关键信息如果多个子任务结果之间存在矛盾要明确说明最终输出要覆盖用户原始需求中的每一个要点4. 实操落地过程全记录4.1 框架选型与技术栈方案聊完了设计我们来点实操的。开头先回答一个很多人问我的问题多 Agent 框架用什么市面上的主流选择有 LangGraph、AutoGen、CrewAI以及自研编排。我们的选择是基于 LangGraph 做底层编排自研上层业务逻辑。原因有三点一是 LangGraph 对“状态机”的支持做得比较成熟。它允许你定义一个图结构节点是 Agent 或工具边是状态转移条件。这和我们前面讲的“计划生成 → 任务分发 → 子 Agent 执行 → 汇总”这个流程天然匹配。二是 LangGraph 支持显式的状态持久化。每轮执行的中间状态可以保存下来计划、任务状态、执行结果都可以随时回溯。这是 LangGraph 相比 AutoGen 等框架在企业场景下最大的优势。三是上层的业务逻辑我们希望完全可控比如用户认证、权限管理、敏感信息脱敏、数据查询逻辑这些不适合写在框架层应该自研。我们的技术栈大概是这样组件选型说明编排引擎LangGraph负责 Agent 节点调度、状态管理大模型GPT-4o / 内部私有化模型两个模型轮询根据任务类型切换服务框架FastAPI提供对外 API 接口数据存储PostgreSQL RedisPostgreSQL 存执行记录Redis 存实时状态任务队列Redis Stream子任务分发和状态同步监控LangSmith Prometheus链路追踪、性能指标采集4.2 主 Agent 的 Prompt 设计实战这是整篇文章里最值得抄作业的部分。放一个我们主 Agent 的 Prompt 核心结构你可以直接改改拿去用你是一个企业级任务规划器。用户会提出一个复杂需求你需要完成以下工作 第一步理解用户需求判断是否涉及多个子任务。 第二步如果任务简单只需要一个步骤直接输出单任务计划。 第三步如果任务复杂将任务拆解成多个子任务。 输出要求 1. 严格输出 JSON 格式不允许输出任何解释文字。 2. JSON 必须包含 plan 数组数组中的每个元素包含 - task_id格式为 task1、task2、task3... - description子任务的具体描述必须包含执行所需的关键参数 - depends_on前置任务 ID 数组无依赖则为空数组 - assignee建议负责执行的子 Agent 名称 3. 子任务拆解要遵循以下原则 - 每个子任务必须有独立、可验证的交付物 - 子任务之间不能有职责重叠 - 数据获取类任务优先拆到最前 - 分析、生成类任务依赖数据任务注意一个细节我们没有让主 Agent 在同一个 Prompt 里既规划又汇总而是准备了两个独立的 Prompt——PLANNER_PROMPT和SUMMARIZER_PROMPT。在 LangGraph 里同一个模型节点根据当前阶段加载不同的 Prompt 模板。这个设计让模型的每一次调用目标都非常纯粹实测下来比一个万能 Prompt 的效果稳定很多。4.3 子 Agent 实现与工具挂载子 Agent 的实现相对简单因为它们职责单一。我以我们项目里的data_fetcher为例它的完整功能就是根据任务单里的参数查数据库返回 JSON 数组。这个子 Agent 的 Prompt 非常“窄”你是一个数据查询助手。你会收到一个 JSON 格式的任务单任务单中包含查询所需的时间范围、区域、字段列表。 请根据任务单中的参数判断需要调用哪个数据查询工具并生成工具调用的参数。 工具会返回查询结果。你需要做以下处理 1. 如果查询成功将结果整理成 JSON 数组并按任务单中的字段要求返回 2. 如果查询失败不要重试超过 2 次直接返回 status 为 failed 的结果单 3. 所有返回必须符合 result 格式为了让子 Agent 真正能干活还需要给它挂载工具。这里我们遇到过一个非常典型的坑把数据库连接字符串直接暴露给子 Agent让子 Agent 自己去生成 SQL 去查。结果非常危险——模型生成的 SQL 偶尔会漏掉WHERE条件直接把整张表查出来差点搞挂数据库。后来我们改了方案不直接暴露数据库连接而是封装成受限的查询接口例如query_sales(start_date, end_date, region)。这样模型只能传参数不能碰 SQL。这个方法强烈建议各位参考——Agent 手里的工具越受限系统越安全。4.4 状态管理与执行链路追踪企业级落地还有一个绕不开的话题状态管理。说白了就是发生问题的时候你能不能说清楚“这个任务执行到哪一步了每一步什么结果哪一步花了多少钱”我们当时落地了一套三层的状态追踪方案第一层每次请求一个全局 request_id。用户发起请求时生成整个执行链路的所有日志、状态记录都带上这个 ID。第二层任务级别的状态记录。每个子任务执行完成后往 PostgreSQL 写入一条记录包含 request_id、task_id、状态、开始时间、结束时间、token 消耗、子 Agent 名称。第三层实时缓存。执行中的状态实时写到 Redis前端页面可以通过轮询或 WebSocket 看到“正在执行哪个步骤”提升用户等待时的体验。这个三层方案的好处是既保证了执行结束后的历史可审计又保证了执行过程中的实时可视化。我们排查线上问题的时候基本都是靠 request_id 直接拉出来整条链路的日志定位效率非常高。5. 常见问题与排查技巧实录5.1 计划生成阶段的典型问题问题一主 Agent 拆解任务过多或过少现象用户需求很简单主 Agent 拆出了十几个子任务或者需求很复杂只拆出了两三个。这种情况下执行效率和结果质量都会受影响。排查思路先看主 Agent 的输出日志确认拆解数量是否异常。如果拆解过多通常是因为 Prompt 里没写“最小任务拆解原则”如果拆解过少通常是因为主 Agent 没有充分理解用户意图我们可以要求它在输出计划前先写一句“我对用户需求的理解”。问题二计划格式解析失败现象主 Agent 偶尔输出 JSON 前面带了一段解释文字或者 JSON 里混入了注释导致程序解析失败。解决方案两招第一是代码层面容错——用正则把输出里的 JSON 部分提取出来再解析第二是 Prompt 层面强调“禁止输出任何非 JSON 内容”。两招缺一不可只靠 Prompt 无法 100% 保证代码容错必须兜底。5.2 子 Agent 执行阶段的典型问题问题三子 Agent 结果与任务描述不符现象data_processor需要按周聚合数据结果返回的数据还是日维度的。排查思路这种情况往往是子 Agent 的 Prompt 对“输出格式”的描述不够具体。我们的经验是子 Agent 的 Prompt 里必须给出“输入样例”和“输出样例”不能只写抽象要求。一个具体的样例比十句抽象描述都管用。问题四执行阶段上下文爆炸现象某些子 Agent 需要处理大量数据比如一次查询返回了上万条记录导致该子 Agent 的上下文窗口被占满后续步骤质量急剧下降。排查思路这个问题非常典型。我们最后的方案是在子 Agent 前面加一个“数据预处理节点”先用代码对结果做筛选、截断、聚合只保留核心数据再交给模型分析。原则是能让代码做的事绝不让模型做。5.3 协作链路的典型问题问题五计划修订陷入循环现象修订计划执行到一半又触发修订连续四五次都搞不定看起来像一个死循环。排查思路这是最棘手的问题之一。我们在设计上加了“最大修订次数”限制默认是 2 次。超过次数后系统强制终止执行返回“当前任务过于复杂需要人工介入”的提示并附上最后的执行记录。宁可让用户知道任务失败了也不能让它无限消耗算力。问题六主子 Agent 之间信息传递丢失现象子 Agent 执行结果里有用的信息汇总阶段没有被主 Agent 采用。排查思路这类问题往往出在“结果单”的摘要字段太简略。我们后来给子 Agent 加了一个强制要求summary 字段必须包含关键数字和结论不能只写“执行成功”。比如“共返回 1280 条记录覆盖 15 个品类同比异常品类 3 个”——这种摘要越具体主 Agent 在汇总时的利用率越高。6. 写在最后的实操经验从单 Agent 改造成 MultiAgent 架构到现在个人最大的感受是这套架构真正解决的不是“模型不够聪明”的问题而是“组织不够清晰”的问题。当每个节点都只做一件事、每件事都有清晰的定义和验收标准时整个系统的确定性和可维护性会大幅提升。最后分享一个我反复验证过的小建议。刚开始搭建这套系统时我建议你不要一上来就追求“完全体”——即完整的多 Agent、并行、动态修订。先跑通一条串行的最小闭环一个主 Agent 规划两个子 Agent 执行所有任务串行。这个闭环能稳定跑通之后再引入并行调度、再引入修订机制、再增加更多的子 Agent。这是我们实际项目迭代的真实路径。先让系统“能跑”再让系统“跑得聪明”。顺序搞反了你会同时面对规划逻辑、并行控制、故障恢复、上下文管理四个维度的 bug排查起来非常痛苦。这套架构后续还有不少可以延展的方向比如引入子 Agent 的“技能注册中心”实现更灵活的任务路由、或者接入更细粒度的成本与耗时优化。但基础的地基就是文里这些朴素的道理职责分清楚、协议定标准、状态留痕迹。以上。