课程0基础Agent开发课 / Agent基础 / 多Agent协作-Orchestrator-Worker与Supervisor模式
— 24 min read

多Agent协作-Orchestrator-Worker与Supervisor模式

*两种多 Agent 模式对比——Orchestrator-Worker(集中控制)与 Supervisor 分层(层级管理)*

多 Agent 协作:Orchestrator-Worker 与 Supervisor 模式

1.1 多 Agent 的动机:单 Agent 能力上限在哪里


两种多 Agent 模式对比——Orchestrator-Worker(集中控制)与 Supervisor 分层(层级管理)

在引入多 Agent 架构之前,需要先认清单 Agent 的能力上限在哪里。不是所有场景都需要多 Agent——过早引入多 Agent 只会增加复杂度而不带来收益。

单 Agent 的三道天花板

天花板一:上下文窗口限制。再大的上下文窗口也有上限,复杂任务(分析大型代码库、处理数百页文档)很容易超出限制。

天花板二:专业化深度与广度的矛盾。要求一个 Agent 同时具备"数据分析专家"、"代码工程师"、"法律顾问"的水平,等于要求一个人能精通所有领域——理论上可以,实践中每个角色都会做得平庸。

天花板三:串行处理的时间成本。10 个独立的子任务,单 Agent 必须串行处理,时间是并行处理的 10 倍。

多 Agent 如何突破这些上限

多 Agent 系统的核心思路是分治:把一个超出单 Agent 能力范围的任务,分解成多个可以被单 Agent 处理的子任务,分配给专门化的 Agent 并行执行,最后合并结果。

每个 Worker Agent 只处理自己专长的子任务,上下文窗口不会被无关内容占用;多个 Worker 并行执行,总时间大幅缩短;Supervisor Agent 负责协调,不承担执行工作,也不需要"懂所有领域",只需要能判断"这个任务该给谁"。

引入多 Agent 的代价

多 Agent 带来的复杂度是真实的:更多的 LLM 调用意味着更高的成本和延迟;Agent 之间的通信需要定义接口和格式;某个 Agent 失败需要有错误传播机制;调试变得更难,因为问题可能出在任何一个 Agent 或它们的交互中。

引入多 Agent 之前,先问一个问题:单 Agent 加上更好的工具、更长的上下文是否已经够用?如果够用,保持简单。


第 17 篇讲了让单个 Agent 在关键节点暂停等待人工确认。但还有另一类问题是人工确认解决不了的:任务本身超出了单个 Agent 的能力边界。

这时候,需要让多个 Agent 分工协作。


1.2 为什么需要多 Agent

单个 Agent 面临三道天花板,无论怎么调优都难以突破。

天花板一:上下文长度限制

任何 LLM 都有上下文窗口(Context Window,模型每次推理时能处理的最大文本量,超出部分会被截断忽略)——可以同时"看到"的文字数量上限。Claude 系列是 200k token,GPT-5 系列是 128k token(GPT-4.1 已扩展至 1M token)。

听起来很大,但分析一个中型代码库(几十个文件、几万行代码)时,把所有代码塞进一个上下文已经不够用。分析一份完整的法律合同集(几百页文件)时,更是远超上限。

单个 Agent 的记忆是有上限的房间——房间再大,也放不下一个仓库的东西。

天花板二:专业化分工的效率差异

一个"通才"Agent 被要求同时扮演:数据分析师(写 SQL、分析趋势)、后端工程师(写 API 代码)、技术文档作者(写用户手册)。

每个角色都有完全不同的专业知识、写作风格、思维框架。一个 Agent 在同一个上下文里同时扮演多个角色,要么每个角色都做得平庸,要么在角色之间的切换中产生混乱。

就像一个公司用一名员工同时承担 CTO、产品经理、销售总监三个职位——理论上可行,实际效果远不如各有专才。

天花板三:串行处理复杂任务太慢

分析 10 个竞争对手的产品,每个需要 3 分钟,串行处理要 30 分钟。如果 10 个 Agent 并行工作,3 分钟就能完成。

任务之间没有依赖关系时,串行是资源的浪费。


1.3 三种多 Agent 拓扑结构

根据任务的依赖关系和协作方式,多 Agent 系统有三种基本拓扑结构:

③ 监督者-工作者(Supervisor-Worker)

分配任务

分配任务

分配任务

返回结果

返回结果

返回结果

Supervisor Agent
协调者

研究员 Agent

代码 Agent

写作 Agent

② 并行分工(Parallel)

分发节点

Agent A
分析文档1

Agent B
分析文档2

Agent C
分析文档3

汇总节点

① 串行管道(Pipeline)

传递研究结果

传递草稿

研究员 Agent

写作 Agent

审核 Agent

三种结构对比:

维度 串行管道 并行分工 Supervisor-Worker
任务依赖 强依赖(前一步的输出是下一步的输入) 无依赖(子任务相互独立) 动态分配(Supervisor 决定)
执行速度 慢(必须按顺序等待) 快(并行执行) 灵活(可并行也可串行)
适用场景 研究→写作→审核;数据→分析→报告 同时分析多个文档;并发爬取多个网页 任务类型多样;需要动态判断下一步
实现难度 简单(A 完成后传给 B) 中等(需要合并多个结果) 较复杂(Supervisor 需要路由逻辑)
错误隔离 差(前一步出错,后续全部失败) 好(某个 Agent 出错不影响其他) 中等(取决于 Supervisor 的错误处理)
典型框架实现 LangGraph 线性图 LangGraph 并行分支 LangGraph + 路由节点

1.4 Supervisor 模式详解

Supervisor-Worker 是三种结构中最灵活、最复杂、也最适合"真实世界复杂任务"的模式。以下重点拆解它的设计。

1.4.1 Supervisor 的四个核心职责

职责一:任务分解

用户说"帮我研究一下竞争对手并写一份报告",Supervisor 要把这个模糊的目标分解成具体的子任务:

  • 先交给研究员 Agent 收集信息
  • 再交给分析 Agent 整理发现
  • 最后交给写作 Agent 生成报告

职责二:Agent 选择

Supervisor 维护一份可用 Worker 清单,根据任务类型路由到合适的 Worker。这需要 Supervisor 知道"每个 Worker 擅长什么"。

职责三:结果整合

多个 Worker 返回的结果,格式、风格、详细程度可能各不相同。Supervisor 负责把碎片化的结果整合成连贯的最终输出。

职责四:质量把控

如果某个 Worker 返回了低质量的结果(答案太短、格式错误、没有回答问题),Supervisor 可以重新分配任务或者要求该 Worker 重试。

1.4.2 Worker Agent 的设计原则

Worker 的设计应遵循三个原则:

  • 专业化:每个 Worker 只做一件事,做精做深,而不是通才
  • 接口统一:所有 Worker 接受相同格式的输入(任务描述字符串),返回相同格式的输出(结果字符串)
  • 可独立测试:Worker 应该可以脱离整个多 Agent 系统单独测试,输入一个任务,验证输出是否符合预期

1.4.3 通信方式:共享 State vs 消息传递

共享 State(共享状态):所有 Agent 共用一个状态对象,任何 Agent 都可以读取和修改状态。LangGraph(LangChain 旗下专门用于构建有状态 Agent 工作流的框架,通过"节点"表示执行步骤、"边"表示流转逻辑来描述复杂的多步骤 Agent 流程)默认使用这种方式。优点是简单直观;缺点是状态对象可能变得复杂,Agent 之间可能意外地修改彼此的数据。

消息传递:每个 Agent 只接收发给它的消息,处理完毕后发送消息给下一个 Agent。优点是耦合度低;缺点是需要明确定义消息格式,实现更复杂。

对于大多数场景,LangGraph 的共享 State 方式已经足够,本篇代码示例也采用这种方式。


1.5 LangGraph 实现 Supervisor 模式

以下为代码示例,非程序员可跳过代码,重点看文字说明。

这个示例实现了一个由三个 Worker 组成的内容生产系统:研究员(收集信息)、写作者(生成内容)、审核者(检查质量)。Supervisor 负责协调这三个 Worker 的工作流程。

验证目的:通过一个研究员-写作者-审核者的三 Agent 协作系统,验证 Supervisor 模式的核心机制——集中式路由决策、Worker 专业化分工、审核反馈循环、防死循环保护——并观察 Agent 之间通过共享状态传递信息的方式。

python
from typing import TypedDict, Literal, Annotated
import operator
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage
from langgraph.graph import StateGraph, START, END

# ---- 定义系统状态 ----

class MultiAgentState(TypedDict):
    """
    共享状态:所有 Agent 都可以读写这个状态对象。
    每个字段存储一类信息,Agent 通过读写对应字段来协作。
    """
    task: str                         # 原始任务描述
    research_result: str              # 研究员的调研结果
    draft_content: str                # 写作者的初稿
    review_feedback: str              # 审核者的反馈意见
    final_output: str                 # 最终输出
    next_agent: str                   # Supervisor 决定的下一个执行者
    iteration_count: int              # 迭代次数(防止无限循环)
    messages: Annotated[list, operator.add]  # 完整消息历史

MAX_ITERATIONS = 10  # 最大迭代次数,超过则强制结束

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

# ---- 定义三个 Worker Agent ----

def researcher_agent(state: MultiAgentState) -> MultiAgentState:
    """
    研究员 Agent:负责收集和整理与任务相关的背景信息。
    输入:任务描述(state["task"])
    输出:调研结果(写入 state["research_result"])
    """
    response = llm.invoke([
        SystemMessage(content=(
            "你是一名专业研究员。请针对给定的任务,收集相关背景信息、"
            "关键数据和重要观点。输出结构化的调研摘要,300字以内。"
        )),
        HumanMessage(content=f"任务:{state['task']}"),
    ])
    print(f"[研究员] 完成调研,字数:{len(response.content)}")
    return {
        "research_result": response.content,
        "messages": [response],
    }


def writer_agent(state: MultiAgentState) -> MultiAgentState:
    """
    写作者 Agent:基于调研结果撰写内容初稿。
    输入:任务描述 + 调研结果
    输出:内容初稿(写入 state["draft_content"])
    """
    # 如果有审核反馈,则参考反馈修改;否则基于调研结果写初稿
    feedback_section = ""
    if state.get("review_feedback"):
        feedback_section = f"\n\n审核反馈(请据此修改):\n{state['review_feedback']}"

    response = llm.invoke([
        SystemMessage(content=(
            "你是一名专业内容写作者。请基于提供的调研结果,撰写高质量的文章内容。"
            "要求:逻辑清晰、语言流畅、有实质内容,500字以内。"
        )),
        HumanMessage(content=(
            f"任务:{state['task']}\n\n"
            f"调研结果:{state['research_result']}"
            f"{feedback_section}"
        )),
    ])
    print(f"[写作者] 完成初稿,第 {state['iteration_count']+1} 次写作")
    return {
        "draft_content": response.content,
        "messages": [response],
    }


def reviewer_agent(state: MultiAgentState) -> MultiAgentState:
    """
    审核者 Agent:审查初稿质量,给出通过/修改意见。
    输入:任务描述 + 初稿内容
    输出:审核反馈(写入 state["review_feedback"])
    特殊约定:如果质量通过,反馈开头写 "APPROVED"
    """
    response = llm.invoke([
        SystemMessage(content=(
            "你是一名严格的内容审核者。请评估文章初稿的质量。\n"
            "评估标准:内容准确性、逻辑连贯性、实用价值。\n"
            "如果质量合格,回复以 'APPROVED' 开头,后接简短评语。\n"
            "如果需要修改,直接说明具体的修改建议,不要写 APPROVED。"
        )),
        HumanMessage(content=(
            f"任务要求:{state['task']}\n\n"
            f"文章初稿:{state['draft_content']}"
        )),
    ])
    print(f"[审核者] 完成审核:{'通过' if 'APPROVED' in response.content else '需修改'}")
    return {
        "review_feedback": response.content,
        "messages": [response],
    }


# ---- 定义 Supervisor Agent ----

def supervisor_agent(state: MultiAgentState) -> MultiAgentState:
    """
    Supervisor:根据当前状态决定下一步派谁去工作。
    路由逻辑:
      - 没有调研结果 → 派研究员
      - 有调研结果但没有初稿 → 派写作者
      - 有初稿但没有审核反馈 → 派审核者
      - 审核通过(APPROVED) → 结束
      - 审核不通过 → 派写作者修改(检查迭代次数防止死循环)
    """
    # 超过最大迭代次数,强制结束(防止无限循环)
    if state["iteration_count"] >= MAX_ITERATIONS:
        print(f"[Supervisor] 已达最大迭代次数 {MAX_ITERATIONS},强制结束")
        return {
            "next_agent": "end",
            "final_output": state.get("draft_content", "任务超时,未能完成"),
        }

    # 路由决策逻辑
    if not state.get("research_result"):
        print("[Supervisor] → 派遣研究员")
        next_step = "researcher"

    elif not state.get("draft_content"):
        print("[Supervisor] → 派遣写作者")
        next_step = "writer"

    elif not state.get("review_feedback"):
        print("[Supervisor] → 派遣审核者")
        next_step = "reviewer"

    elif "APPROVED" in state.get("review_feedback", ""):
        print("[Supervisor] → 内容已通过审核,任务完成")
        next_step = "end"

    else:
        # 审核未通过,让写作者根据反馈修改
        print(f"[Supervisor] → 审核未通过,第 {state['iteration_count']+1} 次修改")
        # 清空旧的审核反馈,让写作者重写后再次审核
        next_step = "writer"

    return {
        "next_agent": next_step,
        "iteration_count": state["iteration_count"] + 1,
    }


# ---- 路由函数:Supervisor 的决策映射到图的边 ----

def route_by_supervisor(state: MultiAgentState) -> Literal[
    "researcher", "writer", "reviewer", "__end__"
]:
    """
    根据 Supervisor 的决策,返回下一个要执行的节点名称。
    LangGraph 用这个函数的返回值决定走哪条边。
    """
    next_agent = state.get("next_agent", "researcher")
    if next_agent == "end":
        return "__end__"
    return next_agent  # 返回 "researcher"、"writer" 或 "reviewer"


# ---- 构建 LangGraph 图 ----

def build_supervisor_graph():
    builder = StateGraph(MultiAgentState)

    # 注册所有节点
    builder.add_node("supervisor", supervisor_agent)
    builder.add_node("researcher", researcher_agent)
    builder.add_node("writer", writer_agent)
    builder.add_node("reviewer", reviewer_agent)

    # 入口:从 Supervisor 开始
    builder.add_edge(START, "supervisor")

    # Supervisor 根据路由函数决定下一步
    builder.add_conditional_edges(
        "supervisor",
        route_by_supervisor,
        {
            "researcher": "researcher",
            "writer": "writer",
            "reviewer": "reviewer",
            "__end__": END,
        }
    )

    # 所有 Worker 完成后,回到 Supervisor 汇报
    builder.add_edge("researcher", "supervisor")
    builder.add_edge("writer", "supervisor")
    builder.add_edge("reviewer", "supervisor")

    return builder.compile()


# ---- 运行示例 ----

def run_multi_agent_task(task: str) -> str:
    graph = build_supervisor_graph()

    initial_state = {
        "task": task,
        "research_result": "",
        "draft_content": "",
        "review_feedback": "",
        "final_output": "",
        "next_agent": "",
        "iteration_count": 0,
        "messages": [],
    }

    print(f"=== 开始多 Agent 协作任务 ===\n任务:{task}\n")

    final_state = graph.invoke(initial_state)

    print("\n=== 任务完成 ===")
    print(f"总迭代次数:{final_state['iteration_count']}")
    print(f"\n最终内容:\n{final_state['draft_content']}")

    return final_state["draft_content"]


# 测试
result = run_multi_agent_task("写一篇面向Java程序员的AI Agent入门介绍,500字")

文字说明(代码之外的关键设计)

  • APPROVED 约定:审核者 Agent 通过在输出开头写 APPROVED 来表示"通过",Supervisor 通过字符串检测来识别。这是 Agent 间通信的一种简单约定,实际生产中建议使用结构化输出(JSON格式)替代字符串匹配,更可靠。
  • iteration_count 是防止死循环的关键。如果写作者和审核者陷入"写了改、改了还不过"的死循环,MAX_ITERATIONS 会强制终止。
  • 每个 Worker 完成后都回到 Supervisor,由 Supervisor 决定下一步。这是"中心化协调"的核心思想:没有 Worker 知道自己之后谁上场,只有 Supervisor 掌握全局。

1.6 防止多 Agent 失控的三个关键设计

多 Agent 系统相比单 Agent,有更多出问题的可能:某个 Agent 卡住、某两个 Agent 互相等待、某个 Agent 反复失败拖慢整个系统……

以下三个设计是避免失控的关键:

1.6.1 设计一:明确的终止条件

每个多 Agent 系统必须有至少一条"结束路径",并且要有兜底的强制结束条件(如最大迭代次数)。否则任何一个环节出现非预期情况,系统就会无限运行消耗资源。

python
# 好的设计:双保险
if task_is_complete(state):      # 正常结束:任务完成
    return END
if state["iterations"] > 20:    # 兜底:超过最大次数强制结束
    return END

1.6.2 设计二:每个 Agent 的权限边界

每个 Worker 只能做自己职责范围内的事,不应该跨界修改其他 Worker 的数据。

python
# 坏的设计:审核者直接修改初稿
def reviewer_agent(state):
    state["draft_content"] = improved_draft  # 不应该!审核者应该写反馈,不应该改稿

# 好的设计:审核者只写反馈
def reviewer_agent(state):
    return {"review_feedback": "建议增加具体数据支撑..."}  # 只修改自己负责的字段

1.6.3 设计三:错误传播的隔离

某个 Worker 报错时,不应该让整个系统崩溃。Supervisor 应该能捕获 Worker 的异常,进行降级处理(跳过、重试、使用备用 Agent)。

python
def supervisor_with_error_handling(state):
    try:
        # 正常路由逻辑
        return route_to_next_agent(state)
    except AgentTimeoutError as e:
        # Worker 超时:记录日志,尝试换一个 Worker
        log_error(e)
        return {"next_agent": "fallback_agent"}
    except CriticalError as e:
        # 严重错误:终止任务,返回错误信息给用户
        return {"next_agent": "end", "final_output": f"任务失败:{e}"}

1.7 实战案例:代码生成与验证协作系统

以下为代码示例,非程序员可跳过代码,重点看文字说明。

这个案例展示了一个三 Agent 协作的代码质量保障系统:代码生成 Agent(写代码)+ 测试 Agent(写测试并运行)+ 代码审查 Agent(检查代码质量)。

python
import subprocess
import tempfile
import os

# 代码生成 Agent:根据需求写代码
def code_generator(state):
    feedback = state.get("review_comments", "")
    prompt = f"需求:{state['requirement']}"
    if feedback:
        prompt += f"\n\n代码审查意见(请据此修改):{feedback}"

    response = llm.invoke([
        SystemMessage(content=(
            "你是一名 Python 专家。请编写符合需求的 Python 代码。"
            "只输出代码,不要解释,不要 markdown 代码块格式。"
        )),
        HumanMessage(content=prompt),
    ])
    print("[代码生成] 完成代码编写")
    return {"generated_code": response.content}


# 测试 Agent:为生成的代码编写单元测试并执行
def test_agent(state):
    # 请 LLM 为代码生成测试用例
    response = llm.invoke([
        SystemMessage(content=(
            "你是测试工程师。请为以下代码编写 pytest 单元测试。"
            "只输出测试代码,不要解释。"
        )),
        HumanMessage(content=f"待测代码:\n{state['generated_code']}"),
    ])
    test_code = response.content

    # 实际执行测试(在临时目录中)
    test_result = "PASS"  # 默认通过
    try:
        with tempfile.TemporaryDirectory() as tmpdir:
            # 写入代码文件
            code_file = os.path.join(tmpdir, "solution.py")
            test_file = os.path.join(tmpdir, "test_solution.py")
            with open(code_file, "w") as f:
                f.write(state["generated_code"])
            with open(test_file, "w") as f:
                f.write(test_code)

            # 运行 pytest
            result = subprocess.run(
                ["python", "-m", "pytest", test_file, "-v", "--tb=short"],
                capture_output=True, text=True, timeout=30, cwd=tmpdir
            )
            test_result = "PASS" if result.returncode == 0 else f"FAIL:\n{result.stdout}"
    except Exception as e:
        test_result = f"ERROR: {e}"

    print(f"[测试] 运行结果:{test_result[:50]}")
    return {"test_result": test_result, "test_code": test_code}


# 代码审查 Agent:检查代码质量
def code_reviewer(state):
    response = llm.invoke([
        SystemMessage(content=(
            "你是高级代码审查专家。请审查代码质量:\n"
            "检查项:命名规范、错误处理、边界条件、代码简洁性。\n"
            "如果代码质量合格且测试通过,回复以 'LGTM'(Looks Good To Me)开头。\n"
            "否则,直接给出具体修改意见。"
        )),
        HumanMessage(content=(
            f"代码:\n{state['generated_code']}\n\n"
            f"测试结果:{state.get('test_result', '未测试')}"
        )),
    ])

    approved = response.content.startswith("LGTM")
    print(f"[代码审查] {'通过' if approved else '未通过'}")
    return {"review_comments": response.content, "code_approved": approved}

这个系统的关键点

  • 测试 Agent 不只是"写测试代码",还会真正执行测试并返回通过/失败。这是多 Agent 协作的价值所在——不同 Agent 可以使用不同的工具(写代码 vs 执行代码)。
  • 审查 Agent 同时看"代码质量"和"测试结果",两者都满足才给出 LGTM。
  • 整个流程和前面的 Supervisor 框架一样:三个 Worker 都完成后,Supervisor 决定"是否需要再次修改"。

1.8 小结

多 Agent 协作是突破单 Agent 能力上限的核心方案,选择哪种拓扑取决于任务特性:

  • 串行管道:当下一步严格依赖上一步的输出,选串行
  • 并行分工:当多个子任务可以独立完成,选并行
  • Supervisor-Worker:当任务需要动态判断下一步做什么,选 Supervisor

设计多 Agent 系统时,最容易被忽视的是防失控设计。最大迭代次数、明确的权限边界、错误隔离——这三点比架构选型更能决定系统在生产环境中的稳定性。

下一篇讲 Agent 长期运行时面临的挑战:进程崩溃、服务重启之后,如何从断点继续执行,而不是从头开始。

本页目录