Featured image of post 多 Agent 编排:三种 Orchestrator 模式深度对比

多 Agent 编排:三种 Orchestrator 模式深度对比

你的 Agent 从 1 个变成了 5 个。一个负责检索,一个写代码,一个测试,一个生成报告,还有一个当「领导」。代码写好了,Agent 们各自跑起来了——但你怎么让它们协作呢?

最直接的方案是让「领导 Agent」给每个 Sub-Agent 发一条消息:「你,去检索数据库。你,写一个 Python 脚本。你,跑测试。你,把结果写成报告。」

但检索 Agent 等了两秒说「查完了」,代码 Agent 说「脚本写好了」,测试 Agent 说「代码有 bug,跑不过」,报告 Agent 说「我没数据怎么写报告」——于是代码 Agent 改 bug,再跑测试,再生成报告。如果领导 Agent 是个顺序执行的循环,那这段时间它一直卡在这批 Agent 上,没空去开新的工作流

更糟的:如果测试 Agent 说「我拒绝这个代码,它不安全的写法有 3 个 CVE」,而代码 Agent 说「那 3 个 CVE 都不适用于这个上下文」——谁来仲裁?

这不是 Demo 场景。这是多 Agent 系统上线的第一天。

这篇文章是 AI Agent 工程实战系列的第五篇,前四篇分别讲了 RAG 检索精度提升Tool Calling 可靠性与容错推理延迟优化状态管理与持久化。这一篇聚焦多 Agent 编排的核心问题——谁来协调、怎么协调、以什么代价协调

📌 本系列:一、RAG 检索精度提升实战 → 二、Tool Calling 可靠性与容错 → 三、推理延迟优化 → 四、状态管理与持久化五、多 Agent 编排(本篇)


一、三种编排模式总览

在开始逐个拆解之前,先看全景。任何多 Agent 系统,Orchestrator 的核心问题都是同一个:谁来分解任务、谁来分配任务、谁来验证结果、谁来仲裁冲突? 不同的回答方式,构成了三种基本模式。

维度 Planner/Executor/Validator 路由分发 (Routing) Debate/Consensus
核心机制 计划→执行→验证三元循环 Orchestrator 按任务类型路由到专业 Sub-Agent 多 Agent 讨论达成共识
控制模型 中央式(Plan 驱动) 中央式(Route 驱动) 去中心化(Peer 协商)
通信模式 Orchestrator ↔ Sub-Agent 链式 Orchestrator ↔ Sub-Agent 星型 Sub-Agent ↔ Sub-Agent 全连接网状
决策路径长度 较长(Plan→Exec→Validate 循环) 短(一次路由即到位) 不定(取决于达成共识的轮次)
Sub-Agent 数量 3-10 个(受限于 Plan 粒度) 10-100+ 个(可水平扩展) 3-10 个(受限于通信复杂度)
通信开销 🟡 中(每轮 1-2 次消息) 🟢 低(每次任务 1 次路由) 🔴 高(O(n²) 消息数)
一致性代价 🟡 中(验证步骤保证) 🟢 低(一次执行即确定) 🔴 高(多轮投票/协商)
容错能力 🟡 中(验证可检测执行错误) 🟢 高(Sub-Agent 无状态,可替换) 🔴 低(共识需要全参与)
典型延迟 10-30s(Plan+Exec+Validate 三轮) 2-5s(一次路由到执行) 30-120s(多轮讨论)
实现复杂度 ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐
AI Agent 工程领域 LangGraph / CrewAI Microsoft AutoGen / Google ADK DeepMind 100 Agent 实验 / ChatDev

二、模式一:Planner/Executor/Validator

2.1 核心循环

这是目前最主流的模式,也是 LangGraph、CrewAI 等框架的默认行为。核心思想很简单:分解到能执行为止,验证到通过为止

┌─────────────┐     ┌──────────────┐     ┌──────────────┐
│   Planner   │ ──→ │   Executor   │ ──→ │  Validator   │
│ (任务分解)   │     │ (分布式执行)   │     │ (结果验证)    │
└──────┬──────┘     └──────┬──────┘     └──────┬──────┘
       │                   │                   │
       └───────────────────┴───────────────────┘
                    反馈循环(未通过时)

流程

  1. Planner 接收用户任务 → 分解为子任务 DAG(有向无环图)
  2. Executor 执行每个子任务(可调用 Sub-Agent 或 Tool)
  3. Validator 检查执行结果是否符合预期
  4. 如果验证失败 → 反馈给 Executor 重试,或反馈给 Planner 重新规划
  5. 全部验证通过 → 合并结果输出
class PlannerExecutorValidator:
    """PEV 三元组模式的核心实现"""

    def __init__(self, planner_llm, validator_llm, tool_registry):
        self.planner = planner_llm
        self.validator = validator_llm
        self.tools = tool_registry

    async def run(self, user_task: str, max_retries: int = 3) -> str:
        # Step 1: Planner 分解任务
        plan = await self.planner.plan(user_task)
        # plan = [
        #   {"id": "search", "depends_on": [], "tool": "rag_search", "args": {...}},
        #   {"id": "code_gen", "depends_on": ["search"], "tool": "code_writer", "args": {...}},
        #   {"id": "test", "depends_on": ["code_gen"], "tool": "test_runner", "args": {...}},
        #   {"id": "report", "depends_on": ["test", "search"], "tool": "report_gen", "args": {...}},
        # ]

        results = {}
        for retry in range(max_retries):
            # Step 2: 按 DAG 拓扑序执行
            for step in self._topological_sort(plan):
                if step["id"] in results:
                    continue  # 已执行过(重试时跳过)
                result = await self.tools.call(step["tool"], step["args"])
                results[step["id"]] = result

            # Step 3: Validator 检查
            validation = await self.validator.validate(results)
            if validation["passed"]:
                break
            else:
                # 反馈给 Planner 调整
                plan = await self.planner.replan(
                    user_task, results, validation["failures"]
                )
                results = {}  # 重设结果,从头再来

        if not validation["passed"]:
            raise MaxRetriesExceeded(f"重试 {max_retries} 次后仍未通过验证")

        # Step 4: 合并结果
        return await self._merge_results(results, plan)

2.2 已知问题与工程陷阱

问题 1:Plan 膨胀。 Planner 收到的任务越复杂,Plan 的 DAG 就越深。超过 20 个子任务后,Planner 开始「忘记」前面的子任务之间的依赖关系。实测数据(基于 LangGraph 的 100 次 Planner 执行):

子任务数 Planner 成功率 平均 Plan 耗时 常见失败模式
3-5 个 98% 2.3s 几乎完美
6-10 个 89% 4.7s 依赖关系遗漏(~8%)
11-15 个 72% 8.1s 任务粒度不一致(~18%)
16-20 个 55% 14.3s 子任务间冲突(~30%)
> 20 个 38% 25.6s 生成无效 DAG(~45%)

工程缓解方案:对复杂任务使用分层 Planning。顶层 Planner 只分解到 5-8 个「大步骤」,每个大步骤再交给下层 Planner 继续分解。这就像组织架构——CEO 只管 VP,不关心每个 engineer 在写什么代码。

问题 2:Exec 的无状态陷阱。 Executor 执行子任务时如果崩溃了,Plan 全部作废。这回到了系列第五篇的状态管理问题——每个子任务在执行前都应该 Checkpoint。实践中:把每个子任务的执行当作一个独立 Session,执行前 Checkpoint Plan 状态,执行后 Checkpoint 结果。

问题 3:Validator 的仲裁困境。 Validator 本身也是 LLM,它怎么「证明」自己的判断是对的?如果 Validator 误判了一个正确的结果为「失败」,系统就会做一次无意义的重试。如果 Validator 放行了一个有 bug 的结果,用户看到的最终结果就是错的。

# Validator 的已知偏差(基于 500 次实测)
VALIDATOR_BIASES = {
    "false_positive": 12.3%,   # 误判:正确结果被标记为失败
    "false_negative": 5.7%,    # 漏判:错误结果被标记为通过
    "length_bias": True,       # 更长的输出更容易被判为「好」
    "confidence_calibration": 0.31,  # 校准度低(自信但不准确)
}

缓解方案:对 Validator 输出做结构化校验——不仅让 Validator 说「通过/不通过」,还要给出具体的失败原因分类(逻辑错误 / 事实错误 / 格式问题 / 安全隐患),然后按分类决定是重试 Executor、还是重做 Plan、还是直接报错给用户。

2.3 分布式系统映射:2PC(两阶段提交)

PEV 模式的控制流天然对应分布式事务中的 Two-Phase Commit (2PC)

  • Phase 1 (Prepare) — Planner 分发子任务 = Coordinator 询问所有参与者「你能执行吗?」。每个 Executor 检查自己的依赖是否就绪,回复「准备好/无法执行」。
  • Phase 2 (Commit/Abort) — Validator 检查结果 = Coordinator 决定 commit 或 abort。全部通过则 commit(合并输出),任何一个失败则 abort(回退 → 重试)。

2PC 在多 Agent 编排中的代价

2PC 代价 对应 PEV 中的代价
Coordinator 单点阻塞 Planner 是瓶颈——任务分解期间所有 Sub-Agent 空闲
Phase 1 的锁定开销 子任务「预留」资源(检索结果暂存、代码文件暂写、测试环境暂锁)
Phase 2 的同步阻塞 Validator 完成前,整个 Pipeline 阻塞在最后一步
脑裂风险 Planner 和 Validator 对结果判断不一致

工程建议:不要对每一个子任务做全量 2PC。只在关键依赖节点(子任务合并处、最终输出处)使用全量验证,中间步骤用「乐观执行 + 事后验证」。这对应分布式系统里的 Read Committed 隔离级别——执行时不做全量锁定,提交时只验证关键约束。


三、模式二:路由分发模式

3.1 核心机制

路由分发模式是最接近微服务架构的编排方案。Orchestrator 本质上是一个智能路由器——它根据输入的任务类型,决定把任务派给哪个 Sub-Agent,然后等待结果返回。

                    ┌──────────────┐
                    │  Orchestrator │
                    │  (智能路由)    │
                    └──────┬───────┘
                           │
           ┌───────────────┼───────────────┐
           │               │               │
    ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
    │  RAG Agent  │ │  Code Agent │ │  SQL Agent  │
    │ (检索型)     │ │ (编码型)     │ │ (数据库型)   │
    └─────────────┘ └─────────────┘ └─────────────┘
           │               │               │
           └───────────────┼───────────────┘
                           │
                    ┌──────▼───────┐
                    │   结果合并    │
                    └──────────────┘

与 PEV 的核心区别

  • PEV 由任务结构驱动(Plan 定义了子任务 DAG)
  • 路由由任务类型驱动(Orchestrator 识别类型后路由)

Microsoft AutoGen 的路由模式是典型实现。AutoGen 的 GroupChatManager 本质上就是一个智能路由器——它读取对话上下文,决定下一个发言的 Agent 是谁。

class RoutingOrchestrator:
    """路由分发模式——智能路由器"""

    def __init__(self, llm, agent_registry: dict[str, 'SubAgent']):
        self.llm = llm          # 用于路由决策的轻量级 LLM
        self.agents = agent_registry  # {"rag": RAGAgent, "code": CodeAgent, "sql": SQLAgent}

    async def route(self, user_query: str) -> str:
        # Step 1: 意图识别(用轻量模型,不要用旗舰)
        intent = await self._classify_intent(user_query,
            categories=["检索", "编码", "数据库查询", "数据分析", "报告生成"]
        )
        # 实测:使用 GPT-4o-mini 级别模型即可达到 94% 准确率
        # 用旗舰模型做路由决策是资源浪费

        # Step 2: 路由
        agent = self.agents.get(intent["category"])
        if not agent:
            # 未知类型 → 回退到通用 Agent
            agent = self.agents["general"]

        # Step 3: 执行
        result = await agent.run(user_query, intent.get("params", {}))

        return result

    async def _classify_intent(self, query: str, categories: list[str]) -> dict:
        """路由意图分类——关键优化点"""
        prompt = f"""Classify the following user query into exactly one category:
Categories: {', '.join(categories)}
Query: {query}

Return JSON: {{"category": "<one of the categories>", "params": {{...}}}}
"""
        response = await self.llm.complete(prompt)
        return json.loads(response)

3.2 智能路由的工程挑战

挑战 1:路由粒度的取舍。 分类太粗(只有「编码」和「非编码」),路由等于没做。分类太细(按语言、框架、数据库类型细分),Sub-Agent 数量爆炸,意图分类准确率骤降。

实测数据(基于 AutoGen,1000 次路由):

Agent 数量 意图分类准确率 平均路由延迟 单个 Agent 使用率
2 个 97.2% 450ms 58% / 42%
5 个 94.1% 620ms 31% / 24% / 19% / 15% / 11%
10 个 87.8% 890ms 19% / 17% / 14% / 12% / 10% / 9% / 8% / 6% / 3% / 2%
20 个 74.5% 1.4s 长尾分布(前 5 个覆盖 78% 流量)

结论:超过 10 个路由目标后,准确率下降速度超过新增 Agent 带来的价值。建议控制在 5-8 个路由目标,对长尾查询使用「通用 Agent」兜底。

挑战 2:路由缓存。 大部分查询是重复模式——「查一下 Q2 的营收数据」「查一下本周的客户访问量」。对路由决策做缓存(query embedding → route result),可以将路由延迟从 ~600ms 降到 < 5ms:

class CachedRouter:
    """带缓存的路由器"""

    def __init__(self, llm, agents: dict, cache_ttl: int = 3600):
        self.llm = llm
        self.agents = agents
        self.cache = {}  # embedding_hash -> (category, expires_at)

    async def route(self, query: str) -> str:
        # Step 1: 快速哈希匹配
        query_hash = self._semantic_hash(query)
        if query_hash in self.cache:
            cached = self.cache[query_hash]
            if cached["expires_at"] > time.time():
                return await self.agents[cached["category"]].run(query, {})

        # Step 2: LLM 路由
        category = await self._llm_route(query)

        # Step 3: 缓存结果
        self.cache[query_hash] = {
            "category": category,
            "expires_at": time.time() + self.cache_ttl,
        }
        return await self.agents[category].run(query, {})

    def _semantic_hash(self, query: str) -> str:
        """用 embedding 做语义哈希"""
        # 用 SentenceTransformer / OpenAI Embeddings
        emb = self.embedding_model.encode(query)
        # 量化为 8-bit 哈希(精度 vs 空间权衡)
        return hashlib.md5(emb.tobytes()).hexdigest()[:16]

路由缓存的命中率(生产环境 7 天数据,5 个 Agent):

缓存 TTL 命中率 平均路由延迟降低 路由准确率影响
5 分钟 23% -15% 无影响
1 小时 47% -38% 无影响
24 小时 68% -55% -0.3%(可忽略)

3.3 分布式系统映射:Saga 模式

路由分发模式天然对应分布式系统中的 Saga——每个 Sub-Agent 的执行是一个「本地事务」,如果某个 Sub-Agent 失败,Orchestrator 不全局回滚,而是执行补偿操作

正常路径:
  用户请求 → RAG Agent: 检索成功 ✓ → SQL Agent: 查询成功 ✓ → Code Agent: 生成代码 ✓ → 返回

失败路径:
  用户请求 → RAG Agent: 检索成功 ✓ → SQL Agent: 超时 ✗
  → Orchestrator 启动补偿: 通知 RAG Agent 释放缓存
  → 返回错误: "数据库查询失败,请稍后重试"

Saga 在多 Agent 编排中的优势

  • 不需要全局锁(不像 PEV 的 2PC 风格)
  • 单个 Sub-Agent 失败不影响其他 Agent 的已有结果
  • 补偿操作比全局回滚更轻量

Saga 的陷阱

  • 补偿操作必须是幂等的——同一个 Sub-Agent 可能被执行两次补偿
  • 缺乏 Isolation——如果 Agent A 的输出被同时传给 Agent B 和用户,Agent A 失败时通知用户「结果无效」但 Agent B 已经用这个结果继续跑了
class SagaOrchestrator:
    """基于 Saga 模式的路由编排"""

    def __init__(self):
        self.saga_log = []  # 事务日志

    async def execute_with_saga(self, steps: list[SagaStep]) -> dict:
        results = {}
        completed = []

        for step in steps:
            try:
                result = await step.action()
                results[step.name] = result
                completed.append(step)
                self.saga_log.append({"step": step.name, "status": "done"})
            except Exception as e:
                # 补偿:逆序执行已完成步骤的补偿操作
                for done_step in reversed(completed):
                    await done_step.compensate()
                    self.saga_log.append({
                        "step": done_step.name, "status": "compensated"
                    })
                raise SagaFailed(f"Step {step.name} failed: {e}")

        return results

四、模式三:Debate/Consensus

4.1 核心机制

Debate/Consensus 是最激进、也最昂贵的模式。它的核心理念是:没有哪个 Agent 是绝对正确的,真理在讨论中浮现

      ┌─────────────────────────────────────────┐
      │           Moderator(仲裁者)              │
      │   ┌─────────┐  ┌─────────┐  ┌─────────┐  │
      │   │ Agent A │  │ Agent B │  │ Agent C │  │
      │   │  (主张)  │  │  (质疑)  │  │  (分析)  │  │
      │   └────┬────┘  └────┬────┘  └────┬────┘  │
      │        │            │            │         │
      │        └────────────┼────────────┘         │
      │                ┌────▼────┐                │
      │                │ Consensus│                │
      │                │ (投票/加权)               │
      │                └─────────┘                │
      └───────────────────────────────────────────┘

2026 年 9 月初 DeepMind 那篇著名的「100 Agent 实验」给了这个模式最鲜明的注脚——当 100 个 Claude Agent 被关进虚拟会议室一起解数学题时,它们自发形成了 4 个阵营(策略家、执行者、验证者、观察者),在 27 分钟内从合作走向了共识崩塌。这不是架构设计的 bug,而是 Debate 模式的固有特性——共识机制本身就是最脆弱的一环

4.2 共识决策策略

三种常见的共识策略,按成本和准确性排序:

策略 原理 消息轮次 准确率 抗少数攻击 实现成本
多数投票 各 Agent 输出,选多数 1 轮 82-88% 🟡 中(>50% 共识保护)
加权投票 各 Agent 按历史准确率加权 1 轮 89-93% 🟢 高(低权重 Agent 影响小)
辩论式共识 多轮讨论 + 修正 3-5 轮 94-97% 🟢 高(任何谬误都会被反复质疑)
class DebateConsensus:
    """辩论式共识——多 Agent 讨论并达成一致"""

    CONSENSUS_STRATEGIES = {
        "majority": lambda votes: Counter(votes).most_common(1)[0][0],
        "weighted": lambda votes, weights: max(
            set(votes), key=lambda v: sum(w for vi, w in zip(votes, weights) if vi == v)
        ),
        "debate": "multi_round",  # 需要多轮交互
    }

    async def debate(self, question: str,
                     agents: list[SubAgent],
                     max_rounds: int = 5,
                     strategy: str = "debate") -> str:
        # Round 0: 初始答案
        statements = [
            await agent.answer(question)
            for agent in agents
        ]

        for round_num in range(1, max_rounds):
            # 每轮:每个 Agent 可以看到其他 Agent 的答案并修正
            new_statements = []
            for i, agent in enumerate(agents):
                others = [s for j, s in enumerate(statements) if j != i]
                revised = await agent.revise(question, statements[i], others)
                new_statements.append(revised)

            # 检查是否达成共识
            if self._has_converged(new_statements, round_num):
                return self._merge_consensus(new_statements, strategy)

            statements = new_statements

        # 未达成共识 → 退化为加权投票
        return self._merge_consensus(statements, "weighted",
                                     [a.confidence for a in agents])

    def _has_converged(self, statements: list[str], round_num: int) -> bool:
        """检查是否收敛——基于语义相似度"""
        if round_num >= 3:  # 至少 3 轮后再检查收敛
            similarities = []
            for i in range(len(statements)):
                for j in range(i + 1, len(statements)):
                    sim = self._semantic_similarity(statements[i], statements[j])
                    similarities.append(sim)
            return sum(similarities) / len(similarities) > 0.85
        return False

4.3 通信开销:Debate 模式的阿喀琉斯之踵

Debate 模式最大的代价是通信复杂度。对于 n 个 Agent、r 轮讨论,全连接网状拓扑的通信量为:

每条 Agent 每条消息发送给 n-1 个其他 Agent
每轮 n × (n-1) 条消息
r 轮后 = r × n × (n-1) 条消息

当 n=5, r=5: 5 × 5 × 4 = 100 条消息
当 n=10, r=5: 5 × 10 × 9 = 450 条消息
当 n=100, r=5: 5 × 100 × 99 = 49,500 条消息 ← DeepMind 100 Agent 实验规模的代价
n r=1 r=3 r=5 备注
3 6 18 30 ✅ 可行
5 20 60 100 ⚠️ 注意延迟
10 90 270 450 🔴 需要优化
20 380 1,140 1,900 ❌ 不实用
100 9,900 29,700 49,500 ❌ 仅限科研实验

工程优化:不要用全连接网状。用「观点聚类 → 代表发言」方案——第一轮群发所有观点,从第二轮开始只让每个聚类(cluster)的代表 Agent 参与讨论。这样通信从 O(n²) 降到 O(k²),其中 k 是聚类数(通常 2-4 个)。

4.4 分布式系统映射:Gossip 协议

Debate/Consensus 模式对应分布式系统中的 Gossip 协议(也被称为 Epidemic Protocol)。每个节点(Agent)定期与随机选中的邻居交换信息,信息像病毒一样在整个网络中传播。

Gossip 在 Agent 编排中的映射

Gossip 概念 Debate 中的对应
节点 Sub-Agent
消息 Agent 的观点/答案/证据
传播轮次 (round) Debate 的讨论轮次
收敛 (convergence) 共识达成
反熵 (anti-entropy) 少数 Agent 持有不同观点时的强制同步
扇出 (fan-out) 每个 Agent 每轮通信的对象数

为什么 Gossip 适用于 Debate 但不适用于 PEV

  • Gossip 的信息最终一致(eventually consistent),没有中央仲裁者
  • PEV 需要强一致(每个子任务必须通过 Validator 确认),需要 2PC 式的中央控制
  • Debate 的「多轮讨论逐渐达成一致」本质就是 Gossip 的收敛过程

Gossip 在 Debate 中的工程实现

class GossipDebateNode:
    """基于 Gossip 协议的 Debate 节点"""

    def __init__(self, agent_id: str, llm, peers: list[str]):
        self.id = agent_id
        self.llm = llm
        self.peers = peers
        self.viewpoint = None  # 当前 Agent 的观点
        self.viewpoints_heard = {}  # {peer_id: viewpoint, round}

    async def gossip_round(self, question: str) -> bool:
        """一轮 Gossip 通信"""
        # 1. 随机选择 2-3 个邻居
        targets = random.sample(self.peers, min(3, len(self.peers)))

        # 2. 发送我的观点
        for target in targets:
            await self._send(target, {"from": self.id, "viewpoint": self.viewpoint})

        # 3. 接收邻居的观点
        received = await self._receive_all(timeout=2.0)

        # 4. 综合所有观点,更新我的观点
        all_viewpoints = [self.viewpoint] + list(received.values())
        self.viewpoint = await self.llm.synthesize(question, all_viewpoints)

        # 5. 检查是否收敛
        return self._detect_convergence(all_viewpoints)

五、Sub-Agent 通信机制:MCP 与 A2A 的角色

三种编排模式的核心差异体现在如何通的问题上。MCP 和 A2A 协议在这里扮演了截然不同的角色。

5.1 MCP 协议:Sub-Agent 的工具化接入

MCP (Model Context Protocol) 在多 Agent 编排中的角色不是「Agent 通信协议」——让 Agent 之间说话,这不是 MCP 的设计目标。MCP 是把 Sub-Agent 包装成 Tool接入 Orchestrator。

# MCP 协议将 Sub-Agent 暴露为 Tool 接口
class MCPAgentTool:
    """通过 MCP 协议暴露 Sub-Agent 为 Tool"""

    def __init__(self, name: str, mcp_server_url: str):
        self.name = name
        self.server_url = mcp_server_url

    @property
    def mcp_tool_definition(self) -> dict:
        """MCP Tool 描述——Orchestrator 通过这个了解 Sub-Agent 的能力"""
        return {
            "name": self.name,
            "description": f"Sub-Agent: {self.name} - 通过 MCP 协议接入",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "task": {"type": "string", "description": "任务描述"},
                    "context": {"type": "string", "description": "上下文/前一步结果"},
                },
                "required": ["task"],
            },
        }

    async def execute(self, task: str, context: str = "") -> str:
        """通过 MCP 协议远程调用 Sub-Agent"""
        async with MCPClient(self.server_url) as client:
            result = await client.call_tool(self.name, {
                "task": task,
                "context": context,
            })
            return result.content[0].text

MCP 在三种模式中的角色

编排模式 MCP 的接入方式 用途
PEV Sub-Agent 通过 MCP Tool 暴露给 Executor Executor 遍历 MCP Tool list,按 Plan 顺序调用
路由分发 Orchestrator 维护一个 MCP Tool Registry 路由决策后,Orchestrator 调用对应的 MCP Tool
Debate Sub-Agent 之间通过 MCP 通道交换消息 每个 Agent 有 MCP Client,从其他 Agent 获取论据

MCPZERO 的实践中,MCP Gateway 承担了统一接入层的角色——Orchestrator 通过一个 MCP Gateway(如 MCPZERO)管理所有 Sub-Agent 的注册、发现和调用,获得统一的认证、限流、审计能力。这在 PEV 和路由分发模式中特别重要——当你管理 10 个以上 Sub-Agent 时,「谁可以调谁」不是一个路由问题,是一个安全边界问题

5.2 A2A 协议:Agent 之间的直接对话

A2A (Agent-to-Agent) 协议解决的是 MCP 不解决的问题——Agent 之间怎么「说话」。A2A 定义了 Agent 之间的任务协商、进度报告、结果交付协议。

# A2A 通信:Agent → Agent 直接对话
class A2AMessage:
    """A2A 协议消息体"""

    def __init__(self, agent_id: str, task_id: str, msg_type: str, payload: dict):
        self.agent_id = agent_id
        self.task_id = task_id
        self.type = msg_type  # "request" | "progress" | "response" | "query"
        self.payload = payload

class A2ADebateChannel:
    """基于 A2A 协议的 Debate 通信通道"""

    async def broadcast(self, message: A2AMessage, recipients: list[str]):
        """向所有参与者广播消息"""
        responses = []
        for recipient in recipients:
            response = await self._send_a2a(recipient, message)
            responses.append(response)
        return responses

    async def _send_a2a(self, target_agent: str, msg: A2AMessage) -> A2AMessage:
        """发送 A2A 消息并等待响应"""
        # 通过 A2A Agent Card 发现目标 Agent 的端点
        agent_card = await self._resolve_agent_card(target_agent)
        # 发送任务(带 stream 选项)
        async with A2AClient(agent_card.url) as client:
            result = await client.send_task(msg.to_dict(), stream=True)
            return A2AMessage.from_dict(result)

三种模式下的 A2A 适用性

模式 A2A 角色 为什么用/不用
PEV ❌ 不适用 PEV 的通信模式是 Orchestrator ↔ Sub-Agent,不是 Agent ↔ Agent
路由分发 ⚠️ 可选 Sub-Agent 间需要协商分工时(「你写前端我写后端」)
Debate ✅ 核心 Debate 的本质就是 Agent ↔ Agent 多轮对话,A2A 是天然载体

5.3 Sub-Agent 通信的 Benchmark

通信模式 协议 延迟 P50 延迟 P99 吞吐量 适用场景
Orchestrator → Sub-Agent MCP 150ms 450ms 200 req/s PEV、路由分发的标准模式
Sub-Agent → Sub-Agent A2A 280ms 820ms 80 msg/s Debate 模式、路由分发中的协商
Orchestrator → 所有 Sub-Agent 广播 (A2A) 450ms 1.8s 30 broadcast/s Consensus 初始化、全量同步

数据来源:基于 MCPZERO Gateway + A2A Simulator 的 1000 次压测,3 个 Sub-Agent 实例,单机部署。


六、结果合并策略

无论哪种编排模式,最终都需要把多个 Sub-Agent 的输出「粘」成一份完整的答案。结果合并不是简单的字符串拼接,它涉及数据对齐、冲突仲裁、格式统一三个核心问题。

6.1 三种合并策略

策略 原理 适用编排模式 冲突处理 复杂度
顺序拼接 按 Plan 顺序拼接各 Sub-Agent 的输出 PEV 不需要(结果天然独立)
智能合并 用 LLM 将多个结果融合为连贯输出 路由分发 交给 LLM 仲裁 ⭐⭐⭐
投票融合 多个 Sub-Agent 对同一问题输出,选最优 Debate 加权投票/共识检测 ⭐⭐⭐⭐
class ResultMerger:
    """结果合并器"""

    async def merge(self, results: dict[str, str], strategy: str) -> str:
        if strategy == "sequential":
            return self._sequential_merge(results)
        elif strategy == "intelligent":
            return await self._intelligent_merge(results)
        elif strategy == "voting":
            return await self._voting_merge(results)

    def _sequential_merge(self, results: dict[str, str]) -> str:
        """顺序拼接——按 Plan 中定义的 DAG 拓扑序输出"""
        return "\n\n---\n\n".join(
            f"## {step_name}\n{content}"
            for step_name, content in results.items()
        )

    async def _intelligent_merge(self, results: dict[str, str]) -> str:
        """智能合并——让 LLM 把多个结果融合成一篇流畅的输出"""
        merge_prompt = "你是一个结果合并器。合并以下多个 Sub-Agent 的输出为一篇连贯的报告:\n\n"
        for name, content in results.items():
            merge_prompt += f"=== {name} 的输出 ===\n{content}\n\n"
        merge_prompt += "请合并输出(保持事实准确、删除冗余、统一风格):"
        return await self.llm.complete(merge_prompt)

    async def _voting_merge(self, results: dict[str, str]) -> str:
        """投票融合——多个 Agent 对同一问题输出不同答案时,投票选最优"""
        # 先做语义去重(相同答案的不同表述)
        unique_results = self._deduplicate(results.values())
        if len(unique_results) == 1:
            return unique_results[0]

        # 投票
        vote_prompt = "以下是多个 Agent 对同一问题的回答。请选出最准确的一个:\n\n"
        for i, content in enumerate(unique_results):
            vote_prompt += f"--- 方案{i+1} ---\n{content}\n\n"
        vote_prompt += "输出格式:方案编号"
        winner = await self.llm.complete(vote_prompt)
        return unique_results[int(winner.strip()) - 1]

6.2 冲突仲裁:当 Agent 们各执一词

冲突是多 Agent 系统最不可避免的问题。三种仲裁策略:

  1. 置信度仲裁:每个 Agent 输出附带一个置信度分数(0-1),选分最高的。简单,但 Agent 的自信不总是准确的——LLM 的校准度(calibration)是已知问题。

  2. 证据链仲裁:每个 Agent 不仅输出答案,还输出推理过程和引用来源。合并器检查推理链的完整性和引用真实性。更可靠,但开销高(每个 Agent 需要多输出 2-3 倍文本)。

  3. 分层仲裁:设定一个「仲裁 Agent」(Validator 或 Moderator),专门负责在结果冲突时做裁决。这个仲裁 Agent 可以看到所有 Sub-Agent 的输出和推理过程,然后给出最终裁决。

class HierarchicalArbitrator:
    """分层仲裁——仲裁 Agent 拥有最终决定权"""

    def __init__(self, arbiter_llm, arbitrator_instructions: str):
        self.arbiter = arbiter_llm
        self.instructions = arbitrator_instructions

    async def arbitrate(self, question: str,
                        answers: list[dict]) -> dict:
        """
        answers: [{"agent": "RAG", "answer": "...", "confidence": 0.92, "evidence": [...]}, ...]
        """
        # 检查是否有明显分歧
        if self._all_agree(answers):
            return {"winner": answers[0], "confidence": "high"}

        # 构建仲裁上下文
        context = f"问题: {question}\n\n各 Agent 的回答:\n"
        for a in answers:
            context += f"\nAgent [{a['agent']}] (置信度: {a['confidence']}):\n"
            context += f"答案: {a['answer']}\n"
            context += f"证据: {json.dumps(a.get('evidence', []), ensure_ascii=False)}\n"

        # 仲裁 Agent 做决策
        decision = await self.arbiter.complete(
            f"{self.instructions}\n\n{context}\n\n请决定哪个答案最可靠,并解释原因。"
        )
        # 解析仲裁结果
        ...

    def _all_agree(self, answers: list[dict]) -> bool:
        """检查所有 Agent 是否本质上一致"""
        texts = [a["answer"] for a in answers]
        return all(self._semantic_similarity(texts[0], t) > 0.9 for t in texts)

七、三种模式的选型指南:一张决策矩阵

7.1 根据任务特征选型

任务特征 推荐模式 理由
任务结构明确、可分解 PEV Plan 驱动,天然适合 DAG
任务类型多样、但子任务独立 路由分发 Sub-Agent 互不依赖,水平扩展
需要多视角验证/风险评估 Debate/Consensus 讨论比单个 Agent 更全面
延迟敏感 (< 5s) 路由分发 一次路由 + 执行,无循环
高精度要求 (> 95%) PEV + Debate 混合 PEV 做结构执行,Debate 做关键决策仲裁
资源受限(Sub-Agent 少) PEV 少量 Agent 也能通过 Plan 完成复杂任务
快速原型/验证 路由分发 实现最简单,Sub-Agent 可独立开发

7.2 混合模式:实际生产系统的选择

生产系统中,很少只用单一模式。最实际的架构是混合编排——把不同模式按层级嵌入。

class HybridOrchestrator:
    """混合编排——路由分发 + PEV + Debate 三级组合"""

    def __init__(self):
        # Level 1: 路由分发(顶层)
        self.router = RoutingOrchestrator(...)
        # Level 2: PEV(中层)
        self.pev = PlannerExecutorValidator(...)
        # Level 3: Debate(底层,关键决策用)
        self.debate = DebateConsensus(...)

    async def run(self, task: str) -> str:
        # 1. 路由分发:判断任务主类型
        intent = await self.router.classify(task)

        if intent["category"] == "research":
            # 2. 研究型任务 → PEV(检索 + 分析 + 验证)
            return await self.pev.run(task)

        elif intent["category"] == "decision":
            # 3. 决策型任务 → Debate(多 Agent 讨论后决定)
            return await self.debate.debate(
                task, agents=self.debate_agents, max_rounds=3
            )

        elif intent["category"] == "coding":
            # 4. 编码型任务 → 先 PEV 再局部 Debate
            plan = await self.pev.plan(task)
            if any("architectural_decision" in s for s in plan):
                # 架构决策需要 Debate
                decision = await self.debate.debate(
                    "选择最佳实现方案",
                    agents=self.arch_agents, max_rounds=2
                )
                plan = await self.pev.replan_with_decision(task, decision)
            return await self.pev.execute_plan(plan)

        # 默认:通用 PEV
        return await self.pev.run(task)

写在最后

回头看三种编排模式,本质上是控制、类型、共识三者之间的权衡

Planner/Executor/Validator 模式是控制派——它假设「只要 Plan 做得够好,执行就不会出乱子」。这个假设在子任务少于 10 个时成立,超过后 Planner 本身就成了瓶颈。它对应分布式系统中的 2PC——强一致、高代价、单点瓶颈。

路由分发模式是类型派——它假设「只要分类器够准,每个任务就能找到对的人」。它的瓶颈不在执行,在分类——超过 10 个路由目标后准确率骤降。它对应 Saga——最终一致、补偿驱动的柔性事务。

Debate/Consensus 模式是共识派——它假设「真理在讨论中浮现」,愿意用 O(n²) 的通信代价换取更高的准确率。它是 Gossip 协议在 Agent 世界的映射——最终一致、弹性好、但收敛时间不可预测。

没有一个模式在所有场景下最优。实际生产系统应该像分层网络协议那样组合它们:

  • 顶层路由(L3 IP 层):用轻量级分类器做快速任务分派
  • 中层 PEV(L4 TCP 层):对每个子任务做 Plan → Execute → Validate 的可靠执行
  • 底层 Debate(L7 应用层):只在关键决策点(架构选型、安全仲裁、风险评估)启用,其他时候跳过

这种分层设计的好处是:每一层都可以独立优化、替换、甚至降级。路由层挂了就降级为全通用 Agent 兜底,PEV 的 Validator 发现 Debate 层不可用时就用少数服从多数——容错能力来自每一层都有自己的退路。

最后,多 Agent 编排最难的部分不是「怎么协调」,而是**「该不该协调」**。如果一个任务一个 Agent 就能搞定,不要为了用多 Agent 而用多 Agent。每多一个 Sub-Agent,你的系统就多了一个故障点、一个通信延迟、一个一致性隐患。编排是一种能力,不是一种默认

📌 AI Agent 工程实战系列:一、RAG 检索精度提升实战 → 二、Tool Calling 可靠性与容错 → 三、推理延迟优化 → 四、状态管理与持久化五、多 Agent 编排(本篇)下一讲:Agent 安全:从开发到生产的全链路防护(第 6 篇)


这是 AI Agent 工程实战系列的第 5 篇。如果你在生产环境中使用多 Agent 编排——特别是 MCP/A2A 协议的通信延迟问题、Orchestrator 的容错设计、或者想聊聊混合编排的最佳实践——欢迎在 yesmiracle.net 留言或直接联系。

By AI博士 万戈