多 Agent 编排
单 Agent 有上下文和能力边界,多 Agent 把任务拆给多个专家。LangGraph 提供从简到繁的编排原语:子图、Send(动态并行)、supervisor(中心调度)、handoff(交接)。
子图:复用与隔离
research_graph = builder.compile() # 子图
def research_node(state):
result = research_graph.invoke({...}) # 父节点内调用子图
return {"findings": result["output"]}- 子图是独立编译的图,可复用、可单独测试
- 父子状态默认隔离:子图有自己的 checkpoint 命名空间,父图不直接看到子图内部状态(跨边界共享用 store,见持久化篇)
- 组合方式:节点内调用(函数式)或作为节点挂进父图(
add_node("research", research_graph))
Send:动态并行
from langgraph.types import Send
def fan_out(state):
return [Send("analyze", {"doc": d}) for d in state["documents"]]
builder.add_node("analyze", analyze_node)
builder.add_conditional_edges("fan_out", fan_out, ["analyze"])- Send:从一个节点动态生成多个“分析任务”,并行执行(map-reduce 模式)
- 每个 Send 携带独立输入,任务数由运行时数据决定
- 典型场景:多文档并行分析、多城市并行查询
Command:动态路由
from langgraph.types import Command
def route_node(state):
if state["needs_research"]:
return Command(goto="research") # 动态指定下一个节点
return Command(goto=END)- Command 让节点动态决定去向(返回哪里、更新什么状态),比编译时固定的条件边更灵活
- 也用于 interrupt 恢复后的路由(见人机协同篇)
supervisor:中心调度
Supervisor 模式: 中央调度, worker 回报
- Supervisor 是“调度模型”:看当前状态决定派给哪个 worker,worker 干完回报,循环直到完成
- worker 是带专属工具/提示词的子 agent
- 对比 Send:supervisor 是运行时决策(下一步做什么模型说了算),Send 是图结构固定、任务数运行时动态生成(并行任务已确定)
handoff:交接
from langgraph.prebuilt import create_handoff_tool
transfer_tool = create_handoff_tool(
agent_name="billing_agent",
description="用户询问账单问题时交给账单 agent",
)- handoff:一个 agent 通过调用工具把对话“交接”给另一个 agent,交接后可带消息
- 适合:客服分流(售前→售后→账单)、权限边界(普通 agent 发现需要管理员权限时交接)
- 交接工具的描述同样决定路由质量(见工具集成篇的描述要点)
编排模式选型
| 模式 | 原语 | 适用 |
|---|---|---|
| 固定流水线 | 子图/边 | 流程确定的编排 |
| 动态并行 | Send | 任务数运行期才知道 |
| 中心调度 | supervisor | 需要模型决策分工 |
| 会话交接 | handoff | 对话流转/权限边界 |
| 混合 | 全部 | 生产常态 |
面试追问
- Send 和 supervisor 的区别? Send 是动态生成并行任务(图结构固定、数量运行时定),supervisor 是运行时决策(模型选下一步)。一个管“多少个”,一个管“走哪条”
- 子图和父图的状态关系? 默认隔离:子图有自己的 checkpoint 空间。跨边界共享用 store
- handoff 是什么? agent 通过工具把对话交给另一个 agent。客服分流、权限边界
- 多 Agent 什么时候值得? 任务要多种专业能力、上下文隔离需求(见 DeepAgents 子代理篇)。简单任务单 Agent 更便宜
- Command 的作用? 节点动态指定下一步(goto)和状态更新。interrupt 恢复后路由也靠它