13_多Agent协作_Supervisor模式vsSwarm模式深度对比

概述

前面几篇我们已经把单 Agent 的核心能力串起来了:

  • create_agent() 负责把模型、工具、提示词和状态组装成 Agent。
  • Middleware 负责在 Agent 执行过程中做摘要、审批、fallback、限流等治理。
  • LangGraph 负责把复杂流程表达成带状态、分支和循环的图。

到这里,一个自然的问题会出现:

如果一个任务太复杂,能不能让多个 Agent 分工协作?

答案是可以,但要先澄清一个误区:

多 Agent 不是"Agent 越多越智能",而是"用更清晰的边界管理复杂上下文和复杂职责"。

一个 Agent 通常会在这几类情况下变得吃力:

  • 工具太多,模型不知道该选哪个。
  • Prompt 太长,角色和规则互相干扰。
  • 任务跨多个专业领域,比如研发、测试、产品、运营。
  • 需要多个步骤顺序执行,并且每一步都有不同判断标准。
  • 某些子任务可以并行做,但最后要合并结果。
  • 不同团队希望独立维护自己的 Agent 能力。

LangChain 官方多 Agent 文档里也强调:多 Agent 的核心价值通常来自上下文管理、分布式开发和并行化,而不是单纯增加模型调用次数。

本文重点讲两种最常见的多 Agent 协作模式:

  • Supervisor 模式:一个主管 Agent 统一调度多个专家 Agent。
  • Swarm 模式:多个 Agent 之间可以动态交接控制权。

多 Agent 的本质不是"堆模型",而是把复杂任务拆成边界清晰、上下文可控、可观测的协作单元。

先看全局:Supervisor 和 Swarm 的核心差异

先用一张表建立直觉。

维度 Supervisor 模式 Swarm 模式
控制中心 有中心调度者 无固定中心,当前 Agent 可交接
决策方式 Supervisor 决定调用哪个专家 Agent 自己决定是否 handoff
用户交互 通常由 Supervisor 对外响应 当前活跃 Agent 可直接对外响应
上下文隔离 强,专家可只看到分配给自己的任务 弱到中等,取决于 handoff 传递什么
流程可控性 强,适合稳定业务流程 更灵活,适合开放式协作
并行能力 更容易并行调用多个专家 通常偏顺序交接
调试难度 相对低,所有路由经过主管 相对高,控制权会转移
适用任务 汇总报告、代码审查、研究分析、审批流 多角色对话、交接式客服、开放式任务推进

可以这样理解:

text 复制代码
Supervisor 像项目经理:
    任务进来 -> 拆给专家 -> 收集结果 -> 统一输出

Swarm 像接力协作:
    当前专家处理 -> 发现不属于自己 -> 交给下一个专家 -> 下一个继续处理

Supervisor 强在集中调度和结果合成,Swarm 强在动态交接和角色连续性。

Supervisor 模式:中心化调度

Supervisor 模式里通常有一个主 Agent,它负责:

  • 理解用户任务。
  • 判断需要哪些专家 Agent。
  • 把子任务分派给专家。
  • 控制执行顺序或并行关系。
  • 汇总专家结果。
  • 给用户返回最终答案。

专家 Agent 则只负责自己的专业能力。
#mermaid-svg-180nIlGVvlNNKMrY{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-180nIlGVvlNNKMrY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-180nIlGVvlNNKMrY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-180nIlGVvlNNKMrY .error-icon{fill:#552222;}#mermaid-svg-180nIlGVvlNNKMrY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-180nIlGVvlNNKMrY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-180nIlGVvlNNKMrY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-180nIlGVvlNNKMrY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-180nIlGVvlNNKMrY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-180nIlGVvlNNKMrY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-180nIlGVvlNNKMrY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-180nIlGVvlNNKMrY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-180nIlGVvlNNKMrY .marker.cross{stroke:#333333;}#mermaid-svg-180nIlGVvlNNKMrY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-180nIlGVvlNNKMrY p{margin:0;}#mermaid-svg-180nIlGVvlNNKMrY .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-180nIlGVvlNNKMrY .cluster-label text{fill:#333;}#mermaid-svg-180nIlGVvlNNKMrY .cluster-label span{color:#333;}#mermaid-svg-180nIlGVvlNNKMrY .cluster-label span p{background-color:transparent;}#mermaid-svg-180nIlGVvlNNKMrY .label text,#mermaid-svg-180nIlGVvlNNKMrY span{fill:#333;color:#333;}#mermaid-svg-180nIlGVvlNNKMrY .node rect,#mermaid-svg-180nIlGVvlNNKMrY .node circle,#mermaid-svg-180nIlGVvlNNKMrY .node ellipse,#mermaid-svg-180nIlGVvlNNKMrY .node polygon,#mermaid-svg-180nIlGVvlNNKMrY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-180nIlGVvlNNKMrY .rough-node .label text,#mermaid-svg-180nIlGVvlNNKMrY .node .label text,#mermaid-svg-180nIlGVvlNNKMrY .image-shape .label,#mermaid-svg-180nIlGVvlNNKMrY .icon-shape .label{text-anchor:middle;}#mermaid-svg-180nIlGVvlNNKMrY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-180nIlGVvlNNKMrY .rough-node .label,#mermaid-svg-180nIlGVvlNNKMrY .node .label,#mermaid-svg-180nIlGVvlNNKMrY .image-shape .label,#mermaid-svg-180nIlGVvlNNKMrY .icon-shape .label{text-align:center;}#mermaid-svg-180nIlGVvlNNKMrY .node.clickable{cursor:pointer;}#mermaid-svg-180nIlGVvlNNKMrY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-180nIlGVvlNNKMrY .arrowheadPath{fill:#333333;}#mermaid-svg-180nIlGVvlNNKMrY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-180nIlGVvlNNKMrY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-180nIlGVvlNNKMrY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-180nIlGVvlNNKMrY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-180nIlGVvlNNKMrY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-180nIlGVvlNNKMrY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-180nIlGVvlNNKMrY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-180nIlGVvlNNKMrY .cluster text{fill:#333;}#mermaid-svg-180nIlGVvlNNKMrY .cluster span{color:#333;}#mermaid-svg-180nIlGVvlNNKMrY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-180nIlGVvlNNKMrY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-180nIlGVvlNNKMrY rect.text{fill:none;stroke-width:0;}#mermaid-svg-180nIlGVvlNNKMrY .icon-shape,#mermaid-svg-180nIlGVvlNNKMrY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-180nIlGVvlNNKMrY .icon-shape p,#mermaid-svg-180nIlGVvlNNKMrY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-180nIlGVvlNNKMrY .icon-shape .label rect,#mermaid-svg-180nIlGVvlNNKMrY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-180nIlGVvlNNKMrY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-180nIlGVvlNNKMrY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-180nIlGVvlNNKMrY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户任务
Supervisor Agent
Researcher Agent
Writer Agent
Reviewer Agent
最终答案

这个结构的关键是:

所有任务分发和结果合成都经过 Supervisor。

专家之间通常不直接对话。

例如一个"写日报"系统可以拆成:

  • Researcher Agent:从 Jira、TAPD、Git 提交记录里收集当天工作材料。
  • Writer Agent:把材料写成日报草稿。
  • Reviewer Agent:检查是否遗漏关键事项、是否夸大、是否格式统一。
  • Supervisor Agent:决定调用顺序,整合最终日报。

Supervisor 模式用一个中心 Agent 管住复杂协作,让专家 Agent 保持单职责。

Supervisor 的两种实现方式

在 LangChain / LangGraph 生态里,Supervisor 可以有两种常见实现方式。

方式一:把子 Agent 暴露成工具

这是当前更推荐的思路。

主 Agent 不需要知道子 Agent 的内部细节,只把它们当成工具调用。

text 复制代码
Supervisor Agent
    tools:
        call_researcher(task)
        call_writer(materials)
        call_reviewer(draft)

这样做的好处是:

  • Supervisor 的控制权清晰。
  • 每个子 Agent 可以独立维护。
  • 子 Agent 的上下文可以隔离。
  • 工具描述可以明确告诉 Supervisor 什么时候调用谁。

方式二:使用 langgraph-supervisor

langgraph-supervisor 提供了 create_supervisor(),可以更快创建层级化多 Agent 系统。

不过它的 README 里已经提示:多数场景更推荐直接用 tool-calling 的方式实现 Supervisor,因为这样对上下文工程有更强控制力。

所以本文后面的代码会优先使用"子 Agent 作为工具"的写法。

Supervisor 最稳的落地方式,是把专家 Agent 包装成 Supervisor 可调用的工具。

Supervisor 示例:多 Agent 协作写日报

先定义三个专家 Agent。

为了让示例聚焦结构,工具里先用模拟数据。真实项目里你可以把这些函数换成 Jira、GitLab、飞书、TAPD、数据库 API。

python 复制代码
from langchain.agents import create_agent
from langchain.tools import tool


@tool
def fetch_today_tasks(user_id: str) -> str:
    """获取用户今天完成的任务、提交记录和阻塞事项。"""
    return (
        "任务:完成 LangGraph 多 Agent 文章大纲;"
        "提交:feat(agent): add daily report workflow;"
        "阻塞:等待测试环境接口权限。"
    )


researcher_agent = create_agent(
    model="openai:gpt-4o-mini",
    tools=[fetch_today_tasks],
    system_prompt=(
        "你是日报材料收集助手。"
        "你的任务是根据用户和日期收集事实材料。"
        "只输出事实,不要润色,不要编造。"
    ),
    name="researcher_agent",
)


writer_agent = create_agent(
    model="openai:gpt-4o-mini",
    tools=[],
    system_prompt=(
        "你是日报写作助手。"
        "你需要把事实材料整理成结构清晰、表达简洁的工作日报。"
        "格式包含:今日完成、遇到问题、明日计划。"
    ),
    name="writer_agent",
)


reviewer_agent = create_agent(
    model="openai:gpt-4o-mini",
    tools=[],
    system_prompt=(
        "你是日报审查助手。"
        "你需要检查日报是否基于事实、是否遗漏阻塞事项、是否格式统一。"
        "如果发现问题,给出修改建议;如果没有问题,返回通过。"
    ),
    name="reviewer_agent",
)

接着把这些 Agent 包成工具,交给 Supervisor。

python 复制代码
def last_text(result: dict) -> str:
    return result["messages"][-1].content


@tool
def collect_daily_material(user_id: str, date: str) -> str:
    """收集指定用户在指定日期的日报事实材料。"""
    result = researcher_agent.invoke({
        "messages": [
            {
                "role": "user",
                "content": f"请收集用户 {user_id} 在 {date} 的工作材料。",
            }
        ]
    })
    return last_text(result)


@tool
def write_daily_report(materials: str) -> str:
    """根据事实材料生成日报草稿。"""
    result = writer_agent.invoke({
        "messages": [
            {
                "role": "user",
                "content": f"请基于以下材料写日报:\n{materials}",
            }
        ]
    })
    return last_text(result)


@tool
def review_daily_report(draft: str, materials: str) -> str:
    """审查日报草稿是否准确、完整、格式统一。"""
    result = reviewer_agent.invoke({
        "messages": [
            {
                "role": "user",
                "content": (
                    f"事实材料:\n{materials}\n\n"
                    f"日报草稿:\n{draft}\n\n"
                    "请审查草稿。"
                ),
            }
        ]
    })
    return last_text(result)

最后创建 Supervisor。

python 复制代码
supervisor_agent = create_agent(
    model="openai:gpt-4o-mini",
    tools=[
        collect_daily_material,
        write_daily_report,
        review_daily_report,
    ],
    system_prompt=(
        "你是日报生成系统的 Supervisor。"
        "你必须先调用 collect_daily_material 收集事实,"
        "再调用 write_daily_report 生成草稿,"
        "最后调用 review_daily_report 审查。"
        "如果审查不通过,需要根据审查意见修订后再输出。"
        "最终只输出日报正文。"
    ),
    name="daily_report_supervisor",
)


result = supervisor_agent.invoke({
    "messages": [
        {
            "role": "user",
            "content": "请生成 user_123 在 2026-06-28 的日报。",
        }
    ]
})

print(result["messages"][-1].content)

这段代码背后的执行逻辑是:
Reviewer Writer Researcher Supervisor User Reviewer Writer Researcher Supervisor User #mermaid-svg-RSeqyEIssC0DNIcZ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-RSeqyEIssC0DNIcZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-RSeqyEIssC0DNIcZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-RSeqyEIssC0DNIcZ .error-icon{fill:#552222;}#mermaid-svg-RSeqyEIssC0DNIcZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RSeqyEIssC0DNIcZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-RSeqyEIssC0DNIcZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RSeqyEIssC0DNIcZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RSeqyEIssC0DNIcZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-RSeqyEIssC0DNIcZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RSeqyEIssC0DNIcZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RSeqyEIssC0DNIcZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RSeqyEIssC0DNIcZ .marker.cross{stroke:#333333;}#mermaid-svg-RSeqyEIssC0DNIcZ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RSeqyEIssC0DNIcZ p{margin:0;}#mermaid-svg-RSeqyEIssC0DNIcZ .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-RSeqyEIssC0DNIcZ text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-RSeqyEIssC0DNIcZ .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-RSeqyEIssC0DNIcZ .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-RSeqyEIssC0DNIcZ .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-RSeqyEIssC0DNIcZ .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-RSeqyEIssC0DNIcZ #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-RSeqyEIssC0DNIcZ .sequenceNumber{fill:white;}#mermaid-svg-RSeqyEIssC0DNIcZ #sequencenumber{fill:#333;}#mermaid-svg-RSeqyEIssC0DNIcZ #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-RSeqyEIssC0DNIcZ .messageText{fill:#333;stroke:none;}#mermaid-svg-RSeqyEIssC0DNIcZ .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-RSeqyEIssC0DNIcZ .labelText,#mermaid-svg-RSeqyEIssC0DNIcZ .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-RSeqyEIssC0DNIcZ .loopText,#mermaid-svg-RSeqyEIssC0DNIcZ .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-RSeqyEIssC0DNIcZ .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-RSeqyEIssC0DNIcZ .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-RSeqyEIssC0DNIcZ .noteText,#mermaid-svg-RSeqyEIssC0DNIcZ .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-RSeqyEIssC0DNIcZ .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-RSeqyEIssC0DNIcZ .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-RSeqyEIssC0DNIcZ .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-RSeqyEIssC0DNIcZ .actorPopupMenu{position:absolute;}#mermaid-svg-RSeqyEIssC0DNIcZ .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-RSeqyEIssC0DNIcZ .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-RSeqyEIssC0DNIcZ .actor-man circle,#mermaid-svg-RSeqyEIssC0DNIcZ line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-RSeqyEIssC0DNIcZ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 生成日报收集事实材料返回任务、提交、阻塞生成日报草稿返回草稿审查草稿返回审查意见输出最终日报

Supervisor 负责"先后顺序"和"最终合成",专家 Agent 只负责自己的专业步骤。

Supervisor 的上下文隔离

Supervisor 模式最大的优势之一是上下文隔离。

在上面的例子里:

  • Researcher 只需要看到用户、日期和数据源。
  • Writer 只需要看到事实材料。
  • Reviewer 只需要看到事实材料和草稿。
  • Supervisor 只需要看到每个专家的最终结果。

这比把所有工具、所有规则、所有中间结果都塞给一个 Agent 更稳。

错误做法:

text 复制代码
一个超级 Agent:
    你会查 Jira
    你会看 Git
    你会写日报
    你会审查
    你会判断是否重写
    你会处理异常
    你会发飞书
    你会归档数据库

这种 Agent 会很快变成一个难以调试的黑盒。

更好的拆法:

text 复制代码
Supervisor:
    负责流程和决策

Researcher:
    负责事实收集

Writer:
    负责表达组织

Reviewer:
    负责质量检查

Publisher:
    负责发送和归档

多 Agent 的第一价值是上下文隔离,不是让多个 Agent 互相聊天。

Swarm 模式:动态交接控制权

Swarm 模式和 Supervisor 最大的不同是:

没有固定中心调度者,当前活跃 Agent 可以把控制权交给另一个 Agent。

它的结构更像这样:
#mermaid-svg-nbDKx62NtOqxyr5s{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nbDKx62NtOqxyr5s .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nbDKx62NtOqxyr5s .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nbDKx62NtOqxyr5s .error-icon{fill:#552222;}#mermaid-svg-nbDKx62NtOqxyr5s .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nbDKx62NtOqxyr5s .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nbDKx62NtOqxyr5s .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nbDKx62NtOqxyr5s .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nbDKx62NtOqxyr5s .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nbDKx62NtOqxyr5s .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nbDKx62NtOqxyr5s .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nbDKx62NtOqxyr5s .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nbDKx62NtOqxyr5s .marker.cross{stroke:#333333;}#mermaid-svg-nbDKx62NtOqxyr5s svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nbDKx62NtOqxyr5s p{margin:0;}#mermaid-svg-nbDKx62NtOqxyr5s .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-nbDKx62NtOqxyr5s .cluster-label text{fill:#333;}#mermaid-svg-nbDKx62NtOqxyr5s .cluster-label span{color:#333;}#mermaid-svg-nbDKx62NtOqxyr5s .cluster-label span p{background-color:transparent;}#mermaid-svg-nbDKx62NtOqxyr5s .label text,#mermaid-svg-nbDKx62NtOqxyr5s span{fill:#333;color:#333;}#mermaid-svg-nbDKx62NtOqxyr5s .node rect,#mermaid-svg-nbDKx62NtOqxyr5s .node circle,#mermaid-svg-nbDKx62NtOqxyr5s .node ellipse,#mermaid-svg-nbDKx62NtOqxyr5s .node polygon,#mermaid-svg-nbDKx62NtOqxyr5s .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nbDKx62NtOqxyr5s .rough-node .label text,#mermaid-svg-nbDKx62NtOqxyr5s .node .label text,#mermaid-svg-nbDKx62NtOqxyr5s .image-shape .label,#mermaid-svg-nbDKx62NtOqxyr5s .icon-shape .label{text-anchor:middle;}#mermaid-svg-nbDKx62NtOqxyr5s .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-nbDKx62NtOqxyr5s .rough-node .label,#mermaid-svg-nbDKx62NtOqxyr5s .node .label,#mermaid-svg-nbDKx62NtOqxyr5s .image-shape .label,#mermaid-svg-nbDKx62NtOqxyr5s .icon-shape .label{text-align:center;}#mermaid-svg-nbDKx62NtOqxyr5s .node.clickable{cursor:pointer;}#mermaid-svg-nbDKx62NtOqxyr5s .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-nbDKx62NtOqxyr5s .arrowheadPath{fill:#333333;}#mermaid-svg-nbDKx62NtOqxyr5s .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nbDKx62NtOqxyr5s .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nbDKx62NtOqxyr5s .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nbDKx62NtOqxyr5s .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-nbDKx62NtOqxyr5s .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nbDKx62NtOqxyr5s .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-nbDKx62NtOqxyr5s .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nbDKx62NtOqxyr5s .cluster text{fill:#333;}#mermaid-svg-nbDKx62NtOqxyr5s .cluster span{color:#333;}#mermaid-svg-nbDKx62NtOqxyr5s div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-nbDKx62NtOqxyr5s .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-nbDKx62NtOqxyr5s rect.text{fill:none;stroke-width:0;}#mermaid-svg-nbDKx62NtOqxyr5s .icon-shape,#mermaid-svg-nbDKx62NtOqxyr5s .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nbDKx62NtOqxyr5s .icon-shape p,#mermaid-svg-nbDKx62NtOqxyr5s .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-nbDKx62NtOqxyr5s .icon-shape .label rect,#mermaid-svg-nbDKx62NtOqxyr5s .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nbDKx62NtOqxyr5s .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-nbDKx62NtOqxyr5s .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-nbDKx62NtOqxyr5s :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} handoff
handoff
handoff
用户
Researcher Agent
Writer Agent
Reviewer Agent

每个 Agent 都可以有自己的工具和提示词,也可以持有交接工具:

text 复制代码
Researcher:
    tools:
        fetch_today_tasks
        handoff_to_writer

Writer:
    tools:
        handoff_to_reviewer

Reviewer:
    tools:
        handoff_to_writer
        handoff_to_user

langgraph-swarm 的核心思路就是这种动态 handoff:

  • 当前 Agent 根据自己的专业判断是否继续处理。
  • 如果任务不属于自己,就调用 handoff tool 交给其他 Agent。
  • 系统记录当前 active agent。
  • 多轮对话时,可以从上一次活跃 Agent 继续。

Swarm 的重点不是"谁调度谁",而是"当前 Agent 处理到合适位置后,把控制权交给更合适的 Agent"。

Swarm 示例:日报写作的接力协作

使用 langgraph-swarm 可以这样组织。

python 复制代码
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langgraph.checkpoint.memory import InMemorySaver
from langgraph_swarm import create_handoff_tool, create_swarm


model = ChatOpenAI(model="gpt-4o-mini")


researcher = create_agent(
    model=model,
    tools=[
        fetch_today_tasks,
        create_handoff_tool(
            agent_name="Writer",
            description="当事实材料已经收集完成后,转交给 Writer 写日报草稿。",
        ),
    ],
    system_prompt=(
        "你是 Researcher,只负责收集日报事实材料。"
        "材料收集完成后,必须转交给 Writer。"
    ),
    name="Researcher",
)


writer = create_agent(
    model=model,
    tools=[
        create_handoff_tool(
            agent_name="Reviewer",
            description="当日报草稿写完后,转交给 Reviewer 审查。",
        ),
    ],
    system_prompt=(
        "你是 Writer,只负责根据事实材料写日报草稿。"
        "写完草稿后,必须转交给 Reviewer。"
    ),
    name="Writer",
)


reviewer = create_agent(
    model=model,
    tools=[
        create_handoff_tool(
            agent_name="Writer",
            description="如果草稿需要修改,转回 Writer。",
        ),
    ],
    system_prompt=(
        "你是 Reviewer,负责审查日报是否准确、完整、格式统一。"
        "如果需要修改,转回 Writer;如果通过,直接给用户最终日报。"
    ),
    name="Reviewer",
)


workflow = create_swarm(
    [researcher, writer, reviewer],
    default_active_agent="Researcher",
)

app = workflow.compile(checkpointer=InMemorySaver())

config = {"configurable": {"thread_id": "daily-report-001"}}

result = app.invoke(
    {
        "messages": [
            {
                "role": "user",
                "content": "请生成 user_123 在 2026-06-28 的日报。",
            }
        ]
    },
    config=config,
)

这里有一个关键点:

Swarm 做多轮对话时,一定要使用 checkpointer,否则系统无法稳定记住上一次活跃的是哪个 Agent。

例如第一轮用户说:

text 复制代码
请帮我写今天的日报。

系统可能从 Researcher 开始,最后交给 Reviewer

第二轮用户说:

text 复制代码
把"明日计划"写得再具体一点。

如果有 checkpointer,系统可以知道当前更适合从上一次活跃 Agent 或相关 Agent 继续处理。

如果没有 checkpointer,Swarm 很可能重新从默认 Agent 开始,导致上下文断裂。

Swarm 依赖 active agent 状态,多轮场景必须重视 checkpoint。

Handoff:Swarm 的核心机制

Swarm 里最关键的是 handoff tool。

handoff 本质上做三件事:

  1. 告诉图下一步跳到哪个 Agent。
  2. 更新父图状态,比如 active_agent
  3. 决定把哪些上下文传给下一个 Agent。

一个自定义 handoff 的核心形态类似这样:

python 复制代码
from typing import Annotated
from langchain.tools import tool
from langchain.messages import ToolMessage
from langgraph.types import Command
from langgraph.prebuilt import InjectedState
from langchain.tools import InjectedToolCallId


def create_report_handoff_tool(agent_name: str):
    @tool
    def handoff(
        task_description: Annotated[
            str,
            "描述下一个 Agent 需要完成的任务和必要上下文。",
        ],
        state: Annotated[dict, InjectedState],
        tool_call_id: Annotated[str, InjectedToolCallId],
    ):
        tool_message = ToolMessage(
            content=f"Transferred to {agent_name}",
            tool_call_id=tool_call_id,
        )

        return Command(
            goto=agent_name,
            graph=Command.PARENT,
            update={
                "messages": state["messages"] + [tool_message],
                "active_agent": agent_name,
                "task_description": task_description,
            },
        )

    return handoff

这个例子里,Command 同时表达了:

  • goto: 下一个 Agent。
  • graph=Command.PARENT: 跳转发生在父图。
  • update: 更新父图状态。

这和第 12 篇讲过的 Command 是同一个思想:节点或工具既能更新状态,也能决定下一步去哪里。

Swarm 的 handoff 不是普通函数调用,而是一次带状态更新的控制权转移。

写日报案例:Supervisor 版本 vs Swarm 版本

现在回到"多 Agent 协作写日报"这个案例。

同样是三个角色:

  • Researcher:收集事实。
  • Writer:写日报。
  • Reviewer:审查日报。

Supervisor 版本的流程是:

text 复制代码
用户 -> Supervisor
Supervisor -> Researcher
Supervisor -> Writer
Supervisor -> Reviewer
Supervisor -> 用户

Swarm 版本的流程是:

text 复制代码
用户 -> Researcher
Researcher -> Writer
Writer -> Reviewer
Reviewer -> Writer 或 用户

二者区别非常明显。

Supervisor 更像流水线

#mermaid-svg-HC41NPIHdJ2s6Xwq{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HC41NPIHdJ2s6Xwq .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HC41NPIHdJ2s6Xwq .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HC41NPIHdJ2s6Xwq .error-icon{fill:#552222;}#mermaid-svg-HC41NPIHdJ2s6Xwq .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HC41NPIHdJ2s6Xwq .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HC41NPIHdJ2s6Xwq .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HC41NPIHdJ2s6Xwq .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HC41NPIHdJ2s6Xwq .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HC41NPIHdJ2s6Xwq .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HC41NPIHdJ2s6Xwq .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HC41NPIHdJ2s6Xwq .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HC41NPIHdJ2s6Xwq .marker.cross{stroke:#333333;}#mermaid-svg-HC41NPIHdJ2s6Xwq svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HC41NPIHdJ2s6Xwq p{margin:0;}#mermaid-svg-HC41NPIHdJ2s6Xwq .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-HC41NPIHdJ2s6Xwq .cluster-label text{fill:#333;}#mermaid-svg-HC41NPIHdJ2s6Xwq .cluster-label span{color:#333;}#mermaid-svg-HC41NPIHdJ2s6Xwq .cluster-label span p{background-color:transparent;}#mermaid-svg-HC41NPIHdJ2s6Xwq .label text,#mermaid-svg-HC41NPIHdJ2s6Xwq span{fill:#333;color:#333;}#mermaid-svg-HC41NPIHdJ2s6Xwq .node rect,#mermaid-svg-HC41NPIHdJ2s6Xwq .node circle,#mermaid-svg-HC41NPIHdJ2s6Xwq .node ellipse,#mermaid-svg-HC41NPIHdJ2s6Xwq .node polygon,#mermaid-svg-HC41NPIHdJ2s6Xwq .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HC41NPIHdJ2s6Xwq .rough-node .label text,#mermaid-svg-HC41NPIHdJ2s6Xwq .node .label text,#mermaid-svg-HC41NPIHdJ2s6Xwq .image-shape .label,#mermaid-svg-HC41NPIHdJ2s6Xwq .icon-shape .label{text-anchor:middle;}#mermaid-svg-HC41NPIHdJ2s6Xwq .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-HC41NPIHdJ2s6Xwq .rough-node .label,#mermaid-svg-HC41NPIHdJ2s6Xwq .node .label,#mermaid-svg-HC41NPIHdJ2s6Xwq .image-shape .label,#mermaid-svg-HC41NPIHdJ2s6Xwq .icon-shape .label{text-align:center;}#mermaid-svg-HC41NPIHdJ2s6Xwq .node.clickable{cursor:pointer;}#mermaid-svg-HC41NPIHdJ2s6Xwq .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-HC41NPIHdJ2s6Xwq .arrowheadPath{fill:#333333;}#mermaid-svg-HC41NPIHdJ2s6Xwq .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HC41NPIHdJ2s6Xwq .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HC41NPIHdJ2s6Xwq .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HC41NPIHdJ2s6Xwq .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-HC41NPIHdJ2s6Xwq .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HC41NPIHdJ2s6Xwq .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-HC41NPIHdJ2s6Xwq .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HC41NPIHdJ2s6Xwq .cluster text{fill:#333;}#mermaid-svg-HC41NPIHdJ2s6Xwq .cluster span{color:#333;}#mermaid-svg-HC41NPIHdJ2s6Xwq div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HC41NPIHdJ2s6Xwq .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-HC41NPIHdJ2s6Xwq rect.text{fill:none;stroke-width:0;}#mermaid-svg-HC41NPIHdJ2s6Xwq .icon-shape,#mermaid-svg-HC41NPIHdJ2s6Xwq .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HC41NPIHdJ2s6Xwq .icon-shape p,#mermaid-svg-HC41NPIHdJ2s6Xwq .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-HC41NPIHdJ2s6Xwq .icon-shape .label rect,#mermaid-svg-HC41NPIHdJ2s6Xwq .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HC41NPIHdJ2s6Xwq .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-HC41NPIHdJ2s6Xwq .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-HC41NPIHdJ2s6Xwq :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户
Supervisor
Researcher
Writer
Reviewer
最终日报

优点:

  • 流程稳定。
  • 易观测。
  • 易加审批。
  • 易做结构化输出。
  • 易限制专家 Agent 的上下文。

缺点:

  • 每次都要回到 Supervisor。
  • 对连续对话来说,可能有额外模型调用。
  • Supervisor 的提示词质量会影响整体调度。

Swarm 更像接力

#mermaid-svg-6ZRa8T7ps1708IVf{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-6ZRa8T7ps1708IVf .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-6ZRa8T7ps1708IVf .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-6ZRa8T7ps1708IVf .error-icon{fill:#552222;}#mermaid-svg-6ZRa8T7ps1708IVf .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6ZRa8T7ps1708IVf .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-6ZRa8T7ps1708IVf .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6ZRa8T7ps1708IVf .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6ZRa8T7ps1708IVf .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-6ZRa8T7ps1708IVf .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6ZRa8T7ps1708IVf .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6ZRa8T7ps1708IVf .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6ZRa8T7ps1708IVf .marker.cross{stroke:#333333;}#mermaid-svg-6ZRa8T7ps1708IVf svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6ZRa8T7ps1708IVf p{margin:0;}#mermaid-svg-6ZRa8T7ps1708IVf .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-6ZRa8T7ps1708IVf .cluster-label text{fill:#333;}#mermaid-svg-6ZRa8T7ps1708IVf .cluster-label span{color:#333;}#mermaid-svg-6ZRa8T7ps1708IVf .cluster-label span p{background-color:transparent;}#mermaid-svg-6ZRa8T7ps1708IVf .label text,#mermaid-svg-6ZRa8T7ps1708IVf span{fill:#333;color:#333;}#mermaid-svg-6ZRa8T7ps1708IVf .node rect,#mermaid-svg-6ZRa8T7ps1708IVf .node circle,#mermaid-svg-6ZRa8T7ps1708IVf .node ellipse,#mermaid-svg-6ZRa8T7ps1708IVf .node polygon,#mermaid-svg-6ZRa8T7ps1708IVf .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6ZRa8T7ps1708IVf .rough-node .label text,#mermaid-svg-6ZRa8T7ps1708IVf .node .label text,#mermaid-svg-6ZRa8T7ps1708IVf .image-shape .label,#mermaid-svg-6ZRa8T7ps1708IVf .icon-shape .label{text-anchor:middle;}#mermaid-svg-6ZRa8T7ps1708IVf .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-6ZRa8T7ps1708IVf .rough-node .label,#mermaid-svg-6ZRa8T7ps1708IVf .node .label,#mermaid-svg-6ZRa8T7ps1708IVf .image-shape .label,#mermaid-svg-6ZRa8T7ps1708IVf .icon-shape .label{text-align:center;}#mermaid-svg-6ZRa8T7ps1708IVf .node.clickable{cursor:pointer;}#mermaid-svg-6ZRa8T7ps1708IVf .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-6ZRa8T7ps1708IVf .arrowheadPath{fill:#333333;}#mermaid-svg-6ZRa8T7ps1708IVf .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-6ZRa8T7ps1708IVf .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-6ZRa8T7ps1708IVf .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6ZRa8T7ps1708IVf .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-6ZRa8T7ps1708IVf .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6ZRa8T7ps1708IVf .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-6ZRa8T7ps1708IVf .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-6ZRa8T7ps1708IVf .cluster text{fill:#333;}#mermaid-svg-6ZRa8T7ps1708IVf .cluster span{color:#333;}#mermaid-svg-6ZRa8T7ps1708IVf div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-6ZRa8T7ps1708IVf .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-6ZRa8T7ps1708IVf rect.text{fill:none;stroke-width:0;}#mermaid-svg-6ZRa8T7ps1708IVf .icon-shape,#mermaid-svg-6ZRa8T7ps1708IVf .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6ZRa8T7ps1708IVf .icon-shape p,#mermaid-svg-6ZRa8T7ps1708IVf .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-6ZRa8T7ps1708IVf .icon-shape .label rect,#mermaid-svg-6ZRa8T7ps1708IVf .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6ZRa8T7ps1708IVf .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-6ZRa8T7ps1708IVf .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-6ZRa8T7ps1708IVf :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 需要修改
通过
用户
Researcher
Writer
Reviewer
最终日报

优点:

  • 角色交接自然。
  • 连续对话更顺。
  • 当前 Agent 可以直接响应用户。
  • 适合开放式、多轮协作任务。

缺点:

  • 控制流更难预测。
  • 容易反复 handoff。
  • 对 checkpoint 依赖更强。
  • 上下文传递策略不当时会污染后续 Agent。

日报这种稳定流程更适合 Supervisor;如果用户会不断和不同角色来回互动,Swarm 才更有优势。

什么时候选 Supervisor?

优先选择 Supervisor 的场景:

  • 任务有明确入口和出口。
  • 流程顺序相对固定。
  • 最终答案需要统一口径。
  • 需要聚合多个专家结果。
  • 需要强审计、强观测。
  • 子任务可以并行。
  • 专家 Agent 不应该直接和用户对话。

典型场景:

场景 为什么适合 Supervisor
写日报 收集、写作、审查、发布流程固定
代码审查 规范、安全、影响范围可以分专家并行检查
研究报告 多个 Researcher 查不同方向,最后统一汇总
企业客服分流 主 Agent 判断走 FAQ、订单、退款、人审
SQL 查询助手 Schema、SQL 生成、安全校验、执行解释要顺序受控

例如代码审查可以这样拆:

text 复制代码
CodeReview Supervisor
    -> Style Agent
    -> Security Agent
    -> Test Impact Agent
    -> Summary Agent

其中前三个 Agent 可以并行执行,最后由 Summary Agent 或 Supervisor 汇总。

只要你希望"流程可控、结果统一、专家隔离",Supervisor 通常是默认选择。

什么时候选 Swarm?

优先选择 Swarm 的场景:

  • 多个 Agent 都可能直接面向用户。
  • 当前角色需要保持连续性。
  • 用户会在多个角色之间来回切换。
  • 任务路径不固定。
  • Agent 之间的交接本身就是业务流程。
  • 不希望所有动作都回到中心调度者。

典型场景:

场景 为什么适合 Swarm
多角色客服 售前、售后、技术支持之间动态转接
教学助手 讲解、出题、批改、提示之间来回切换
游戏 NPC 不同角色根据剧情交接对话
结对编程助手 架构师、实现者、测试者之间接力
开放式工作台 用户随时改变任务方向,需要当前 Agent 判断转交

例如客服系统:

text 复制代码
售前 Agent:
    介绍套餐
    用户问故障 -> handoff 技术支持

技术支持 Agent:
    排查问题
    用户问退款 -> handoff 售后

售后 Agent:
    处理退款和工单
    用户问新套餐 -> handoff 售前

这种场景里,如果每一步都回到 Supervisor,反而可能显得绕。

当"谁继续接待用户"本身会随对话动态变化时,Swarm 更自然。

上下文工程:多 Agent 成败的关键

多 Agent 最容易翻车的地方不是代码,而是上下文。

你必须决定:

  • 每个 Agent 能看到哪些消息?
  • 每个 Agent 能使用哪些工具?
  • handoff 时传完整历史还是任务摘要?
  • 专家 Agent 的中间推理是否暴露给其他 Agent?
  • 最终结果由谁合成?

Supervisor 的上下文建议

Supervisor 模式里,建议默认只让专家看到必要输入。

例如 Reviewer 不需要看到用户和 Supervisor 的所有对话,它只需要:

text 复制代码
事实材料
日报草稿
审查标准

这样可以减少干扰。

如果专家 Agent 需要保留自己的长期经验,可以通过 memory 或 store 管,而不是把所有消息都丢进本次上下文。

Swarm 的上下文建议

Swarm 模式里,handoff 时要特别谨慎。

最简单的做法是传完整 messages,但这可能导致:

  • 后续 Agent 看到太多无关内容。
  • 某个 Agent 的内部过程污染其他 Agent。
  • token 成本快速上涨。
  • 角色边界变模糊。

更稳的做法是 handoff 时让当前 Agent 生成一个 task_description

text 复制代码
请 Writer 基于以下事实写日报:
1. 今天完成 LangGraph 多 Agent 文章大纲。
2. 提交 feat(agent): add daily report workflow。
3. 当前阻塞是测试环境接口权限未开。

要求:
使用"今日完成 / 遇到问题 / 明日计划"格式。

把任务摘要传给下一个 Agent,而不是无脑传整段对话。

多 Agent 不是共享越多越好,而是每个 Agent 只看到完成任务所需的最小上下文。

结构化输出:让协作结果可判断

多 Agent 系统里,最好不要只靠自然语言判断下一步。

例如 Reviewer 如果返回:

text 复制代码
整体还可以,但明日计划可以再具体一点。

Supervisor 很难稳定判断到底是通过还是不通过。

更好的做法是让 Reviewer 返回结构化结果。

python 复制代码
from pydantic import BaseModel, Field


class ReviewResult(BaseModel):
    approved: bool = Field(description="日报是否通过审查")
    issues: list[str] = Field(description="发现的问题")
    revised_suggestions: list[str] = Field(description="修改建议")

然后创建 Reviewer:

python 复制代码
reviewer_agent = create_agent(
    model="openai:gpt-4o-mini",
    tools=[],
    system_prompt="你是严格的日报审查助手。",
    response_format=ReviewResult,
    name="reviewer_agent",
)

Supervisor 拿到结果后可以稳定决策:

python 复制代码
if review_result.approved:
    return final_report
else:
    rewrite_with_feedback(review_result.issues)

这和第 09 篇结构化输出、第 12 篇条件边是连起来的。

多 Agent 协作中的路由和审批,最好基于结构化字段,而不是解析自然语言。

常见问题一:为了多 Agent 而多 Agent

很多任务并不需要多 Agent。

如果你的流程只是:

text 复制代码
用户问题 -> 检索 -> 生成答案

用 RAG Chain 就够了。

如果你的流程只是:

text 复制代码
用户问题 -> 模型决定是否调用工具 -> 最终回答

用单个 create_agent() 就够了。

不要因为"多 Agent 听起来高级"就拆成:

text 复制代码
理解 Agent
规划 Agent
执行 Agent
总结 Agent
润色 Agent

这会带来额外问题:

  • 更多模型调用。
  • 更高延迟。
  • 更高 token 成本。
  • 更多中间错误。
  • 更难调试。

多 Agent 是复杂度管理工具,不是默认架构。

常见问题二:Supervisor 变成超级大脑

Supervisor 不应该什么都做。

错误做法:

text 复制代码
Supervisor:
    理解任务
    查数据
    写日报
    审查日报
    修改日报
    发消息

这和单 Agent 没区别,只是名字叫 Supervisor。

更好的边界是:

text 复制代码
Supervisor:
    拆任务
    选专家
    控顺序
    合结果

Expert:
    完成具体专业任务

Supervisor 的提示词也应该强调调度职责:

text 复制代码
你是调度者,不直接完成专家任务。
需要事实材料时调用 Researcher。
需要写作时调用 Writer。
需要审查时调用 Reviewer。

Supervisor 负责协调,不负责替所有专家干活。

常见问题三:Swarm 交接没有退出条件

Swarm 里很容易出现循环:

text 复制代码
Writer -> Reviewer -> Writer -> Reviewer -> Writer ...

这通常来自两个问题:

  • Reviewer 的通过标准太模糊。
  • Writer 不知道如何根据意见收敛。

要给系统加退出条件:

text 复制代码
最多修改 2 轮。
如果仍不通过,输出当前最佳版本,并附上未解决问题。

也可以在状态里记录:

python 复制代码
revision_count: int

每次从 Reviewer 转回 Writer 时加 1。

超过阈值就不再 handoff。

任何 Agent 交接循环都必须有明确的业务退出条件。

常见问题四:所有 Agent 共用一大段 messages

很多人为了省事,让所有 Agent 共用同一个 messages

这在小 demo 里没问题,但生产里会带来风险:

  • Agent 看到不该看的内部信息。
  • 子任务上下文越来越长。
  • 专家角色被其他 Agent 的输出干扰。
  • 难以做权限隔离。

更稳的方式是:

  • Supervisor 调专家时只传任务输入。
  • Swarm handoff 时传任务摘要。
  • 对敏感 Agent 使用独立 state key。
  • 对最终输出做单独合成。

例如:

python 复制代码
class DailyReportState(TypedDict):
    messages: list
    researcher_notes: str
    draft_report: str
    review_result: dict

不要所有东西都堆进 messages

共享消息历史方便,但不是上下文工程的最终答案。

常见问题五:忽略成本和延迟

多 Agent 会增加调用次数。

例如日报系统:

text 复制代码
单 Agent:
    1~3 次模型调用

Supervisor:
    Supervisor 调度
    Researcher 调用
    Supervisor 接收
    Writer 调用
    Supervisor 接收
    Reviewer 调用
    Supervisor 合成

Swarm:
    Researcher
    handoff Writer
    Writer
    handoff Reviewer
    Reviewer
    可能再 handoff Writer

如果每一步都是大模型,延迟和成本会很快上升。

优化方向:

  • 简单分类用小模型。
  • 固定规则用代码,不用 Agent。
  • 可并行的专家并行执行。
  • 专家只接收必要上下文。
  • 对重复材料做缓存。
  • 对长历史做摘要。

多 Agent 的架构收益必须大于额外调用成本。

生产建议:从 Supervisor 开始

如果你不知道选哪个,建议先从 Supervisor 开始。

原因很简单:

  • 更接近传统工作流。
  • 更容易画流程图。
  • 更容易加日志和 trace。
  • 更容易做权限控制。
  • 更容易定位是哪一步错了。
  • 更容易把专家替换成普通函数、Chain 或 Agent。

一个实用落地路径:

text 复制代码
第 1 步:先写成普通 LangGraph 流程
第 2 步:把复杂节点替换成专家 Agent
第 3 步:让 Supervisor 通过工具调用专家
第 4 步:给关键节点加结构化输出
第 5 步:接入 checkpoint 和 LangSmith 观测
第 6 步:只有在需要动态角色交接时,再引入 Swarm

这样不会一上来就陷入"多个 Agent 互相转来转去"的复杂性。

业务流程明确时,Supervisor 是更稳的默认架构;Swarm 应该在确实需要动态交接时再引入。

一张图总结:如何选择多 Agent 模式

#mermaid-svg-TFUnDuWARnjej76C{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-TFUnDuWARnjej76C .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TFUnDuWARnjej76C .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TFUnDuWARnjej76C .error-icon{fill:#552222;}#mermaid-svg-TFUnDuWARnjej76C .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TFUnDuWARnjej76C .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TFUnDuWARnjej76C .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TFUnDuWARnjej76C .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TFUnDuWARnjej76C .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TFUnDuWARnjej76C .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TFUnDuWARnjej76C .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TFUnDuWARnjej76C .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TFUnDuWARnjej76C .marker.cross{stroke:#333333;}#mermaid-svg-TFUnDuWARnjej76C svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TFUnDuWARnjej76C p{margin:0;}#mermaid-svg-TFUnDuWARnjej76C .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-TFUnDuWARnjej76C .cluster-label text{fill:#333;}#mermaid-svg-TFUnDuWARnjej76C .cluster-label span{color:#333;}#mermaid-svg-TFUnDuWARnjej76C .cluster-label span p{background-color:transparent;}#mermaid-svg-TFUnDuWARnjej76C .label text,#mermaid-svg-TFUnDuWARnjej76C span{fill:#333;color:#333;}#mermaid-svg-TFUnDuWARnjej76C .node rect,#mermaid-svg-TFUnDuWARnjej76C .node circle,#mermaid-svg-TFUnDuWARnjej76C .node ellipse,#mermaid-svg-TFUnDuWARnjej76C .node polygon,#mermaid-svg-TFUnDuWARnjej76C .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TFUnDuWARnjej76C .rough-node .label text,#mermaid-svg-TFUnDuWARnjej76C .node .label text,#mermaid-svg-TFUnDuWARnjej76C .image-shape .label,#mermaid-svg-TFUnDuWARnjej76C .icon-shape .label{text-anchor:middle;}#mermaid-svg-TFUnDuWARnjej76C .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-TFUnDuWARnjej76C .rough-node .label,#mermaid-svg-TFUnDuWARnjej76C .node .label,#mermaid-svg-TFUnDuWARnjej76C .image-shape .label,#mermaid-svg-TFUnDuWARnjej76C .icon-shape .label{text-align:center;}#mermaid-svg-TFUnDuWARnjej76C .node.clickable{cursor:pointer;}#mermaid-svg-TFUnDuWARnjej76C .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-TFUnDuWARnjej76C .arrowheadPath{fill:#333333;}#mermaid-svg-TFUnDuWARnjej76C .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-TFUnDuWARnjej76C .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-TFUnDuWARnjej76C .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TFUnDuWARnjej76C .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-TFUnDuWARnjej76C .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TFUnDuWARnjej76C .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-TFUnDuWARnjej76C .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-TFUnDuWARnjej76C .cluster text{fill:#333;}#mermaid-svg-TFUnDuWARnjej76C .cluster span{color:#333;}#mermaid-svg-TFUnDuWARnjej76C div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-TFUnDuWARnjej76C .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-TFUnDuWARnjej76C rect.text{fill:none;stroke-width:0;}#mermaid-svg-TFUnDuWARnjej76C .icon-shape,#mermaid-svg-TFUnDuWARnjej76C .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TFUnDuWARnjej76C .icon-shape p,#mermaid-svg-TFUnDuWARnjej76C .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-TFUnDuWARnjej76C .icon-shape .label rect,#mermaid-svg-TFUnDuWARnjej76C .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TFUnDuWARnjej76C .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-TFUnDuWARnjej76C .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-TFUnDuWARnjej76C :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否







任务是否真的需要多 Agent?
使用 Chain 或单 Agent
流程是否稳定可描述?
优先 Supervisor
是否需要角色动态交接?
考虑 Swarm
考虑 Router / Custom LangGraph
是否需要并行专家?
Supervisor + 并行子任务
Supervisor + 顺序工具调用
Swarm + checkpointer + handoff 摘要

这张图背后的判断标准是:

  • 不复杂就不要多 Agent。
  • 流程稳定先用 Supervisor。
  • 路径开放、角色动态交接再用 Swarm。
  • 多 Agent 里的路由、审批、合成尽量结构化。
  • 上下文越复杂,越要严格控制每个 Agent 能看到什么。

总结

本文对比了两种多 Agent 协作模式。

需要记住这些结论:

  • 多 Agent 的核心价值是上下文管理、职责边界、并行化和团队协作。
  • Supervisor 是中心化调度模式,适合稳定流程、结果合成、强观测场景。
  • Swarm 是动态 handoff 模式,适合多角色连续对话和开放式任务推进。
  • Supervisor 可以把专家 Agent 包装成工具,由主 Agent 统一调用。
  • Swarm 的关键是 handoff tool,它会更新状态并转移控制权。
  • 日报、报告、代码审查这类稳定流程,通常优先选 Supervisor。
  • 客服转接、教学角色切换、开放式工作台这类动态场景,可以考虑 Swarm。
  • 不要为了多 Agent 而多 Agent,能用 Chain 或单 Agent 解决就不要拆。
  • 多 Agent 的质量取决于上下文工程,而不是 Agent 数量。
  • 所有循环交接都要有退出条件。