深入浅出 LangGraph —— 第12章:多Agent系统架构

📖 本章学习目标

  • ✅ 理解多 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 各负责专门的任务。

工作流程:

  1. 监督者接收用户请求
  2. 监督者分析任务,决定下一步
  3. 路由到对应的工作者Agent
  4. 工作者执行任务,返回结果
  5. 回到监督者,继续决策
  6. 直到任务完成(FINISH)

2、使用 createReactAgent 创建工作者

LangGraph 提供了 createReactAgent 预构建函数,快速创建 ReAct 工作者 Agent:

步骤1:导入依赖
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
// 搜索工作者的工具
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
// 分析 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('你是专业的代码审查助手,擅长发现代码问题和提供改进建议。'),
});

每个工作者有专门的工具和角色定义,在设计工作者时,通常遵循以下原则:

  1. 单一职责:每个Agent只做一件事
  2. 专业化工具:只绑定相关的工具
  3. 明确角色:SystemMessage清晰定义职责

3、实现监督者

定义路由Schema
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:给工作者的具体指令
实现监督者节点
// 监督者节点:决定下一步派谁去做
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
import { messagesStateReducer } from '@langchain/langgraph';

// 扩展 State 添加路由字段
const MultiAgentState = Annotation.Root({
  messages: Annotation({
    reducer: messagesStateReducer,
    default: () => [],
  }),
  next: Annotation<Worker | 'FINISH'>(),
});
创建工作者节点包装器
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

工作流程:

  1. 接收当前messages
  2. 调用工作者Agent处理
  3. 获取工作者的最后一条消息
  4. 添加前缀标识(如[搜索助手])
  5. 返回更新后的messages
组装完整图
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 系统

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

// 提案 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
  });

执行流程:

  1. proposer提出方案
  2. reviewer审阅
  3. 如果不满意,回到proposer修改
  4. 如果满意(APPROVED),结束

注意事项:

  • 必须设置recursionLimit防止无限循环
  • APPROVED关键词要明确

对比两种架构:

特性Supervisor-WorkerPeer-to-Peer
控制方式集中式(监督者)分布式(平等)
通信模式星型拓扑网状拓扑
适用场景任务分解与分配双向协作与迭代
复杂度中等简单
扩展性好(易添加工作者)一般

五、最佳实践和踩坑指南

💡 实践 1:防止无限循环

// 添加最大循环次数限制
const MAX_ITERATIONS = 10;

const safeMultiAgentGraph = new StateGraph(MultiAgentState)
  // ... nodes and edges ...
  .compile({
    recursionLimit: MAX_ITERATIONS, // 超过限制自动停止
  });

原因:多Agent系统容易陷入无限循环,必须设置安全限制。

💡 实践 2:监督者的提示词要明确

// ✅ 明确的终止条件
const goodSupervisorPrompt = `
任务完成标准:
- 搜索结果已获取 AND
- 内容已撰写 AND
- 用户问题已完整回答
满足以上所有条件时,回复 FINISH。
`;

// ❌ 模糊的终止条件
const badSupervisorPrompt = `
你觉得差不多了就结束吧。
`;

原因:模糊的终止条件会导致监督者无法判断何时结束。

💡 实践 3:工作者上下文管理

// ✅ 只传相关消息给工作者
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 团队
  • 要求:
    1. 监督者分配任务
    2. 结果汇总后由写作者输出最终报告
    3. 支持多轮迭代优化
  • 验收标准:
    • 给定研究主题,自动生成完整的研究报告
    • 报告结构清晰,内容准确
    • 协作过程可追溯

练习 2:辩论 Agent

  • 目标:两个 Agent 对一个观点进行正反方辩论(3轮)
  • 要求:
    1. 双方各持立场
    2. 每轮针对对方观点反驳
    3. 最后由第三个 Agent 裁判得出结论
  • 验收标准:
    • 3轮辩论后输出裁判结论
    • 辩论逻辑清晰,有理有据
    • 不超过最大轮数限制

练习 3:代码审查团队

  • 目标:4个 Agent 分别负责安全审查、性能审查、可读性审查、最终汇总
  • 要求:
    1. 前三个并行执行
    2. 最后汇总输出综合评分
    3. 每个Agent有专门的检查清单
  • 验收标准:
    • 给定代码,输出四个维度的审查报告
    • 每个维度有具体问题和建议
    • 综合评分客观公正

练习 4:动态工作者注册

  • 目标:实现工作者动态注册和注销
  • 要求:
    1. 监督者能感知可用工作者列表
    2. 运行时可以添加新工作者
    3. 工作者可以主动退出
  • 验收标准:
    • 新增工作者无需修改监督者代码
    • 工作者列表动态更新
    • 系统稳定运行

📚 延伸阅读


下一章:第13章 —— Functional API:函数式工作流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值