logo
0
0
WeChat Login
feat: 使用LangGraph状态图编排多智能体协调方式

🎯 LangGraph 多智能体系统说明

📚 项目概述

本项目实现了两种多智能体协调方式:

  1. 简化版 (orchestrator.simple.ts) - 函数式调用
  2. LangGraph版 (orchestrator.langgraph.ts) - 状态图编排 ⭐️

🔄 两种模式对比

简化版 (Simple)

文件: src/agents/multi-agent/orchestrator.simple.ts

特点:

  • ✅ 代码简单易懂
  • ✅ 直接的函数调用
  • ✅ 无外部依赖问题
  • ✅ 适合学习基础概念

代码示例:

async execute(userQuestion: string) { // 1. 接待员分析 const decision = await this.receptionistAgent.routeQuestion(userQuestion); // 2. 根据决策路由 if (decision.targetAgent === AgentType.TECH_SUPPORT) { return await this.techSupportAgent.handleQuestion(userQuestion); } else if (decision.targetAgent === AgentType.SALES) { return await this.salesAgent.handleQuestion(userQuestion); } else { return await this.answerWithDirectLLM(userQuestion); } }

LangGraph版 (LangGraph) ⭐️

文件: src/agents/multi-agent/orchestrator.langgraph.ts

特点:

  • ✅ 声明式状态图定义
  • ✅ 自动状态管理
  • ✅ 支持复杂路由
  • ✅ 可视化工作流
  • ✅ 流式执行支持
  • ✅ 适合复杂场景

代码示例:

// 1. 定义状态图 const workflow = new StateGraph(StateAnnotation); // 2. 添加节点 workflow.addNode('receptionist', async (state) => {...}); workflow.addNode('tech_support', async (state) => {...}); workflow.addNode('sales', async (state) => {...}); workflow.addNode('direct_llm', async (state) => {...}); // 3. 定义边(流程) workflow.addEdge(START, 'receptionist'); workflow.addConditionalEdges('receptionist', routingLogic); workflow.addEdge('tech_support', END); workflow.addEdge('sales', END); workflow.addEdge('direct_llm', END); // 4. 编译并执行 const graph = workflow.compile(); const result = await graph.invoke(initialState);

🎨 LangGraph 工作流可视化

🔧 切换模式

方法1: 环境变量(推荐)

编辑 .env 文件:

# 使用 LangGraph 版本 USE_LANGGRAPH=true # 使用简化版本 USE_LANGGRAPH=false

方法2: 运行时切换

// 在服务中切换 multiAgentService.switchMode(true); // 切换到 LangGraph multiAgentService.switchMode(false); // 切换到简化版

📖 LangGraph 核心概念

1. 状态图 (StateGraph)

状态图是LangGraph的核心,定义了智能体的执行流程。

const workflow = new StateGraph(StateAnnotation);

2. 状态注解 (Annotation)

定义状态的结构和更新规则:

const StateAnnotation = Annotation.Root({ messages: Annotation<any[]>({ reducer: (left, right) => left.concat(right), // 合并消息 default: () => [], }), userQuestion: Annotation<string>({ reducer: (left, right) => right || left, // 保留最新值 default: () => '', }), // ... 更多字段 });

Reducer的作用:

  • 定义如何合并新旧状态
  • left: 旧值
  • right: 新值
  • 返回: 合并后的值

3. 节点 (Node)

节点是工作流中的处理单元,每个节点执行特定任务:

// @ts-ignore - LangGraph 1.0 类型定义不完善 workflow.addNode('receptionist', async (state: AgentState) => { // 处理逻辑 const decision = await this.receptionistAgent.routeQuestion(state.userQuestion); // 返回状态更新 return { currentAgent: decision.targetAgent, routingReason: decision.reason, processingSteps: [{ agent: AgentType.RECEPTIONIST, action: '路由决策', timestamp: Date.now(), }], }; });

节点特点:

  • 接收当前状态
  • 执行异步操作
  • 返回状态更新(部分更新,会被合并)

4. 边 (Edge)

边定义节点之间的连接关系:

a) 直接边 (Direct Edge)

// @ts-ignore workflow.addEdge(START, 'receptionist'); // START → 接待员 // @ts-ignore workflow.addEdge('tech_support', END); // 技术支持 → END

b) 条件边 (Conditional Edge)

// @ts-ignore workflow.addConditionalEdges( 'receptionist', // 来源节点 (state: AgentState) => { // 路由逻辑 if (state.currentAgent === AgentType.TECH_SUPPORT) { return 'tech_support'; } else if (state.currentAgent === AgentType.SALES) { return 'sales'; } return 'direct_llm'; }, // 映射表:返回值 → 目标节点 { tech_support: 'tech_support', sales: 'sales', direct_llm: 'direct_llm', } );

5. 执行方式

a) 一次性执行

const result = await graph.invoke(initialState); console.log(result.finalAnswer);

b) 流式执行

const stream = await graph.stream(initialState); for await (const chunk of stream) { console.log('状态更新:', chunk); }

🐛 TypeScript 类型问题

LangGraph 1.0 的TypeScript类型定义还不完善,我们使用 @ts-ignore 来绕过:

// @ts-ignore - LangGraph 1.0 类型定义不完善 workflow.addNode('receptionist', async (state: AgentState) => {...});

为什么使用 @ts-ignore 而不是 @ts-expect-error

  • @ts-expect-error: 期望有错误,如果没错误会报警
  • @ts-ignore: 无条件忽略下一行的类型检查
  • LangGraph 1.0 在某些环境可能不报错,所以用 @ts-ignore 更稳定

📊 状态流转示例

假设用户问题: "我的账号登录不上去了"

1. START └─> 初始状态: { userQuestion: "我的账号登录不上去了", messages: [...] } 2. receptionist 节点 └─> 分析问题 → 决策: tech_support └─> 状态更新: { currentAgent: 'tech_support', routingReason: '...' } 3. 条件路由 └─> 根据 currentAgent 选择 → tech_support 节点 4. tech_support 节点 └─> 调用技术支持智能体处理 └─> 状态更新: { finalAnswer: '...', messages: [...] } 5. END └─> 返回最终结果

🎯 使用建议

何时使用简化版?

  • 学习多智能体基础概念
  • 简单的顺序流程
  • 快速原型开发
  • 避免外部依赖问题

何时使用LangGraph版?

  • 复杂的多智能体协作
  • 需要条件分支和循环
  • 需要状态持久化
  • 需要可视化工作流
  • 学习LangGraph技术

🚀 快速开始

1. 安装依赖

yarn install

2. 配置环境变量

# 编辑 .env 文件 USE_LANGGRAPH=true # 使用LangGraph版本

3. 启动服务

PORT=4005 yarn start:dev

4. 访问页面

http://localhost:4005/multi-agent

5. 测试问题

试试这些问题:

  • "你们的产品多少钱?" → 销售智能体
  • "我的账号登录不上去了" → 技术支持智能体
  • "你好" → LLM直接回答
  • "今天天气怎么样?" → LLM直接回答(礼貌拒绝)

📝 代码位置

src/agents/multi-agent/ ├── orchestrator.simple.ts # 简化版协调器 ├── orchestrator.langgraph.ts # LangGraph版协调器 ⭐️ ├── orchestrator.ts.bak # 原始LangGraph版本(备份) ├── multi-agent.service.ts # NestJS服务(支持两种模式) ├── types.ts # 类型定义 └── agents/ ├── receptionist.agent.ts # 接待员智能体 ├── tech-support.agent.ts # 技术支持智能体 └── sales.agent.ts # 销售智能体

🔬 学习资源

LangGraph 官方文档

本项目学习路径

  1. 理解简化版 (orchestrator.simple.ts)

    • 掌握基本的多智能体协作流程
    • 理解路由决策逻辑
  2. 学习LangGraph版 (orchestrator.langgraph.ts)

    • 理解状态图的定义
    • 学习节点和边的概念
    • 掌握状态管理
  3. 对比两种实现

    • 理解它们解决的问题相同
    • 体会声明式 vs 命令式的区别
  4. 扩展功能

    • 添加新的智能体
    • 实现更复杂的路由逻辑
    • 添加循环和递归流程

💡 常见问题

Q1: 为什么要用 @ts-ignore

A: LangGraph 1.0 的TypeScript类型定义还不完善,使用 @ts-ignore 可以绕过类型检查。

Q2: 两种模式可以同时使用吗?

A: 可以!服务会同时初始化两个协调器,通过 USE_LANGGRAPH 环境变量或 switchMode() 方法切换。

Q3: LangGraph的性能怎么样?

A: LangGraph增加了一层抽象,但对于AI应用来说,性能瓶颈通常在LLM调用上,状态图的开销可以忽略不计。

Q4: 如何调试LangGraph?

A:

  1. 在每个节点打印日志
  2. 使用流式执行查看中间状态
  3. 查看控制台输出的状态转换

🎓 总结

LangGraph的核心优势:

  • 📊 可视化工作流
  • 🔄 声明式状态管理
  • 🎯 支持复杂路由
  • 🚀 易于扩展

适用场景:

  • 复杂的多智能体协作
  • 需要条件分支、循环
  • 需要状态持久化
  • 团队协作开发

开始你的LangGraph学习之旅吧!🚀