📖 本章学习目标
- ✅ 理解多 Agent 系统相比单 Agent 的核心优势
- ✅ 掌握监督者-工作者(Supervisor-Worker)架构模式
- ✅ 学会使用
createReactAgent快速创建工作者 Agent- ✅ 理解 Agent 间的通信与任务传递机制
- ✅ 能够设计并实现一个协同工作的多 Agent 团队
- ✅ 避免常见的多Agent设计陷阱
一、为什么需要多 Agent
1、单 Agent 的瓶颈
当任务越来越复杂,单个 Agent 会遇到以下瓶颈:
- 上下文窗口有限:单个 Agent 处理长任务时历史消息超限
- 工具太多:绑定几十个工具后,LLM 调用准确率下降
- 专业化不足:一个 Agent 什么都做,什么都做得不精
- 并行能力弱:单 Agent 只能串行处理任务
- 维护困难:单一Agent逻辑复杂,难以调试和维护
多Agent就是处理以上问题的解决方案。
多Agent团队
用户请求
监督者Agent
任务分解
搜索Agent
分析Agent
写作Agent
结果汇总
高质量完成
2、多 Agent 的优势
搜索任务
分析任务
写作任务
🧑💼 监督者 Agent
任务规划与分配
🔍 搜索 Agent
专注信息检索
📊 分析 Agent
专注数据分析
✍️ 写作 Agent
专注内容生成
📋 最终结果
| 维度 | 单 Agent | 多 Agent |
|---|---|---|
| 专业性 | 通才,样样略懂 | 专家,各司其职 |
| 并行能力 | 串行执行 | 并行分工 |
| 上下文管理 | 单一上下文 | 各 Agent 独立上下文 |
| 可扩展性 | 难以扩展 | 按需增加专家 Agent |
| 可靠性 | 单点故障 | 容错性强 |
| 维护性 | 复杂难维护 | 模块化易维护 |
实际应用场景:
- 📰 新闻生成:搜索→分析→写作→审核
- 💻 代码开发:需求分析→架构设计→编码→测试
- 🔬 学术研究:文献检索→数据分析→论文撰写
- 🏥 医疗诊断:症状分析→检查建议→治疗方案
二、监督者-工作者架构
1、架构设计
最经典的多 Agent 模式:一个监督者(Supervisor) 负责规划和任务分配,多个工作者(Worker)Agent 各负责专门的任务。
工作流程:
- 监督者接收用户请求
- 监督者分析任务,决定下一步
- 路由到对应的工作者Agent
- 工作者执行任务,返回结果
- 回到监督者,继续决策
- 直到任务完成(FINISH)
2、使用 createReactAgent 创建工作者
LangGraph 提供了 createReactAgent 预构建函数,快速创建 ReAct 工作者 Agent:
步骤1:导入依赖
typescript
import * as dotenv from 'dotenv';
dotenv.config();
import { createReactAgent } from '@langchain/langgraph/prebuilt';
import { ChatOpenAI } from '@langchain/openai';
import { tool } from '@langchain/core/tools';
import { z } from 'zod';
import { HumanMessage, SystemMessage } from '@langchain/core/messages';
const model = new ChatOpenAI({ model: 'gpt-4o-mini' });
步骤2:创建搜索Agent
typescript
// 搜索工作者的工具
const webSearchTool = tool(
async ({ query }) => `搜索"${query}":找到了相关结果...`,
{
name: 'web_search',
description: '搜索互联网信息',
schema: z.object({ query: z.string() })
}
);
// 创建搜索 Agent
const searchAgent = createReactAgent({
llm: model,
tools: [webSearchTool],
stateModifier: new SystemMessage(
'你是专业的信息检索助手,擅长搜索并整理网络信息。请返回详细的搜索结果。'
),
});
步骤3:创建分析Agent
typescript
// 分析 Agent
const codeAnalysisTool = tool(
async ({ code }) => `代码分析结果:发现3个潜在问题...`,
{
name: 'analyze_code',
description: '分析代码质量和潜在问题',
schema: z.object({ code: z.string() })
}
);
const analysisAgent = createReactAgent({
llm: model,
tools: [codeAnalysisTool],
stateModifier: new SystemMessage('你是专业的代码审查助手,擅长发现代码问题和提供改进建议。'),
});
每个工作者有专门的工具和角色定义,在设计工作者时,通常遵循以下原则:
- 单一职责:每个Agent只做一件事
- 专业化工具:只绑定相关的工具
- 明确角色:SystemMessage清晰定义职责
3、实现监督者
定义路由Schema
typescript
import {
Annotation, StateGraph, MessagesAnnotation,
END, START
} from '@langchain/langgraph';
import { AIMessage, BaseMessage } from '@langchain/core/messages';
import { z } from 'zod';
// 工作者列表
const workers = ['search_agent', 'analysis_agent', 'writer_agent'] as const;
type Worker = typeof workers[number];
// 监督者的路由决策 Schema
const SupervisorDecision = z.object({
next: z.enum([...workers, 'FINISH']).describe('下一个要执行的工作者,FINISH 表示任务完成'),
reason: z.string().describe('选择原因'),
instructions: z.string().describe('给工作者的具体指令'),
});
- 代码解读:
workers:定义所有可用的工作者名称SupervisorDecision:约束监督者的输出格式next:下一步路由目标(工作者或FINISH)reason:决策原因,便于调试instructions:给工作者的具体指令
实现监督者节点
typescript
// 监督者节点:决定下一步派谁去做
async function supervisorNode(state: typeof MessagesAnnotation.State) {
const supervisorModel = model.withStructuredOutput(SupervisorDecision);
const decision = await supervisorModel.invoke([
new SystemMessage(
`你是团队监督者,负责将任务分配给以下工作者:\n` +
`- search_agent:负责信息搜索\n` +
`- analysis_agent:负责数据分析\n` +
`- writer_agent:负责内容写作\n` +
`根据对话历史决定下一步,任务完成时回复 FINISH。`
),
...state.messages,
]);
return {
messages: [
new AIMessage({
content: `[监督者] → ${decision.next}: ${decision.instructions}`,
}),
],
next: decision.next,
};
}
代码解读:
withStructuredOutput:约束监督者只能返回合法的工作者名称- 监督者消息包含**"给工作者的指令"**,工作者会看到这条消息
next字段用于路由到对应的工作者或结束
监督者的职责:
- 理解用户需求
- 分解任务步骤
- 分配合适的工作者
- 判断任务是否完成
提示词技巧:
- 明确列出所有工作者及其职责
- 说明终止条件(FINISH)
- 要求给出决策原因
4、组装多 Agent 图
扩展State
typescript
import { messagesStateReducer } from '@langchain/langgraph';
// 扩展 State 添加路由字段
const MultiAgentState = Annotation.Root({
messages: Annotation({
reducer: messagesStateReducer,
default: () => [],
}),
next: Annotation<Worker | 'FINISH'>(),
});
创建工作者节点包装器
typescript
import { CompiledStateGraph } from '@langchain/langgraph';
// 工作者节点:调用对应的 Agent,将结果加入消息历史
async function makeWorkerNode(agentGraph: CompiledStateGraph, agentName: string) {
return async (state: typeof MultiAgentState.State) => {
const result = await agentGraph.invoke({ messages: state.messages });
const lastMsg = result.messages[result.messages.length - 1];
return {
messages: [
new AIMessage({ content: `[${agentName}] ${lastMsg.content}` })
],
};
};
}
makeWorkerNode是工厂函数,用于创建工作者节点。
agentGraph:编译好的工作者Agent(createReactAgent返回)agentName:工作者名称,用于标识消息来源- 调用工作者Agent,获取结果
- 将结果包装后添加到
messages
工作流程:
- 接收当前messages
- 调用工作者Agent处理
- 获取工作者的最后一条消息
- 添加前缀标识(如[搜索助手])
- 返回更新后的messages
组装完整图
typescript
const multiAgentGraph = new StateGraph(MultiAgentState)
.addNode('supervisor', supervisorNode)
.addNode('search_agent', await makeWorkerNode(searchAgent, '搜索助手'))
.addNode('analysis_agent', await makeWorkerNode(analysisAgent, '分析助手'))
.addEdge('__start__', 'supervisor')
// 监督者根据 next 字段路由
.addConditionalEdges('supervisor', (state) => state.next, {
search_agent: 'search_agent',
analysis_agent: 'analysis_agent',
writer_agent: 'writer_agent',
FINISH: '__end__',
})
// 所有工作者执行后都回到监督者
.addEdge('search_agent', 'supervisor')
.addEdge('analysis_agent', 'supervisor')
.compile();
每个工作者完成后都回到 supervisor,让监督者决定下一步,这形成了**"监督者→工作者→监督者→..."** 的循环,直到 FINISH。state.next 是监督者设置的路由目标,条件边据此分发。
关键点:
- 监督者是中心节点
- 工作者之间不直接通信
- 所有决策由监督者做出
- 通过
next字段控制路由
多Agent协作流程图:
search_agent
analysis_agent
writer_agent
FINISH
start
监督者节点
决策下一步
next字段?
搜索Agent
执行搜索
分析Agent
执行分析
写作Agent
生成内容
end
三、运行多 Agent 系统
typescript
async function runMultiAgentSystem() {
const result = await multiAgentGraph.invoke({
messages: [
new HumanMessage(
'请帮我:1.搜索LangGraph的最新版本信息,2.分析其主要特性,3.写一篇介绍文章'
),
],
next: 'supervisor', // 初始路由到监督者
});
// 打印所有消息(展示协作过程)
for (const msg of result.messages) {
if (msg instanceof AIMessage) {
console.log(msg.content);
console.log('---');
}
}
}
await runMultiAgentSystem();
// 输出示例:
// [监督者] → search_agent: 请先搜索LangGraph最新版本信息
// ---
// [搜索助手] LangGraph最新版本是0.2.0,主要更新包括...
// ---
// [监督者] → analysis_agent: 请分析这些特性的价值
// ---
// [分析助手] 这些特性提升了开发效率,主要体现在...
// ---
// [监督者] → writer_agent: 请基于以上信息写介绍文章
// ---
// [写作助手] LangGraph是一个强大的Agent框架...
// ---
// [监督者] → FINISH: 任务已完成
// ---
invoke时传入初始消息和next字段,next:'supervisor'表示从监督者开始。整个过程全自动,监督者智能分配任务。 最终result.messages包含完整的协作历史。
调试技巧:
- 打印所有
messages查看协作过程 - 使用
streamEvents观察每一步 - 检查
next字段的决策是否正确
四、对等协作架构(Peer-to-Peer)
1、适用场景
当 Agent 之间需要双向通信时(如辩论、互相审阅),使用对等架构:
反馈
修订
批准
Agent A
提出方案
Agent B
审阅方案
完成
典型应用:
- 🗣️ 辩论系统:正反方交替发言
- 👀 代码审阅:开发者与审阅者交互
- ✍️ 内容创作:作者与编辑协作
- 🎯 方案设计:提案者与评审者迭代
2、实现辩论Agent
typescript
// 提案 Agent
async function proposerNode(state: typeof MessagesAnnotation.State) {
const response = await model.invoke([
new SystemMessage('你是方案提出者,根据需求给出具体解决方案,简洁有力'),
...state.messages,
]);
return { messages: [response] };
}
// 审阅 Agent
async function reviewerNode(state: typeof MessagesAnnotation.State) {
const response = await model.invoke([
new SystemMessage('你是严格的方案审阅者,指出问题和改进点,如果方案足够好回复"APPROVED"'),
...state.messages,
]);
return { messages: [response] };
}
// 路由:审阅结果决定继续还是结束
function reviewRouter(state: typeof MessagesAnnotation.State): string {
const lastMsg = state.messages[state.messages.length - 1];
return (lastMsg.content as string).includes('APPROVED') ? '__end__' : 'proposer';
}
const collaborativeGraph = new StateGraph(MessagesAnnotation)
.addNode('proposer', proposerNode)
.addNode('reviewer', reviewerNode)
.addEdge('__start__', 'proposer')
.addEdge('proposer', 'reviewer')
.addConditionalEdges('reviewer', reviewRouter)
.compile({
recursionLimit: 10
});
执行流程:
- proposer提出方案
- reviewer审阅
- 如果不满意,回到proposer修改
- 如果满意(
APPROVED),结束
注意事项:
- 必须设置
recursionLimit防止无限循环 APPROVED关键词要明确
对比两种架构:
| 特性 | Supervisor-Worker | Peer-to-Peer |
|---|---|---|
| 控制方式 | 集中式(监督者) | 分布式(平等) |
| 通信模式 | 星型拓扑 | 网状拓扑 |
| 适用场景 | 任务分解与分配 | 双向协作与迭代 |
| 复杂度 | 中等 | 简单 |
| 扩展性 | 好(易添加工作者) | 一般 |
五、最佳实践和踩坑指南
💡 实践 1:防止无限循环
typescript
// 添加最大循环次数限制
const MAX_ITERATIONS = 10;
const safeMultiAgentGraph = new StateGraph(MultiAgentState)
// ... nodes and edges ...
.compile({
recursionLimit: MAX_ITERATIONS, // 超过限制自动停止
});
原因:多Agent系统容易陷入无限循环,必须设置安全限制。
💡 实践 2:监督者的提示词要明确
typescript
// ✅ 明确的终止条件
const goodSupervisorPrompt = `
任务完成标准:
- 搜索结果已获取 AND
- 内容已撰写 AND
- 用户问题已完整回答
满足以上所有条件时,回复 FINISH。
`;
// ❌ 模糊的终止条件
const badSupervisorPrompt = `
你觉得差不多了就结束吧。
`;
原因:模糊的终止条件会导致监督者无法判断何时结束。
💡 实践 3:工作者上下文管理
typescript
// ✅ 只传相关消息给工作者
async function smartWorkerNode(agentGraph: CompiledStateGraph, agentName: string) {
return async (state: typeof MultiAgentState.State) => {
// 只传最近5条消息,避免Token超限
const relevantMessages = state.messages.slice(-5);
const result = await agentGraph.invoke({ messages: relevantMessages });
// ...
};
}
// ❌ 传递全部历史
const badWorkerNode = async (state) => {
const result = await agentGraph.invoke({ messages: state.messages }); // 可能超限
};
原因:工作者不需要完整历史,只传相关内容可节省Token。
⚠️ 常见陷阱
| 问题 | 现象 | 解决方案 |
|---|---|---|
| 监督者无限循环 | 图永远不返回 FINISH | 设置 recursionLimit,优化终止条件提示词 |
| 工作者上下文太长 | Token 超限报错 | 传给工作者的 messages 只传相关的,不传全部历史 |
| Agent 输出格式不一致 | 监督者无法解析工作者结果 | 为每个工作者定义明确的输出格式规范 |
| 并行工作者写入同一字段 | 状态合并冲突 | 为工作者的输出设计追加 Reducer |
| 工作者之间直接通信 | 绕过监督者,逻辑混乱 | 所有通信经过监督者协调 |
忘记初始化next字段 |
第一次路由失败 | invoke时必须传入next:'supervisor' |
📝 本章小结
核心知识点回顾
| 知识点 | 关键要点 | 应用场景 |
|---|---|---|
createReactAgent |
快速创建 ReAct 工作者 | 工作者 Agent 的快速搭建 |
| Supervisor 模式 | 中央调度 + 专家分工 | 复杂多步骤任务 |
| Peer-to-Peer 模式 | Agent 间双向协作 | 辩论、审阅、协商 |
| recursionLimit | 防止无限循环 | 所有多 Agent 系统 |
| 状态转换 | 工作者结果汇入messages | 多Agent通信 |
| 路由控制 | next字段决定下一步 |
Supervisor决策 |
🎯 动手练习
练习 1:研究团队
- 目标:构建"规划者+搜索者+写作者"三 Agent 团队
- 要求 :
- 监督者分配任务
- 结果汇总后由写作者输出最终报告
- 支持多轮迭代优化
- 验收标准 :
- 给定研究主题,自动生成完整的研究报告
- 报告结构清晰,内容准确
- 协作过程可追溯
练习 2:辩论 Agent
- 目标:两个 Agent 对一个观点进行正反方辩论(3轮)
- 要求 :
- 双方各持立场
- 每轮针对对方观点反驳
- 最后由第三个 Agent 裁判得出结论
- 验收标准 :
- 3轮辩论后输出裁判结论
- 辩论逻辑清晰,有理有据
- 不超过最大轮数限制
练习 3:代码审查团队
- 目标:4个 Agent 分别负责安全审查、性能审查、可读性审查、最终汇总
- 要求 :
- 前三个并行执行
- 最后汇总输出综合评分
- 每个Agent有专门的检查清单
- 验收标准 :
- 给定代码,输出四个维度的审查报告
- 每个维度有具体问题和建议
- 综合评分客观公正
练习 4:动态工作者注册
- 目标:实现工作者动态注册和注销
- 要求 :
- 监督者能感知可用工作者列表
- 运行时可以添加新工作者
- 工作者可以主动退出
- 验收标准 :
- 新增工作者无需修改监督者代码
- 工作者列表动态更新
- 系统稳定运行
📚 延伸阅读
下一章:第13章 ------ Functional API:函数式工作流