深入理解 AI Agent · 多 Agent 编排 #01:多 Agent 编排的四种核心模式 📅 发布时间:2026/8/28 17:39:50 👁 浏览次数: 《深入理解 AI Agent》多 Agent 编排系列 · 第1篇前篇回顾Agent 基础篇 → RAG 篇 → MCP 篇 → 记忆篇 →编排篇记忆系统解决了单个 Agent 的remembering问题但任务复杂度一旦超过单 Agent 的能力边界就需要多 Agent 协作——分工、协调、汇总。多 Agent 编排要解决的核心问题怎么让这些 Agent 按正确的顺序、正确的方式协同工作网上讲编排的文章大多是串行、并行、条件、竞争四种模式的概念罗列。但在 Dream-SaaS 落地的经验是模式本身不复杂复杂的是每种模式背后的坑。这篇直接聊问题。1. 为什么单 Agent 不够用给一个 Agent 塞 10 个工具、写 2000 字 system prompt当任务涉及搜索 → 分析 → 写报告 → 生成图表 → 排版发布这种多步骤流程时单 Agent 会碰到三个硬伤问题一Prompt 膨胀工具越多Prompt 越长模型注意力分散指令遵循能力下降。实测中当工具数从 3 个增加到 10 个时指令遵循准确率从 92% 降至 71%。问题二错误放大单 Agent 链路中一步错步步错没有回退或降级的机会。上游 Agent 输出的微小偏差会在下游被逐步放大。问题三无法并行所有步骤串行执行总延迟 各步骤延迟之和用户体验差。5 个串行步骤每步 3 秒总延迟就是 15 秒。解法是把任务拆分给多个专业 Agent每个只负责一小块通过编排层协调执行顺序和数据流。2. 四种编排模式每种模式的坑在哪四种基础模式串行、并行、条件分支、竞争。定义不展开直接聊每种模式的坑点。2.1 模式一串行SequentialAgent A → Agent B → Agent C → 结果A 的输出作为 B 的输入像流水线一样。✅优势逻辑清晰每步输入输出可追踪。⚠️坑点延迟累积如果 A 耗时 2s、B 耗时 3s、C 耗时 5s总延迟 10s。用户等不了。单点脆弱任何一个环节失败整条链路断裂。B 挂了A 和 C 的结果全部作废。错误传播A 输出一个小错误经过 B 放大到 C 已经面目全非——就像传话游戏。工程建议串行链路中每个节点都应有超时控制和输出校验。不要假设上游一定返回正确数据。Dream-SaaS 的内容生成链路中每个节点之间加了一层轻量级校验输出为空或格式异常时直接触发降级逻辑而不是让错误继续传播。实际代码思路Javapublic class SequentialPipeline { private final ListAgentNode nodes; private final Duration timeoutPerNode; public String execute(String input) { String current input; for (AgentNode node : nodes) { try { current node.execute(current) .orTimeout(timeoutPerNode.toSeconds(), TimeUnit.SECONDS) .join(); // 输出校验防止错误传播 if (current null || current.isBlank()) { log.warn(节点 {} 返回空结果触发降级, node.getName()); current node.fallback(current); } } catch (CompletionException e) { log.error(节点 {} 执行失败: {}, node.getName(), e.getMessage()); throw new PipelineException(node.getName(), e); } } return current; } }2.2 模式二并行Parallel┌→ Agent A ─┐ 输入 ─┼→ Agent B ─┼→ 合并 → 输出 └→ Agent C ─┘多个 Agent 同时执行最后合并结果。✅优势吞吐高、延迟低。⚠️坑点资源争用5 个 Agent 同时调用 LLM API触发限流反而比串行还慢。结果不一致A 说答案是 XB 说答案是 Y怎么合并简单拼接投票让 LLM 仲裁部分失败3 个 Agent 中 1 个失败了是返回 2 个的部分结果还是整体回滚真实踩坑Dream-SaaS 的多源知识检索功能最初设计 4 个 Agent 并行查询不同数据源。上线后发现并发数超过 3 时DeepSeek API 的限流导致大量 429 错误。最终方案是引入信号量控制并发数指数退避重试并在合并层做容错处理——允许部分 Agent 失败只要核心数据源成功即可。并发控制示例public class ParallelOrchestrator { private final Semaphore concurrencyLimit; private final ExecutorService executor; public ParallelResult execute(ListAgentTask tasks) { ListCompletableFutureAgentResult futures tasks.stream() .map(task - CompletableFuture.supplyAsync(() - { try { concurrencyLimit.acquire(); // 控制并发数 return executeWithRetry(task, 3); // 指数退避重试 } catch (InterruptedException e) { Thread.currentThread().interrupt(); return AgentResult.failed(e.getMessage()); } finally { concurrencyLimit.release(); } }, executor)) .toList(); // 容错合并只要核心数据源成功即可 ListAgentResult results futures.stream() .map(CompletableFuture::join) .toList(); long coreSuccess results.stream() .filter(r - r.isCoreSource() r.isSuccess()) .count(); if (coreSuccess 0) { throw new OrchestrationException(所有核心数据源均失败); } return mergeResults(results); } private AgentResult executeWithRetry(AgentTask task, int maxRetries) { for (int i 0; i maxRetries; i) { try { return task.agent().execute(task.input()); } catch (RateLimitException e) { if (i maxRetries) throw e; long backoff (long) Math.pow(2, i) * 1000; // 指数退避 sleep(backoff); } } throw new UnreachableException(); } }2.3 模式三条件分支Conditional┌→ Agent A路径 1 输入 → 路由器 ─┼→ Agent B路径 2 └→ Agent C路径 3根据条件判断路由到不同 Agent。典型场景意图识别后分发。✅优势职责分离Prompt 精准。⚠️坑点LLM 的不确定性路由器用 LLM 实现时同一个问题问两次可能路由到不同 Agent。例如用户问帮我查一下文档里的代码示例第一次路由到 RAG Agent关键词命中文档第二次可能路由到 Code Review Agent关键词命中代码。边界模糊用户的问题可能同时涉及多个分支需要设计优先级或组合路由策略。无默认路径路由条件未覆盖所有情况时请求会掉到地上。必须有兜底的 default route。工程建议路由层的设计原则是**能不调 LLM 就不调**。Dream-SaaS 的 Supervisor 设计采用三层判定策略第一层规则匹配关键词命中延迟 1ms→ 如包含代码审查直接走 Review Agent第二层启发式判断基于特征延迟 50ms→ 如检测到代码片段 长度 50 行第三层LLM 分类兜底延迟 500ms→ 只有前两层无法确定时才调用 LLM这种设计让 80% 的请求在前两层完成路由显著降低延迟和不确定性。三层路由实现public class ThreeLayerRouter { private final ListRuleMatcher rules; // 第一层 private final ListHeuristicMatcher heuristics; // 第二层 private final LLMAgent llmClassifier; // 第三层 public AgentRoute route(String input) { // 第一层规则匹配 for (RuleMatcher rule : rules) { if (rule.matches(input)) { log.debug(规则命中: {} - {}, rule.pattern(), rule.targetAgent()); return rule.targetAgent(); } } // 第二层启发式判断 for (HeuristicMatcher h : heuristics) { if (h.matches(input)) { log.debug(启发式命中: {} - {}, h.feature(), h.targetAgent()); return h.targetAgent(); } } // 第三层LLM 分类兜底 try { String classification llmClassifier.classify(input); return AgentRegistry.resolve(classification); } catch (Exception e) { // 必须有 default route不能让请求掉到地上 log.warn(LLM 分类失败使用默认路由: {}, e.getMessage()); return AgentRegistry.defaultAgent(); } } }2.4 模式四竞争Race┌→ Agent A ─┐ 输入 ─┼→ Agent B ─┼→ 取最快/最优 → 输出 └→ Agent C ─┘多个 Agent 同时执行相同任务取最快或最优的结果。✅优势低延迟、高可靠、可 A/B 测试。⚠️坑点资源浪费3 个 Agent 都在跑但只有 1 个的结果会被用到其他 2 个的算力和 API 调用费都浪费了。败者清理取到最快结果后其余 Agent 还在跑吗要不要主动取消如何取消结果质量最快的不一定是最好的。如果 Agent A 100ms 返回了一个不知道Agent B 2s 后返回了正确答案你取哪个容易被忽略的问题竞争模式中的**败者清理。Java 中用CompletableFuture.anyOf()拿到最快返回的 Future但其他 Future 还在后台执行继续占用线程和 LLM 资源。Dream-SaaS 实现了一个竞争清理器**胜者确定后遍历所有败者 Future调用cancel(true)并记录取消原因到日志方便后续分析。public class RaceOrchestrator { SuppressWarnings(unchecked) public AgentResult race(ListAgentTask tasks) { CompletableFutureAgentResult[] futures tasks.stream() .map(t - CompletableFuture.supplyAsync( () - t.agent().execute(t.input()), executor)) .toArray(CompletableFuture[]::new); try { // 取最快结果 AgentResult winner CompletableFuture.anyOf(futures).join(); // 败者清理取消所有未完成的 Future for (CompletableFutureAgentResult future : futures) { if (!future.isDone()) { boolean cancelled future.cancel(true); log.info(取消败者任务: cancelled{}, cancelled); } } // 质量校验最快的结果可能质量不够 if (!winner.meetsQualityThreshold()) { log.warn(最快结果质量不达标等待次优结果); return waitForQualityResult(futures, winner); } return winner; } catch (CompletionException e) { throw new RaceException(所有竞争任务均失败, e); } } }3. DAG 调度编排模式的集大成者实际项目中更常见的是混合编排——先条件路由再并行执行最后串行汇总。描述这种复杂拓扑的最佳方式是DAG有向无环图。┌→ Agent A ─┐ START → 路由 ─┼→ Agent B ─┼→ 合并 → Agent D → END └→ Agent C ─┘DAG 的好处是声明式你只需要定义谁依赖谁调度器自动计算执行顺序。但有几个问题值得注意3.1 静态 DAG vs 动态 DAG传统的 DAG 是编译时确定的——你画好图执行时就按这个拓扑走。但在 Agent 场景中图的结构可能需要在运行时动态决定。举个例子Agent A 分析用户需求后可能决定需要调用 Agent B 和 C也可能只需要 B甚至可能发现需要新增一个 Agent D。这种动态图生成的需求传统 DAG 调度器搞不定。主流框架的解法框架策略特点LangGraph有状态的有向图允许循环节点可根据状态动态决定下一节点条件边甚至回退。代价是需要处理无限循环——必须设置最大步数或收敛检测Spring AI Alibaba StateGraphDAG 条件边保留 DAG 结构约束但通过条件边Conditional Edge支持运行时动态路由。静态拓扑 动态路由的折中约束更强但可预测性更好LangGraph 的循环机制from langgraph.graph import StateGraph, END workflow StateGraph(AgentState) workflow.add_node(analyze, analyze_node) workflow.add_node(execute, execute_node) workflow.add_node(review, review_node) # 条件边review 节点可以回退到 execute workflow.add_conditional_edges( review, lambda state: execute if state[needs_revision] else END ) # 必须设置最大步数防止无限循环 app workflow.compile() result app.invoke(input, config{recursion_limit: 10})Spring AI Alibaba StateGraph 的条件边StateGraph graph new StateGraph(supervisor, stateFactory) .addNode(intent, intentRouterNode) .addNode(rag, ragAgentNode) .addNode(code_review, codeReviewNode) // 条件边根据运行时状态动态路由 .addConditionalEdges(intent, state - { String intent state.get(intent); return switch (intent) { case knowledge - rag; case code - code_review; default - rag; // 默认路由 }; }) .addEdge(rag, END) .addEdge(code_review, END);两者的核心区别LangGraph 允许review → execute → review这种循环本质是有向图而 StateGraph 要求拓扑无环只能通过条件边在同一层的不同节点之间做选择。前者表达力更强后者更容易推理和调试。3.2 状态传递DAG 中节点之间的状态传递有两种方式方式说明适用场景显式传递节点输出作为下一个节点的输入参数串行链路、简单 DAG共享状态所有节点读写同一个全局状态对象复杂 DAG、需要跨分支共享数据显式传递更安全但不够灵活共享状态更灵活但容易出竞态条件——两个并行节点同时修改同一个状态字段结果不可预测。3.3 竞态条件及解法当并行分支共享同一个状态对象时两个节点可能同时读写同一字段导致数据不一致。三种常见解法方案原理优点缺点不可变状态每次更新返回新对象不修改原对象Redux reducer 模式天然线程安全内存开销大状态对象多时 GC 压力上升细粒度锁对状态字段加ReentrantLock或synchronized简单直接可能成为性能瓶颈死锁风险原子更新AtomicReferenceMap或ConcurrentHashMap原子操作性能好实现复杂复合操作需要 CAS 循环Dream-SaaS 的方案是共享状态 增量更新 键隔离// 每个节点返回状态增量而非修改全局状态 public MapString, Object execute(MapString, Object sharedState) { MapString, Object delta new HashMap(); delta.put(analysisResult, performAnalysis(sharedState.get(input))); delta.put(confidence, 0.95); return delta; // 框架负责合并 } // 并行分支的约束只写各自隔离的状态键 // Agent A 只写 rag_result 键 // Agent B 只写 code_result 键 // 合并阶段由汇总节点统一处理避免并行写入冲突Spring AI Alibaba 的 StateGraph 采用的就是这种模式每个节点返回一个MapString, Object作为状态增量框架负责合并到全局状态。Dream-SaaS 在此基础上增加了约束并行分支只写各自隔离的状态键从设计上杜绝了竞态条件的发生。4. 选型决策框架面对具体任务怎么选编排模式下面是一个从实际项目中总结的决策框架第一步任务可拆分吗 ├─ 不可拆分 → 单 Agent不需要编排 └─ 可拆分 → 进入第二步 第二步子任务之间有依赖吗 ├─ 无依赖 → 并行模式 └─ 有依赖 → 进入第三步 第三步依赖是线性的还是分支的 ├─ 线性A → B → C→ 串行模式 └─ 分支A 的输出决定走 B 还是 C→ 条件分支模式 第四步需要冗余或低延迟吗 ├─ 需要如多模型择优、容灾→ 竞争模式 └─ 不需要 → 用前面的组合即可核心逻辑从简单到复杂能用简单模式就不上复杂模式。编排越复杂调试越困难故障点越多。反模式警告不要为了架构感而过度编排。见过有项目把简单的检索 → 生成流程搞成 5 个 Agent 的 DAG每个 Agent 都要调 LLM总延迟从 3s 变成 12s用户直接流失。编排是为了解决问题不是炫技。5. 总结模式适用场景主要风险缓解措施串行线性流程步骤间有强依赖延迟累积、错误传播超时控制 输出校验 降级逻辑并行无依赖的独立子任务资源争用、结果不一致信号量限流 容错合并条件分支意图路由、任务分发LLM 不确定性、边界模糊三层路由规则→启发式→LLM竞争低延迟要求、多模型择优资源浪费、败者未清理竞争清理器 质量阈值DAG 混合复杂多步骤任务动态图、竞态条件条件边 键隔离 增量状态关键结论编排模式没有银弹每种都有适用场景和对应的坑LLM 的不确定性会沿着编排链路传染路由层、判断层都需要兜底机制动态 DAG 的表达力强但实现复杂度不容小觑从简单到复杂编排是手段不是目的下篇预告《深入理解 AI Agent六Agent 之间怎么说话——通信、状态与冲突解决》深入理解 AI Agent · 编排篇上作者宋哥 | Java 后端 → AI Agent 工程师项目Dream-SaaS · 多 Agent 协作平台有问题评论区见欢迎交流~