Skip to content

12.2 多智能体工作流复杂案例

在上一节中,我们了解了多智能体系统的基本概念。本节将深入探讨 Supervisor 模式的高级用法,通过一个内容创作团队的完整案例,展示如何构建企业级的多智能体协作系统。


为什么需要复杂的多智能体架构?

当你的 AI 应用场景变得复杂时,简单的单 Agent 方案往往力不从心:

挑战表现解决思路
决策复杂度高需要综合判断、权衡利弊专业 Agent 各司其职,协同决策
规则维护困难规则多且易冲突、更新成本高分解到不同 Agent,降低耦合
依赖非结构化数据需要理解文档、对话等专门的信息提取与处理 Agent

核心洞察:复杂任务的关键不在于单个模型有多强大,而在于如何让多个专业 Agent 高效协作。


Supervisor 模式核心机制

Supervisor 模式的核心思想是中央调度——由一个"总指挥"来协调各个专业 Agent 的工作。

运作流程

┌──────────────────────────────────────────────────────────┐
│                      用户请求                             │
│                         ↓                                │
│                   ┌─────────┐                            │
│                   │Supervisor│ ← 分析意图、分配任务        │
│                   └────┬────┘                            │
│          ┌─────────────┼─────────────┐                   │
│          ↓             ↓             ↓                   │
│    ┌─────────┐   ┌─────────┐   ┌─────────┐              │
│    │ Agent A │   │ Agent B │   │ Agent C │              │
│    └────┬────┘   └────┬────┘   └────┬────┘              │
│          ↓             ↓             ↓                   │
│                   ┌─────────┐                            │
│                   │Supervisor│ ← 汇总结果、反馈用户        │
│                   └─────────┘                            │
└──────────────────────────────────────────────────────────┘

与 Swarm 模式的核心差异

特性Supervisor 模式Swarm 模式
控制方式集中式,Supervisor 统筹去中心化,Agent 自主交接
用户交互主要通过 Supervisor可与任意 Agent 直接交互
执行流程任务完成后返回 SupervisorAgent 之间直接传递控制权
起始节点固定为 Supervisor可配置默认 Agent
通信路径必经 SupervisorAgent 点对点通信
最佳场景流程明确、需要监控灵活对话、专家轮换

完整实现:内容创作团队

下面我们构建一个智能内容创作系统,包含:

  • 调研专员:负责搜索资料、收集信息
  • 数据分析师:负责数据计算和统计分析
  • 总编辑(Supervisor):协调团队、整合输出

环境准备

bash
pip install langgraph-supervisor langchain-openai langchain-community
python
import os
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
from langgraph_supervisor import create_supervisor
from langchain_community.tools.tavily_search import TavilySearchResults

# 配置 LLM
llm = ChatOpenAI(
    model="gpt-4o",
    api_key=os.getenv("OPENAI_API_KEY")
)

定义工具集

python
# 数据分析工具
def calculate_sum(numbers: list[float]) -> float:
    """对一组数字求和"""
    return sum(numbers)

def calculate_average(numbers: list[float]) -> float:
    """计算平均值"""
    return sum(numbers) / len(numbers) if numbers else 0

def calculate_percentage(part: float, total: float) -> float:
    """计算百分比"""
    return (part / total * 100) if total != 0 else 0

# 搜索工具
search_tool = TavilySearchResults(
    max_results=3,
    tavily_api_key=os.getenv("TAVILY_API_KEY")
)

创建专业 Agent

python
# 调研专员 Agent
researcher = create_react_agent(
    model=llm,
    tools=[search_tool],
    name="research_specialist",
    prompt="""你是一名专业的信息调研员。

职责范围:
- 执行网络搜索,收集相关资料
- 整理并提炼关键信息
- 不要进行任何数学计算

工作规范:
- 完成调研后,将结果直接汇报给总编辑
- 只返回调研结果,不要添加无关内容"""
)

# 数据分析师 Agent
analyst = create_react_agent(
    model=llm,
    tools=[calculate_sum, calculate_average, calculate_percentage],
    name="data_analyst",
    prompt="""你是一名专业的数据分析师。

职责范围:
- 执行数学计算和统计分析
- 处理数值型数据
- 不要进行网络搜索

工作规范:
- 完成分析后,将结果直接汇报给总编辑
- 只返回计算结果和分析结论"""
)

创建 Supervisor

python
# 总编辑(Supervisor)
editor_in_chief = create_supervisor(
    model=llm,
    agents=[researcher, analyst],
    prompt="""你是内容创作团队的总编辑,负责协调以下成员:
- research_specialist:负责信息搜索和资料收集
- data_analyst:负责数据计算和统计分析

工作原则:
1. 分析用户请求,判断需要调用哪个专家
2. 一次只分配任务给一个专家,避免并行调用
3. 自己不执行具体任务,只负责协调和汇总
4. 复杂请求可能需要多轮协调(先调研、再分析)""",
    add_handoff_back_messages=True,
    output_mode="full_history"
).compile()

测试运行

python
def run_creative_task(query: str):
    """执行创作任务"""
    print(f"📝 任务: {query}")
    print("-" * 60)

    for chunk in editor_in_chief.stream(
        {"messages": [{"role": "user", "content": query}]},
        subgraphs=False
    ):
        for node_name, node_data in chunk.items():
            if "messages" in node_data:
                last_msg = node_data["messages"][-1]
                print(f"[{node_name}] {last_msg.content[:200]}...")

    print("=" * 60)

# 示例:综合性请求
run_creative_task(
    "帮我调研一下2024年中国新能源汽车市场的销量数据,"
    "然后计算前三大品牌的市场份额占比"
)

执行流程

  1. 总编辑接收请求,判断需要先调研
  2. 分配给 research_specialist 搜索市场数据
  3. 调研完成后,任务返回总编辑
  4. 总编辑将数据分配给 data_analyst 计算份额
  5. 分析完成后,总编辑汇总并回复用户

消息历史管理策略

在多 Agent 协作中,如何管理对话历史至关重要。LangGraph 提供了两种策略:

完整历史模式

保留 Agent 执行过程中的所有消息,适合需要追溯和调试的场景:

python
supervisor = create_supervisor(
    agents=[researcher, analyst],
    output_mode="full_history"  # 保留完整对话历史
)

消息流示例

Human → Supervisor → [Tool: transfer_to_researcher] → Researcher
→ [搜索过程...] → [Tool: transfer_back] → Supervisor
→ [Tool: transfer_to_analyst] → Analyst → [计算过程...]
→ [Tool: transfer_back] → Supervisor → 最终回复

精简结果模式

只保留每个 Agent 的最终输出,适合需要简洁上下文的场景:

python
supervisor = create_supervisor(
    agents=[researcher, analyst],
    output_mode="last_message"  # 只保留最后一条消息
)

消息流示例

Human → Supervisor → Researcher最终结果 → Analyst最终结果 → 最终回复

如何选择?

场景推荐模式理由
开发调试阶段full_history便于追踪问题
上下文敏感任务full_historyAgent 需要了解前序工作
简单独立任务last_message减少 token 消耗
长对话场景last_message避免上下文溢出

多层级架构设计

当系统规模扩大时,可以构建层级式的 Supervisor 结构:

                    ┌────────────────┐
                    │  总编辑(顶层) │
                    └───────┬────────┘
              ┌─────────────┼─────────────┐
              ↓             ↓             ↓
      ┌───────────┐  ┌───────────┐  ┌───────────┐
      │ 调研组长  │  │ 分析组长  │  │ 创作组长  │
      └─────┬─────┘  └─────┬─────┘  └─────┬─────┘
            │              │              │
      ┌─────┴─────┐  ┌─────┴─────┐  ┌─────┴─────┐
      │ 搜索专员  │  │ 统计专员  │  │ 文案专员  │
      │ 整理专员  │  │ 可视化专员│  │ 校对专员  │
      └───────────┘  └───────────┘  └───────────┘

实现多层级 Supervisor

python
# 第一层:创建各组的 Supervisor
research_team = create_supervisor(
    [search_agent, organize_agent],
    model=llm,
    supervisor_name="research_lead"
).compile(name="research_team")

analysis_team = create_supervisor(
    [stats_agent, viz_agent],
    model=llm,
    supervisor_name="analysis_lead"
).compile(name="analysis_team")

# 第二层:顶层 Supervisor 管理各组
top_supervisor = create_supervisor(
    [research_team, analysis_team],
    model=llm,
    supervisor_name="editor_in_chief"
).compile(name="content_team")

优势

  • ✅ 职责清晰,易于维护
  • ✅ 可独立扩展各团队
  • ✅ 支持更复杂的协作流程

自定义任务交接机制

默认的 handoff 工具可能无法满足特定需求,你可以创建自定义版本:

基础自定义

python
from langgraph_supervisor import create_handoff_tool

# 自定义工具名称和描述
custom_tools = [
    create_handoff_tool(
        agent_name="research_specialist",
        name="assign_research_task",
        description="将调研类任务分配给调研专员,包括信息搜索、资料整理等"
    ),
    create_handoff_tool(
        agent_name="data_analyst",
        name="assign_analysis_task",
        description="将数据分析任务分配给分析师,包括计算、统计、对比等"
    )
]

supervisor = create_supervisor(
    [researcher, analyst],
    model=llm,
    tools=custom_tools  # 使用自定义工具
)

高级自定义:带参数的交接

python
from typing import Annotated
from langchain_core.tools import tool, InjectedToolCallId
from langgraph.prebuilt import InjectedState
from langgraph.types import Command
from langgraph.graph import MessagesState

def create_task_handoff(agent_name: str, description: str):
    """创建带任务描述的交接工具"""

    @tool(f"delegate_to_{agent_name}", description=description)
    def handoff_with_context(
        task_description: str,  # LLM 填写的任务描述
        priority: str = "normal",  # 任务优先级
        state: Annotated[MessagesState, InjectedState] = None,
        tool_call_id: Annotated[str, InjectedToolCallId] = None
    ) -> Command:
        """
        将任务交接给指定 Agent。

        Args:
            task_description: 具体任务说明
            priority: 任务优先级 (high/normal/low)
        """
        # 构建交接消息
        handoff_msg = {
            "role": "tool",
            "content": f"任务已分配给 {agent_name}\n"
                      f"任务说明: {task_description}\n"
                      f"优先级: {priority}",
            "name": f"delegate_to_{agent_name}",
            "tool_call_id": tool_call_id
        }

        return Command(
            goto=agent_name,
            update={
                **state,
                "messages": state["messages"] + [handoff_msg],
                "current_task": task_description,
                "task_priority": priority
            },
            graph=Command.PARENT
        )

    return handoff_with_context

控制交接消息显示

python
# 不显示交接过程的系统消息
supervisor = create_supervisor(
    [researcher, analyst],
    model=llm,
    add_handoff_messages=False  # 隐藏交接消息
)

# 自定义交接工具前缀
supervisor = create_supervisor(
    [researcher, analyst],
    model=llm,
    handoff_tool_prefix="assign_to"  # 工具名变为 assign_to_xxx
)

消息转发优化

有时 Supervisor 不需要对 Agent 的回复做额外处理,可以直接转发给用户:

python
from langgraph_supervisor.handoff import create_forward_message_tool

# 创建转发工具
forward_tool = create_forward_message_tool("editor_in_chief")

supervisor = create_supervisor(
    [researcher, analyst],
    model=llm,
    tools=[forward_tool]  # 添加转发能力
)

使用场景

  • Agent 输出已经足够完整,无需 Supervisor 润色
  • 减少 Supervisor 的额外处理,降低延迟
  • 避免信息在转述过程中失真

Swarm 模式对比实现

为了理解 Supervisor 与 Swarm 的区别,我们用 Swarm 模式实现同样的系统:

python
from langgraph_swarm import create_swarm, create_handoff_tool

# Swarm 模式下,每个 Agent 需要持有交接工具
handoff_to_analyst = create_handoff_tool(
    agent_name="data_analyst",
    description="当需要数据计算时,转交给数据分析师"
)

handoff_to_researcher = create_handoff_tool(
    agent_name="research_specialist",
    description="当需要搜索资料时,转交给调研专员"
)

# 重新创建带有交接能力的 Agent
researcher_swarm = create_react_agent(
    model=llm,
    tools=[search_tool, handoff_to_analyst],  # 可以转交给分析师
    name="research_specialist",
    prompt="你是调研专员。完成调研后,如需数据分析,转交给分析师。"
)

analyst_swarm = create_react_agent(
    model=llm,
    tools=[calculate_sum, calculate_average, handoff_to_researcher],
    name="data_analyst",
    prompt="你是数据分析师。如需补充资料,转交给调研专员。"
)

# 创建 Swarm
swarm_team = create_swarm(
    agents=[researcher_swarm, analyst_swarm],
    default_active_agent="research_specialist"  # 默认从调研开始
).compile()

对比总结

维度Supervisor 实现Swarm 实现
代码复杂度较简单,集中配置需要为每个 Agent 配置交接工具
流程可控性高,Supervisor 把关低,Agent 自主决策
调试难度低,有明确的中心节点高,需要追踪 Agent 切换链
灵活性中等高,支持任意 Agent 间协作
适用场景流程驱动的任务对话驱动的交互

Agent 执行控制

调用模式

python
# 同步调用 - 等待完成
result = supervisor.invoke(
    {"messages": [{"role": "user", "content": "查询今年销售数据"}]}
)

# 异步调用 - 非阻塞
result = await supervisor.ainvoke(
    {"messages": [{"role": "user", "content": "查询今年销售数据"}]}
)

# 流式输出 - 实时反馈
for chunk in supervisor.stream(
    {"messages": [{"role": "user", "content": "查询今年销售数据"}]},
    stream_mode="updates"
):
    print(chunk)

迭代次数限制

防止 Agent 陷入无限循环:

python
from langgraph.errors import GraphRecursionError

max_rounds = 5
recursion_limit = 2 * max_rounds + 1

try:
    result = supervisor.invoke(
        {"messages": [{"role": "user", "content": query}]},
        {"recursion_limit": recursion_limit}
    )
except GraphRecursionError:
    print("⚠️ 达到最大迭代次数,请简化任务或检查 Agent 配置")

实战建议

1. Agent 命名与描述

python
# ❌ 模糊的描述
@tool("helper", description="帮助处理事情")
def bad_agent(): ...

# ✅ 清晰的描述
@tool(
    "market_researcher",
    description="专门负责市场调研,包括:竞品分析、行业趋势、用户画像。"
                "适用于需要外部市场信息的请求。"
)
def good_agent(): ...

2. 渐进式复杂度

阶段建议方案
验证想法单 Agent + 少量工具
初步生产Supervisor + 2-3 专业 Agent
规模化层级式多智能体架构

3. 常见问题排查

问题可能原因解决方案
Supervisor 不调用 Agent工具描述不清晰优化 Agent 工具的 description
Agent 执行错误任务职责边界模糊明确每个 Agent 的 prompt
无限循环缺少终止条件设置 recursion_limit
上下文丢失使用了 last_message 模式改用 full_history 模式

小结

本节我们深入学习了 Supervisor 模式的高级用法:

  • 核心机制:中央调度、专业分工
  • 消息管理:完整历史 vs 精简结果
  • 层级架构:支持大规模团队协作
  • 自定义交接:灵活控制任务流转
  • 模式对比:Supervisor vs Swarm 的适用场景

核心要点:多智能体系统的关键在于职责清晰协作顺畅。Supervisor 模式提供了一种结构化的方式来组织 Agent 团队,特别适合流程明确、需要监控的业务场景。


下一节预告:我们将探讨 Agentic RAG——如何让 Agent 更智能地检索和利用知识库。

基于 MIT 许可证发布。内容版权归作者所有。