分而治之——Supervisor 多 Agent 模式与子图 — LangGraph 实战——构建跨平台爆款图文 Agent 第6篇

第6章:分而治之——Supervisor 多 Agent 模式与子图

本章目标

读完本章你会:

  • 能解释为什么单个巨型 Agent 不如多个专业 Agent 协作
  • 能用 Supervisor 模式 设计一个中央调度器 + N 个专业子 Agent 的架构
  • 能用子图(Subgraph) 把独立 Agent 封装为可复用的图模块
  • 能处理好父图与子图之间的 State 共享
  • 能将 LocalTrend 拆分为 Researcher → Analyst → Writer → Publisher 四角色协作系统

知识讲解

从一个生活例子开始

一支交响乐团正在演奏。台上没有一个人包办所有乐器——指挥站在中央,弦乐组在左边,管乐组在右边,打击乐组在后面。

指挥的工作不是自己拉小提琴或吹长号。他的工作是:

  1. 读懂总谱,知道每个乐器组在什么时候该干什么
  2. 给弦乐组一个手势——"你们进"
  3. 听弦乐组的表现,决定"够了,管乐组接上"
  4. 调整各组的强弱、速度、情绪

每个乐器组内部有自己的协作方式——弦乐组的首席小提琴会协调组内弓法。指挥不需要关心这些细节——他只管"弦乐组,第三乐章,起"。

这就是 Supervisor 多 Agent 模式:

交响乐团 LangGraph
指挥 Supervisor Agent——中央调度器,决定"下一个该谁"
弦乐组 Researcher Agent——一个独立的子图,负责搜索和收集
管乐组 Analyst Agent——分析搜索结果,提炼规律
打击乐组 Writer Agent——根据分析结果撰写内容
总谱 共享 State——所有子 Agent 读写同一份状态

关键洞察:指挥不需要会吹长号,Researcher 不需要会写文章。 每个子 Agent 只做自己擅长的事,Supervisor 负责把它们串成一个完整的作品。

工作原理

为什么需要多 Agent?

看看你现在的 LocalTrend——第 5 章的 build_multi_platform_graph() 把所有逻辑塞在一个图里:搜索、分析、生成、审核全混在一起。随着功能增长:

  • State 膨胀platform_reportsgenerated_contentreview_decisionpublished……20 多个字段,没人记得住
  • 节点膨胀:10+ 个节点,每个节点要理解整个 State 的上下文
  • 修改困难:想给"搜索"加个重试逻辑?你得在图中间插入新节点和边——牵一发动全身

多 Agent 架构解决的就是这个问题:把大图拆成小图,每个小图只关心自己领域的状态子集。

Supervisor 模式的结构

                        ┌─────────────┐
                        │  Supervisor │  ← 中央调度器(路由 Agent)
                        └──┬──┬──┬───┘
                           │  │  │
              ┌────────────┘  │  └────────────┐
              ↓               ↓               ↓
        ┌──────────┐  ┌──────────┐  ┌──────────────┐
        │Researcher│  │ Analyst  │  │    Writer    │  ← 专业子 Agent
        │ (子图)   │  │ (子图)   │  │   (子图)     │    每个是独立编译的图
        └──────────┘  └──────────┘  └──────────────┘
              ↓               ↓               ↓
              └───────────────┴───────────────┘
                              ↓
                    共享 State(所有子图读写同一份)

Supervisor 本身通常是一个带 LLM 的路由节点——它分析当前 State,决定"下一步该调用哪个子 Agent"。它的路由函数类似:

def supervisor_router(state) -> str:
    # 检查当前进度,决定下一步
    if 还没搜索 → "researcher"
    elif 搜索完了还没分析 → "analyst"
    elif 分析完了还没写 → "writer"
    elif 写完了还没发布 → "publisher"
    else → END

子图与父图的 State 关系

这是一个容易踩坑的地方。LangGraph 中子图和父图的 State 处理规则:

  1. 子图必须使用与父图相同的 State schema——至少包含父图 State 中它需要读写的字段
  2. 子图可以直接读取和修改共享 State——子图的节点就像父图节点一样读写 State
  3. 子图内部的状态变更在子图完成后才对父图可见——子图执行期间,父图看到的是子图开始前的快照

⚠️ 常见坑:初学者容易给子图定义一个"精简版"State(只包含自己需要的字段),然后发现父图传给子图时丢失了其他字段。解决方式:所有子图使用和父图完全相同的 State 类,或确保子图 State 是父图 State 的完整超集。

思考一下: 如果 Researcher 子图在搜索时改了 messages,Analyst 子图能看到这些消息吗?能——因为它们共享同一个 State。那为什么还要用子图?因为子图把"搜索相关的节点和边"封装成一个可理解的单元——Analyst 不需要知道 Researcher 内部有几个节点、怎么路由的,只需要知道"Researcher 会在 messages 里追加搜索结果"。


代码实战

基础版:两子 Agent + Supervisor 的最简模式

先从最简单的 Supervisor 开始——一个 MathAgent 做计算,一个 TextAgent 做文本处理,Supervisor 判断该找谁。新建文件 chapter06_supervisor_basics.py

"""
第 6 章 基础演示:Supervisor 多 Agent 最简模式
一个 Supervisor 调度两个子 Agent——MathAgent 和 TextAgent
"""
from typing import TypedDict, Annotated, Literal
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.checkpoint.memory import MemorySaver

from langchain_core.messages import HumanMessage, AIMessage
from langchain_openai import ChatOpenAI
import os


# ============================================================
# 共享 State——所有子图 + 父图使用同一个 schema
# ============================================================
class TeamState(TypedDict):
    messages: Annotated[list, add_messages]
    next_agent: str     # Supervisor 决定下一个调谁
    task_done: bool     # 任务完成标记


# ============================================================
# 子图 1:MathAgent——一个独立的 StateGraph
# ============================================================
def create_math_agent():
    """处理数学计算的专业 Agent。对外部来说它就是一个黑盒节点。"""

    def math_solver(state: TeamState) -> dict:
        """计算节点——内部可能有 own LLM 调用、工具调用等复杂逻辑"""
        last_msg = state["messages"][-1]
        content = last_msg.content if hasattr(last_msg, "content") else str(last_msg)

        # 模拟数学计算(实际项目这里会调 LLM + 计算器工具)
        print(f"  [MathAgent] 处理计算请求: {content[:60]}")

        # 简单计算演示
        result = "计算结果:根据数据,线性回归斜率约为 2.35,R² = 0.87。"
        return {
            "messages": [AIMessage(content=f" MathAgent: {result}")],
            "task_done": True,
        }

    builder = StateGraph(TeamState)
    builder.add_node("math_solver", math_solver)
    builder.add_edge(START, "math_solver")
    builder.add_edge("math_solver", END)
    return builder.compile()


# ============================================================
# 子图 2:TextAgent——另一个独立 StateGraph
# ============================================================
def create_text_agent():
    """处理文本分析的专业 Agent"""

    def text_analyzer(state: TeamState) -> dict:
        last_msg = state["messages"][-1]
        content = last_msg.content if hasattr(last_msg, "content") else str(last_msg)
        print(f"  [TextAgent] 处理文本请求: {content[:60]}")

        result = "文本分析结果:该段落的情感倾向为正面(置信度 0.92),关键词包括'增长'、'创新'、'突破'。"
        return {
            "messages": [AIMessage(content=f" TextAgent: {result}")],
            "task_done": True,
        }

    builder = StateGraph(TeamState)
    builder.add_node("text_analyzer", text_analyzer)
    builder.add_edge(START, "text_analyzer")
    builder.add_edge("text_analyzer", END)
    return builder.compile()


# ============================================================
# 父图:Supervisor + 子图
# ============================================================
def build_supervisor_graph():
    builder = StateGraph(TeamState)

    #  把编译好的子图作为节点注册到父图中
    builder.add_node("math_agent", create_math_agent())
    builder.add_node("text_agent", create_text_agent())

    #  Supervisor 节点——用 LLM 决定路由
    llm = ChatOpenAI(
        model="deepseek-chat",
        api_key=os.getenv("DEEPSEEK_API_KEY", "your-api-key-here"),
        base_url="https://api.deepseek.com",
        temperature=0,
    )

    def supervisor(state: TeamState) -> dict:
        """中央调度器:分析请求,决定调哪个 Agent"""
        last_msg = state["messages"][-1]
        content = last_msg.content if hasattr(last_msg, "content") else str(last_msg)

        print(f"\n[Supervisor] 分析请求: {content[:80]}")

        # 让 LLM 判断该找谁
        response = llm.invoke([
            HumanMessage(content=(
                f"用户的请求是:\n{content}\n\n"
                f"你需要决定调用哪个 Agent:\n"
                f"- 如果请求涉及数学计算、数据分析、数值统计 → 回复 'math'\n"
                f"- 如果请求涉及文本分析、情感分析、关键词提取 → 回复 'text'\n"
                f"- 如果已经处理完了 → 回复 'done'\n\n"
                f"只回复一个词: math 或 text 或 done。"
            ))
        ])

        choice = response.content.strip().lower()
        print(f"  ↳ Supervisor 决策: {choice}")
        return {"next_agent": choice}

    def supervisor_router(state: TeamState) -> Literal["math_agent", "text_agent", "__end__"]:
        """条件路由:根据 supervisor 的决策分发"""
        choice = state.get("next_agent", "")
        if choice == "math":
            return "math_agent"
        elif choice == "text":
            return "text_agent"
        return END

    builder.add_node("supervisor", supervisor)

    builder.add_edge(START, "supervisor")

    #  条件路由到不同子图
    builder.add_conditional_edges(
        "supervisor", supervisor_router,
        {"math_agent": "math_agent", "text_agent": "text_agent", END: END}
    )

    #  子图完成后回到 supervisor,让它决定"下一步"
    builder.add_edge("math_agent", "supervisor")
    builder.add_edge("text_agent", "supervisor")

    return builder.compile()


# ============================================================
# 运行
# ============================================================
if __name__ == "__main__":
    graph = build_supervisor_graph()

    print("=" * 60)
    print("测试 1:数学问题")
    print("=" * 60)
    result = graph.invoke({
        "messages": [HumanMessage(content="帮我分析这组数据: [12, 18, 25, 33, 41],拟合线性回归")],
        "next_agent": "",
        "task_done": False,
    })
    # 打印所有消息,观察 MathAgent 和 TextAgent 各被调了几次
    for msg in result["messages"]:
        role = type(msg).__name__
        content = str(msg.content)[:80]
        print(f"  [{role}] {content}")

    print("\n" + "=" * 60)
    print("测试 2:文本问题")
    print("=" * 60)
    result2 = graph.invoke({
        "messages": [HumanMessage(content="分析这段文字的情感:产品增长迅猛,用户反馈积极。")],
        "next_agent": "",
        "task_done": False,
    })
    for msg in result2["messages"]:
        print(f"  [{type(msg).__name__}] {str(msg.content)[:80]}")

逐行解析

builder.add_node("math_agent", create_math_agent())

这就是子图的关键用法。create_math_agent() 返回一个 compile() 过的图对象——这个对象可以像普通节点函数一样被 add_node 注册。当 Supervisor 路由到 "math_agent" 时,LangGraph 会把整个子图作为一个"超级节点"来执行:START → math_solver → END,然后返回到父图的边。

子图和父图使用相同的 State 类 (TeamState)

这是 State 兼容性的保证。子图的所有节点都读写 TeamState,和父图共享同一份数据。MathAgentmessages 里追加的内容,TextAgentSupervisor 都能看到。

子图完成后回到 Supervisor

builder.add_edge("math_agent", "supervisor")builder.add_edge("text_agent", "supervisor") 是关键设计——每个子 Agent 完成工作后,控制权交回 Supervisor。Supervisor 再次评估当前 State,决定"下一步"——可能调用另一个 Agent,也可能结束。

这形成了一个循环:Supervisor → 子 Agent → Supervisor → 子 Agent → ... → END。 不同于第 2 章的 Agent ↔ Tool 循环,这里的循环粒度更大——每次循环是一个完整的子任务,而非单个工具调用。

扩展版:LocalTrend 四 Agent 团队

现在把 LocalTrend 正式升级为多 Agent 架构。四个专业子 Agent:

  • Researcher:接收话题,搜索平台趋势
  • Analyst:分析搜索结果,提炼爆款规律
  • Writer:基于规律撰写爆款内容
  • Publisher:审核(interrupt)并发布

新建文件 chapter06_localtrend_team.py

"""
第 6 章 扩展演示:LocalTrend 多 Agent 团队
Researcher → Analyst → Writer → Publisher 四角色协作
"""
import os
import sqlite3
from typing import TypedDict, Annotated, Literal
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.checkpoint.sqlite import SqliteSaver
from langgraph.types import interrupt, Command

from langchain_core.messages import HumanMessage, AIMessage, ToolMessage
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI


# ============================================================
# 配置
# ============================================================
llm = ChatOpenAI(
    model="deepseek-chat",
    api_key=os.getenv("DEEPSEEK_API_KEY", "your-api-key-here"),
    base_url="https://api.deepseek.com",
    temperature=0.7,
)


# ============================================================
# 共享 State——所有子 Agent 使用此 schema
# ============================================================
class TeamState(TypedDict):
    # 消息历史(所有 Agent 共享)
    messages: Annotated[list, add_messages]

    # Supervisor 控制
    next_agent: str

    # Researcher 产出
    research_results: str

    # Analyst 产出
    trend_patterns: str

    # Writer 产出
    generated_content: str

    # Publisher 状态
    review_decision: str
    review_feedback: str
    published: bool


# ============================================================
# 工具(仅 Researcher 使用)
# ============================================================
@tool
def search_trending(topic: str) -> str:
    """搜索热门话题趋势"""
    print(f"     [工具] 搜索: {topic}")
    knowledge = {
        "AI": "AI爆款:Agent开发(CTR 12%)、RAG实战(完读率45%)、LLM应用架构(收藏率高)。标题公式:'从零'/'实战'/'2026最新'。",
        "职场": "职场爆款:'AI时代核心竞争力'(情绪共鸣强)、'副业月入复盘'(转化率高)、'中年转型'(评论互动多)。",
    }
    for key, val in knowledge.items():
        if key in topic:
            return val
    return f"关于'{topic}'的趋势分析数据。"


# ============================================================
# 子图 1: Researcher Agent
# ============================================================
def create_researcher():
    """搜索 Agent——负责搜索和收集原始数据"""
    llm_with_tools = llm.bind_tools([search_trending])

    def research_node(state: TeamState) -> dict:
        print("\n   [Researcher] 开始搜索趋势...")

        # 从消息历史中提取用户的原始话题
        user_requests = [
            m for m in state["messages"]
            if isinstance(m, HumanMessage)
        ]
        topic = user_requests[-1].content if user_requests else "AI"

        response = llm_with_tools.invoke([
            HumanMessage(content=f"搜索'{topic}'的爆款趋势。使用搜索工具。")
        ])

        results = []
        if hasattr(response, "tool_calls") and response.tool_calls:
            for tc in response.tool_calls:
                result = search_trending.invoke(tc["args"])
                results.append(result)

        research_summary = "\n".join(results) if results else response.content
        print(f"  ✅ [Researcher] 完成,收集到 {len(results)} 条结果")
        return {
            "messages": [response],
            "research_results": research_summary,
        }

    builder = StateGraph(TeamState)
    builder.add_node("research_node", research_node)
    builder.add_edge(START, "research_node")
    builder.add_edge("research_node", END)
    return builder.compile()


# ============================================================
# 子图 2: Analyst Agent
# ============================================================
def create_analyst():
    """分析 Agent——从原始数据中提炼爆款规律"""

    def analyze_node(state: TeamState) -> dict:
        print("\n   [Analyst] 分析搜索结果,提炼规律...")

        research = state.get("research_results", "")
        if not research:
            research = "无搜索结果"

        response = llm.invoke([
            HumanMessage(content=(
                f"基于以下搜索数据,提炼 3 条跨平台爆款规律:\n\n{research}\n\n"
                f"每条规律包含:标题模式、内容结构、互动设计"
            ))
        ])

        print(f"  ✅ [Analyst] 分析完成")
        return {
            "messages": [AIMessage(content=f" 分析结果:\n{response.content}")],
            "trend_patterns": response.content,
        }

    builder = StateGraph(TeamState)
    builder.add_node("analyze_node", analyze_node)
    builder.add_edge(START, "analyze_node")
    builder.add_edge("analyze_node", END)
    return builder.compile()


# ============================================================
# 子图 3: Writer Agent
# ============================================================
def create_writer():
    """写作 Agent——根据规律生成爆款内容"""

    def write_node(state: TeamState) -> dict:
        print("\n  ✍️ [Writer] 基于规律撰写内容...")

        patterns = state.get("trend_patterns", "")
        if not patterns:
            patterns = "通用爆款规律:痛点切入+分点论述+案例支撑+互动引导"

        # 如果有驳回意见,加入上下文
        feedback = state.get("review_feedback", "")
        feedback_context = f"上一版被驳回,意见:{feedback}。请根据意见改进。" if feedback else ""

        response = llm.invoke([
            HumanMessage(content=(
                f"根据以下爆款规律,为微信公众号撰写一篇 200 字的短文:\n\n{patterns}\n\n"
                f"{feedback_context}\n"
                f"要求:标题含数字+情感词、开头痛点切入、结尾互动引导。"
            ))
        ])

        print(f"  ✅ [Writer] 内容生成完成({len(response.content)} 字)")
        return {
            "messages": [AIMessage(content=f"✍️ 生成内容:\n{response.content}")],
            "generated_content": response.content,
            "review_feedback": "",  # 清除旧驳回意见
        }

    builder = StateGraph(TeamState)
    builder.add_node("write_node", write_node)
    builder.add_edge(START, "write_node")
    builder.add_edge("write_node", END)
    return builder.compile()


# ============================================================
# 子图 4: Publisher Agent
# ============================================================
def create_publisher():
    """发布 Agent——审核+发布(含 Human-in-the-Loop)"""

    def review_node(state: TeamState) -> dict:
        print("\n   [Publisher] 内容审核...")

        content = state.get("generated_content", "")
        print(f"  {'='*50}")
        print(f"  {content[:200]}")
        print(f"  {'='*50}")

        decision = interrupt("请审核:approve(批准) / 输入修改意见")

        if decision.lower() in ("approve", "批准"):
            print("  ✅ 审核通过,准备发布")
            return {
                "review_decision": "approved",
                "published": True,
            }
        else:
            print(f"  ❌ 驳回,意见: {decision}")
            return {
                "review_decision": "rejected",
                "review_feedback": decision,
                "published": False,
            }

    builder = StateGraph(TeamState)
    builder.add_node("review_node", review_node)
    builder.add_edge(START, "review_node")
    builder.add_edge("review_node", END)
    return builder.compile()


# ============================================================
# 父图:Supervisor + 四个子 Agent
# ============================================================

def build_localtrend_team(db_path="localtrend_team.db"):
    builder = StateGraph(TeamState)

    #  注册四个子图
    builder.add_node("researcher", create_researcher())
    builder.add_node("analyst", create_analyst())
    builder.add_node("writer", create_writer())
    builder.add_node("publisher", create_publisher())

    # Supervisor 节点
    supervisor_llm = ChatOpenAI(
        model="deepseek-chat",
        api_key=os.getenv("DEEPSEEK_API_KEY", "your-api-key-here"),
        base_url="https://api.deepseek.com",
        temperature=0,
    )

    def supervisor(state: TeamState) -> dict:
        """中央调度器:根据当前进度决定下一步"""
        research = state.get("research_results", "")
        patterns = state.get("trend_patterns", "")
        content = state.get("generated_content", "")
        published = state.get("published", False)

        # 构建状态摘要给 LLM
        status = f"""
当前任务进度:
- 搜索完成: {'是' if research else '否'}
- 分析完成: {'是' if patterns else '否'}
- 内容生成: {'是' if content else '否'}
- 已发布: {'是' if published else '否'}
- 最近驳回意见: {state.get('review_feedback', '无')}

请决定下一步调用哪个 Agent:
- 搜索未完成 → researcher
- 搜索完成、分析未完成 → analyst
- 分析完成、内容未生成 → writer
- 内容生成但驳回(review_feedback 非空)→ writer(重写)
- 内容生成且有驳回意见 → writer(根据意见重写)
- 内容生成且审核通过 → finish
- 内容生成但未审核 → publisher
"""
        response = supervisor_llm.invoke([
            HumanMessage(content=(
                f"{status}\n只回复一个词: researcher / analyst / writer / publisher / finish"
            ))
        ])
        choice = response.content.strip().lower()
        print(f"\n [Supervisor] → {choice}")
        return {"next_agent": choice}

    def supervisor_router(state: TeamState) -> Literal[
        "researcher", "analyst", "writer", "publisher", "__end__"
    ]:
        choice = state.get("next_agent", "")
        if choice == "researcher":
            return "researcher"
        elif choice == "analyst":
            return "analyst"
        elif choice == "writer":
            return "writer"
        elif choice == "publisher":
            return "publisher"
        return END

    builder.add_node("supervisor", supervisor)
    builder.add_edge(START, "supervisor")

    builder.add_conditional_edges(
        "supervisor", supervisor_router,
        {
            "researcher": "researcher",
            "analyst": "analyst",
            "writer": "writer",
            "publisher": "publisher",
            END: END,
        }
    )

    #  所有子 Agent 完成后回到 Supervisor
    builder.add_edge("researcher", "supervisor")
    builder.add_edge("analyst", "supervisor")
    builder.add_edge("writer", "supervisor")
    builder.add_edge("publisher", "supervisor")

    conn = sqlite3.connect(db_path, check_same_thread=False)
    return builder.compile(checkpointer=SqliteSaver(conn))


# ============================================================
# 运行演练
# ============================================================
if __name__ == "__main__":
    graph = build_localtrend_team()
    config = {"configurable": {"thread_id": "team-demo-1"}}

    print("=" * 60)
    print(" LocalTrend 团队启动")
    print("=" * 60)

    # 启动:Supervisor → Researcher → Analyst → Writer → Publisher(中断)
    result = graph.invoke(
        {
            "messages": [HumanMessage(content="帮我分析 AI 领域的爆款规律,并写一篇公众号文章。")],
            "next_agent": "",
            "research_results": "",
            "trend_patterns": "",
            "generated_content": "",
            "review_decision": "",
            "review_feedback": "",
            "published": False,
        },
        config
    )

    # 在 publisher 中断了——审核
    print("\n⏸️ 等待审核...")

    # 模拟场景 A:批准
    print("\n--- 批准 ---")
    final = graph.invoke(Command(resume="approve"), config)
    print(f"\n✅ 发布状态: {'已发布' if final['published'] else '未发布'}")

    # 模拟场景 B:驳回重写
    print("\n\n" + "=" * 60)
    print("场景 B:驳回 → Writer 重写 → 再审核 → 批准")
    print("=" * 60)
    config_b = {"configurable": {"thread_id": "team-demo-2"}}

    graph.invoke(
        {
            "messages": [HumanMessage(content="分析 AI 爆款规律,写一篇小红书笔记。")],
            "next_agent": "",
            "research_results": "",
            "trend_patterns": "",
            "generated_content": "",
            "review_decision": "",
            "review_feedback": "",
            "published": False,
        },
        config_b
    )
    print("⏸️ 审核暂停")

    # 驳回
    result_b = graph.invoke(
        Command(resume="标题不够吸引人,加 emoji,用更短的分句"),
        config_b
    )
    # 驳回后 Writer 重新生成 → 又到 Publisher 中断
    print("⏸️ 再次暂停(重写后)")

    # 批准
    final_b = graph.invoke(Command(resume="approve"), config_b)
    print(f"✅ {'已发布' if final_b['published'] else '未发布'}")

运行后的关键观察

  1. Supervisor 像一个智能调度器:它读取 State 中的进度标记(research_resultstrend_patterns 等),决定"下一步该谁"
  2. 驳回后的重写是自动的:Supervisor 看到 review_feedback 非空,自动路由回 writer——不需要手动控制
  3. 每个子 Agent 的代码清晰独立create_researcher() 的代码不超过 30 行,职责单一。修改 Researcher 的逻辑不会影响 Analyst

本章小结

  1. Supervisor 模式 = 中央调度器 + N 个专业子 Agent——每个子 Agent 是独立编译的图,负责一个明确的任务域。
  2. 子图作为节点注册builder.add_node("name", create_subgraph())——子图对外表现为一个"超级节点"。
  3. 父图和子图必须共享相同的 State schema——否则字段会丢失或冲突。
  4. 子 Agent 完成后回到 Supervisor——循环决策直到任务完成。这是 ReAct 循环的高层次版本。
  5. 各子 Agent 可以使用不同的 LLM 模型——根据任务需求(成本、质量、速度)灵活选择。
  6. 子图内部可以使用 LangGraph 全部特性——Send 并行、interrupt 审核、条件边,都可以在子图内部使用。

关键术语

术语 释义
Supervisor 模式 一个中央调度 Agent 根据当前进度决定调用哪个子 Agent 的多 Agent 架构
子图(Subgraph) 一个独立编译的 StateGraph,作为父图的节点使用
Agent 团队 多个专业子 Agent 通过共享 State 协作完成复杂任务的架构
Agent 路由 Supervisor 根据 State 中的进度标记(research_results、trend_patterns 等)决定下一个调谁
共享 State 父图和所有子图使用相同的 State schema,确保数据无缝流转

posted @ 2026-06-16 11:40  Yobeeo  阅读(3)  评论(0)    收藏  举报