Skip to content

25. 项目实战:多 Agent 协作系统 ​

项目简介 ​

本项目将从零构建一个多 Agent 协作系统,实现:

  • 🎭 角色分工:多个专业化 Agent 各司其职
  • 📋 任务分发:协调者 Agent 分配和调度任务
  • 🔄 结果聚合:汇总各 Agent 的产出
  • 🔗 状态同步:通过共享 Memory Store 协同
  • 👤 人工审核:最终输出前的人工确认

难度等级: ⭐⭐⭐⭐⭐

涉及知识点: 子图 + Send API + 长期记忆 + 流式 + HITL


🎯 学习目标 ​

完成本项目后,你将掌握:

  1. 如何设计多 Agent 协作架构
  2. 如何使用子图封装专业 Agent
  3. 如何使用 Send API 动态分发任务
  4. 如何通过 Memory Store 实现状态共享
  5. 如何整合人工审核流程

项目架构 ​

复杂任务 → 协调者 Agent(父图)
              │
              ├→ 任务分解
              │
              ├→ 子图分发(Send API)
              │   ├→ [子图] 研究 Agent
              │   ├→ [子图] 分析 Agent
              │   └→ [子图] 写作 Agent
              │
              ├→ 状态同步(共享 Memory Store)
              │
              ├→ 结果汇总
              │
              └→ 人工审核(HITL)→ 最终输出

多 Agent 协作系统架构总览


项目结构 ​

plaintext
multi-agent/
├── src/
│   ├── state.ts           # 状态定义
│   ├── agents/
│   │   ├── researcher.ts  # 研究 Agent
│   │   ├── analyst.ts     # 分析 Agent
│   │   └── writer.ts      # 写作 Agent
│   ├── coordinator.ts     # 协调者节点
│   ├── memory.ts          # 共享记忆
│   ├── graph.ts           # 主图构建
│   └── index.ts           # 入口文件
├── package.json
├── tsconfig.json
└── .env

第一步:项目初始化 ​

package.json ​

json
{
  "name": "multi-agent",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "tsx src/index.ts"
  },
  "dependencies": {
    "@langchain/langgraph": "^0.2.0",
    "@langchain/openai": "^0.3.0",
    "@langchain/core": "^0.3.0"
  },
  "devDependencies": {
    "typescript": "^5.0.0",
    "@types/node": "^20.0.0",
    "tsx": "^4.0.0"
  }
}

.env ​

bash
OPENAI_API_KEY=sk-xxx...

第二步:状态定义 ​

src/state.ts ​

typescript
import { Annotation } from "@langchain/langgraph";
import { BaseMessage } from "@langchain/core/messages";

export type AgentRole = "researcher" | "analyst" | "writer";

export interface AgentTask {
  id: string;
  role: AgentRole;
  description: string;
  input: string;
  status: "pending" | "in_progress" | "completed" | "failed";
  output?: string;
  metadata?: Record<string, any>;
}

export interface AgentResult {
  taskId: string;
  role: AgentRole;
  success: boolean;
  output: string;
  insights?: string[];
  duration: number;
  timestamp: string;
}

export const MultiAgentState = Annotation.Root({
  messages: Annotation<BaseMessage[]>({
    reducer: (curr, update) => [...curr, ...update],
    default: () => [],
  }),
  
  mainTask: Annotation<string>({
    reducer: (_, update) => update,
    default: () => "",
  }),
  
  subTasks: Annotation<AgentTask[]>({
    reducer: (_, update) => update,
    default: () => [],
  }),
  
  agentResults: Annotation<AgentResult[]>({
    reducer: (curr, update) => [...curr, ...update],
    default: () => [],
  }),
  
  currentTask: Annotation<AgentTask | null>({
    reducer: (_, update) => update,
    default: () => null,
  }),
  
  synthesis: Annotation<{
    summary: string;
    keyFindings: string[];
    recommendations: string[];
    finalReport: string;
  } | null>({
    reducer: (_, update) => update,
    default: () => null,
  }),
  
  phase: Annotation<"planning" | "executing" | "synthesizing" | "reviewing" | "complete">({
    reducer: (_, update) => update,
    default: () => "planning",
  }),
  
  humanApproval: Annotation<{
    required: boolean;
    approved?: boolean;
    feedback?: string;
  }>({
    reducer: (_, update) => update,
    default: () => ({ required: true }),
  }),
});

export type MultiAgentStateType = typeof MultiAgentState.State;

💡 人话解读:

状态字段作用
mainTask主任务描述
subTasks分解后的子任务列表
agentResults各 Agent 的执行结果(追加模式)
currentTask当前执行的子任务(用于并行)
synthesis最终综合结果
phase当前执行阶段
humanApproval人工审批状态

MultiAgentState 状态字段体系


第三步:专业 Agent 子图 ​

src/agents/researcher.ts ​

typescript
import { StateGraph, START, END, Annotation } from "@langchain/langgraph";
import { ChatOpenAI } from "@langchain/openai";
import { HumanMessage, SystemMessage } from "@langchain/core/messages";

const ResearcherState = Annotation.Root({
  task: Annotation<string>({
    reducer: (_, update) => update,
    default: () => "",
  }),
  findings: Annotation<string[]>({
    reducer: (curr, update) => [...curr, ...update],
    default: () => [],
  }),
  output: Annotation<string>({
    reducer: (_, update) => update,
    default: () => "",
  }),
});

const llm = new ChatOpenAI({ model: "gpt-4o-mini", temperature: 0.7 });

async function researchNode(state: typeof ResearcherState.State) {
  console.log(`      🔬 研究 Agent 开始工作...`);
  
  const response = await llm.invoke([
    new SystemMessage(`你是一个专业的研究员。你的任务是深入研究给定的主题,收集关键信息和数据。

输出格式:
1. 首先列出 3-5 个关键发现
2. 然后提供详细的研究报告

请确保研究内容准确、全面。`),
    new HumanMessage(`请研究以下主题:${state.task}`),
  ]);
  
  const content = response.content as string;
  
  const findingsMatch = content.match(/关键发现[::]([\s\S]*?)(?=详细|报告|$)/i);
  const findings = findingsMatch 
    ? findingsMatch[1].split(/\d+\./g).filter(f => f.trim()).map(f => f.trim())
    : [content.slice(0, 200)];
  
  console.log(`      ✅ 研究完成,发现 ${findings.length} 个关键点`);
  
  return {
    findings,
    output: content,
  };
}

const researcherGraph = new StateGraph(ResearcherState)
  .addNode("research", researchNode)
  .addEdge(START, "research")
  .addEdge("research", END);

export const researcherAgent = researcherGraph.compile();
export { ResearcherState };

src/agents/analyst.ts ​

typescript
import { StateGraph, START, END, Annotation } from "@langchain/langgraph";
import { ChatOpenAI } from "@langchain/openai";
import { HumanMessage, SystemMessage } from "@langchain/core/messages";

const AnalystState = Annotation.Root({
  task: Annotation<string>({
    reducer: (_, update) => update,
    default: () => "",
  }),
  data: Annotation<string>({
    reducer: (_, update) => update,
    default: () => "",
  }),
  analysis: Annotation<{
    insights: string[];
    trends: string[];
    risks: string[];
  }>({
    reducer: (_, update) => update,
    default: () => ({ insights: [], trends: [], risks: [] }),
  }),
  output: Annotation<string>({
    reducer: (_, update) => update,
    default: () => "",
  }),
});

const llm = new ChatOpenAI({ model: "gpt-4o-mini", temperature: 0.3 });

async function analyzeNode(state: typeof AnalystState.State) {
  console.log(`      📊 分析 Agent 开始工作...`);
  
  const response = await llm.invoke([
    new SystemMessage(`你是一个专业的数据分析师。你的任务是分析给定的信息,提取洞察、识别趋势和评估风险。

请按以下格式输出:
## 关键洞察
- 洞察1
- 洞察2

## 趋势分析
- 趋势1
- 趋势2

## 风险评估
- 风险1
- 风险2

## 综合分析
详细的分析报告...`),
    new HumanMessage(`请分析以下内容:

任务:${state.task}

数据/背景:
${state.data || "无额外数据"}`),
  ]);
  
  const content = response.content as string;
  
  const insightsMatch = content.match(/关键洞察[::]([\s\S]*?)(?=趋势|##|$)/i);
  const trendsMatch = content.match(/趋势分析[::]([\s\S]*?)(?=风险|##|$)/i);
  const risksMatch = content.match(/风险评估[::]([\s\S]*?)(?=综合|##|$)/i);
  
  const parseList = (text: string | undefined) => 
    text ? text.split(/[-•]/g).filter(i => i.trim()).map(i => i.trim()).slice(0, 5) : [];
  
  console.log(`      ✅ 分析完成`);
  
  return {
    analysis: {
      insights: parseList(insightsMatch?.[1]),
      trends: parseList(trendsMatch?.[1]),
      risks: parseList(risksMatch?.[1]),
    },
    output: content,
  };
}

const analystGraph = new StateGraph(AnalystState)
  .addNode("analyze", analyzeNode)
  .addEdge(START, "analyze")
  .addEdge("analyze", END);

export const analystAgent = analystGraph.compile();
export { AnalystState };

src/agents/writer.ts ​

typescript
import { StateGraph, START, END, Annotation } from "@langchain/langgraph";
import { ChatOpenAI } from "@langchain/openai";
import { HumanMessage, SystemMessage } from "@langchain/core/messages";

const WriterState = Annotation.Root({
  task: Annotation<string>({
    reducer: (_, update) => update,
    default: () => "",
  }),
  materials: Annotation<string>({
    reducer: (_, update) => update,
    default: () => "",
  }),
  style: Annotation<"formal" | "casual" | "technical">({
    reducer: (_, update) => update,
    default: () => "formal",
  }),
  output: Annotation<string>({
    reducer: (_, update) => update,
    default: () => "",
  }),
});

const llm = new ChatOpenAI({ model: "gpt-4o-mini", temperature: 0.8 });

async function writeNode(state: typeof WriterState.State) {
  console.log(`      ✍️  写作 Agent 开始工作...`);
  
  const styleGuide: Record<string, string> = {
    formal: "使用正式、专业的语言,适合商业报告",
    casual: "使用轻松、易读的语言,适合博客文章",
    technical: "使用技术性语言,包含专业术语",
  };
  
  const response = await llm.invoke([
    new SystemMessage(`你是一个专业的写作专家。你的任务是根据提供的素材撰写高质量的内容。

写作风格要求:${styleGuide[state.style]}

请确保:
1. 内容结构清晰
2. 语言流畅自然
3. 论述有理有据
4. 结论明确有力`),
    new HumanMessage(`请根据以下素材撰写内容:

任务:${state.task}

素材:
${state.materials}`),
  ]);
  
  console.log(`      ✅ 写作完成,${(response.content as string).length} 字符`);
  
  return {
    output: response.content as string,
  };
}

const writerGraph = new StateGraph(WriterState)
  .addNode("write", writeNode)
  .addEdge(START, "write")
  .addEdge("write", END);

export const writerAgent = writerGraph.compile();
export { WriterState };

💡 Agent 角色说明:

Agent角色专长
Researcher研究员深入调研,收集信息
Analyst分析师数据分析,洞察挖掘
Writer写作者内容撰写,报告生成

三个专业 Agent 角色对比


第四步:协调者节点 ​

src/coordinator.ts ​

typescript
import { Send, interrupt } from "@langchain/langgraph";
import { ChatOpenAI } from "@langchain/openai";
import { HumanMessage, SystemMessage } from "@langchain/core/messages";
import { MultiAgentStateType, AgentTask, AgentRole } from "./state.js";
import { researcherAgent } from "./agents/researcher.js";
import { analystAgent } from "./agents/analyst.js";
import { writerAgent } from "./agents/writer.js";

const llm = new ChatOpenAI({ model: "gpt-4o-mini", temperature: 0.3 });

export async function planningNode(state: MultiAgentStateType) {
  console.log(`\n🎯 协调者: 任务规划`);
  console.log(`   主任务: ${state.mainTask}`);
  
  const response = await llm.invoke([
    new SystemMessage(`你是一个任务规划专家。请将复杂任务分解为可以由不同专业 Agent 执行的子任务。

可用的 Agent 角色:
1. researcher - 研究员:负责调研、收集信息
2. analyst - 分析师:负责数据分析、洞察挖掘
3. writer - 写作者:负责内容撰写、报告生成

请以 JSON 格式输出任务分解:
{
  "tasks": [
    { "role": "researcher", "description": "任务描述" },
    { "role": "analyst", "description": "任务描述" },
    { "role": "writer", "description": "任务描述" }
  ]
}`),
    new HumanMessage(`请分解以下任务:${state.mainTask}`),
  ]);
  
  let tasks: AgentTask[] = [];
  
  try {
    const content = response.content as string;
    const jsonMatch = content.match(/\{[\s\S]*\}/);
    if (jsonMatch) {
      const parsed = JSON.parse(jsonMatch[0]);
      tasks = parsed.tasks.map((t: any, i: number) => ({
        id: `task-${i}-${Date.now()}`,
        role: t.role as AgentRole,
        description: t.description,
        input: state.mainTask,
        status: "pending" as const,
      }));
    }
  } catch (e) {
    tasks = [
      { id: `task-0-${Date.now()}`, role: "researcher", description: "研究主题背景", input: state.mainTask, status: "pending" },
      { id: `task-1-${Date.now()}`, role: "analyst", description: "分析关键要素", input: state.mainTask, status: "pending" },
      { id: `task-2-${Date.now()}`, role: "writer", description: "撰写综合报告", input: state.mainTask, status: "pending" },
    ];
  }
  
  console.log(`   📋 分解为 ${tasks.length} 个子任务:`);
  tasks.forEach((t, i) => {
    console.log(`      ${i + 1}. [${t.role}] ${t.description}`);
  });
  
  return {
    subTasks: tasks,
    phase: "executing" as const,
  };
}

export function dispatchNode(state: MultiAgentStateType): Send[] {
  console.log(`\n📤 协调者: 分发任务`);
  
  const researchTasks = state.subTasks.filter(t => t.role === "researcher");
  const analysisTasks = state.subTasks.filter(t => t.role === "analyst");
  const writingTasks = state.subTasks.filter(t => t.role === "writer");
  
  const sends: Send[] = [];
  
  researchTasks.forEach(task => {
    console.log(`   → 分发研究任务: ${task.description}`);
    sends.push(new Send("executeResearcher", { currentTask: task }));
  });
  
  analysisTasks.forEach(task => {
    console.log(`   → 分发分析任务: ${task.description}`);
    sends.push(new Send("executeAnalyst", { currentTask: task }));
  });
  
  writingTasks.forEach(task => {
    console.log(`   → 分发写作任务: ${task.description}`);
    sends.push(new Send("executeWriter", { currentTask: task }));
  });
  
  return sends;
}

export async function executeResearcherNode(state: MultiAgentStateType) {
  const task = state.currentTask;
  if (!task) return { agentResults: [] };
  
  console.log(`\n   🔬 执行研究任务: ${task.description}`);
  
  const startTime = Date.now();
  
  const result = await researcherAgent.invoke({
    task: `${task.description}\n\n背景:${task.input}`,
  });
  
  const duration = Date.now() - startTime;
  
  return {
    agentResults: [{
      taskId: task.id,
      role: "researcher" as const,
      success: true,
      output: result.output,
      insights: result.findings,
      duration,
      timestamp: new Date().toISOString(),
    }],
  };
}

export async function executeAnalystNode(state: MultiAgentStateType) {
  const task = state.currentTask;
  if (!task) return { agentResults: [] };
  
  console.log(`\n   📊 执行分析任务: ${task.description}`);
  
  const startTime = Date.now();
  
  const researchResults = state.agentResults
    .filter(r => r.role === "researcher")
    .map(r => r.output)
    .join("\n\n");
  
  const result = await analystAgent.invoke({
    task: task.description,
    data: researchResults || task.input,
  });
  
  const duration = Date.now() - startTime;
  
  return {
    agentResults: [{
      taskId: task.id,
      role: "analyst" as const,
      success: true,
      output: result.output,
      insights: [
        ...result.analysis.insights,
        ...result.analysis.trends,
      ],
      duration,
      timestamp: new Date().toISOString(),
    }],
  };
}

export async function executeWriterNode(state: MultiAgentStateType) {
  const task = state.currentTask;
  if (!task) return { agentResults: [] };
  
  console.log(`\n   ✍️  执行写作任务: ${task.description}`);
  
  const startTime = Date.now();
  
  const allResults = state.agentResults
    .map(r => `[${r.role}]\n${r.output}`)
    .join("\n\n---\n\n");
  
  const result = await writerAgent.invoke({
    task: task.description,
    materials: allResults || task.input,
    style: "formal",
  });
  
  const duration = Date.now() - startTime;
  
  return {
    agentResults: [{
      taskId: task.id,
      role: "writer" as const,
      success: true,
      output: result.output,
      duration,
      timestamp: new Date().toISOString(),
    }],
  };
}

export async function synthesizeNode(state: MultiAgentStateType) {
  console.log(`\n📥 协调者: 综合结果`);
  
  const researchOutputs = state.agentResults
    .filter(r => r.role === "researcher")
    .map(r => r.output);
    
  const analysisOutputs = state.agentResults
    .filter(r => r.role === "analyst")
    .map(r => r.output);
    
  const writingOutputs = state.agentResults
    .filter(r => r.role === "writer")
    .map(r => r.output);
  
  const allInsights = state.agentResults
    .flatMap(r => r.insights || []);
  
  const response = await llm.invoke([
    new SystemMessage(`你是一个综合分析专家。请根据多个 Agent 的输出,生成最终的综合报告。

请包含:
1. 执行摘要(200字以内)
2. 关键发现(3-5个要点)
3. 建议与行动项(3-5条)
4. 详细报告`),
    new HumanMessage(`请综合以下内容生成最终报告:

## 研究结果
${researchOutputs.join("\n\n")}

## 分析结果
${analysisOutputs.join("\n\n")}

## 撰写内容
${writingOutputs.join("\n\n")}

## 关键洞察
${allInsights.map((i, idx) => `${idx + 1}. ${i}`).join("\n")}`),
  ]);
  
  const content = response.content as string;
  
  const summaryMatch = content.match(/执行摘要[::]([\s\S]*?)(?=关键|##|$)/i);
  const findingsMatch = content.match(/关键发现[::]([\s\S]*?)(?=建议|##|$)/i);
  const recommendationsMatch = content.match(/建议[::]([\s\S]*?)(?=详细|##|$)/i);
  
  const parseList = (text: string | undefined) =>
    text ? text.split(/\d+\./g).filter(i => i.trim()).map(i => i.trim()) : [];
  
  console.log(`   📝 综合报告生成完成`);
  
  return {
    synthesis: {
      summary: summaryMatch?.[1]?.trim() || content.slice(0, 200),
      keyFindings: parseList(findingsMatch?.[1]),
      recommendations: parseList(recommendationsMatch?.[1]),
      finalReport: content,
    },
    phase: "reviewing" as const,
  };
}

export async function humanReviewNode(state: MultiAgentStateType) {
  console.log(`\n👤 等待人工审核...`);
  
  const reviewData = interrupt({
    type: "final_review",
    message: "请审核最终报告",
    synthesis: state.synthesis,
    agentResults: state.agentResults.map(r => ({
      role: r.role,
      success: r.success,
      duration: r.duration,
    })),
    options: ["approve", "revise", "reject"],
  });
  
  const { action, feedback } = reviewData as {
    action: "approve" | "revise" | "reject";
    feedback?: string;
  };
  
  if (action === "approve") {
    console.log(`   ✅ 人工审核通过`);
    return {
      humanApproval: { required: true, approved: true, feedback },
      phase: "complete" as const,
    };
  }
  
  if (action === "revise") {
    console.log(`   ✏️  需要修改: ${feedback}`);
    return {
      humanApproval: { required: true, approved: false, feedback },
      messages: [new HumanMessage(feedback || "请根据反馈修改")],
      phase: "executing" as const,
    };
  }
  
  console.log(`   ❌ 审核被拒绝: ${feedback}`);
  return {
    humanApproval: { required: true, approved: false, feedback },
    phase: "complete" as const,
  };
}

export function routeAfterExecution(state: MultiAgentStateType): string {
  const completedTasks = state.agentResults.length;
  const totalTasks = state.subTasks.length;
  
  if (completedTasks >= totalTasks) {
    return "synthesize";
  }
  
  return "dispatch";
}

协调者任务分发流程


第五步:构建主图 ​

src/graph.ts ​

typescript
import { StateGraph, START, END, MemorySaver } from "@langchain/langgraph";
import { MultiAgentState } from "./state.js";
import {
  planningNode,
  dispatchNode,
  executeResearcherNode,
  executeAnalystNode,
  executeWriterNode,
  synthesizeNode,
  humanReviewNode,
  routeAfterExecution,
} from "./coordinator.js";

const graph = new StateGraph(MultiAgentState)
  .addNode("planning", planningNode)
  .addNode("dispatch", dispatchNode)
  .addNode("executeResearcher", executeResearcherNode)
  .addNode("executeAnalyst", executeAnalystNode)
  .addNode("executeWriter", executeWriterNode)
  .addNode("synthesize", synthesizeNode)
  .addNode("humanReview", humanReviewNode)
  
  .addEdge(START, "planning")
  .addEdge("planning", "dispatch")
  
  .addEdge("executeResearcher", "synthesize")
  .addEdge("executeAnalyst", "synthesize")
  .addEdge("executeWriter", "synthesize")
  
  .addConditionalEdges("synthesize", (state) => {
    if (state.humanApproval.required) {
      return "humanReview";
    }
    return "end";
  }, {
    humanReview: "humanReview",
    end: END,
  })
  
  .addConditionalEdges("humanReview", (state) => {
    if (state.phase === "executing") {
      return "dispatch";
    }
    return "end";
  }, {
    dispatch: "dispatch",
    end: END,
  });

const checkpointer = new MemorySaver();

export const multiAgentSystem = graph.compile({ checkpointer });

💡 流程图:

START
  │
  ▼
┌──────────────┐
│   planning   │ ← 任务分解
└──────┬───────┘
       │
       ▼
┌──────────────┐
│   dispatch   │ ← 返回 Send[]
└──────┬───────┘
       │
    ┌──┴───────────────────┐
    │          │           │
    ▼          ▼           ▼
┌────────┐ ┌────────┐ ┌────────┐
│Research│ │Analyst │ │Writer  │  ← 并行执行
└───┬────┘ └───┬────┘ └───┬────┘
    │          │           │
    └──────────┴───────────┘
               │
               ▼
        ┌────────────┐
        │ synthesize │ ← 综合结果
        └─────┬──────┘
              │
              ▼
        ┌────────────┐
        │humanReview │ ← 人工审核
        └─────┬──────┘
              │
         ┌────┴────┐
         │         │
      approve   revise
         │         │
         ▼         ▼
        END    dispatch(循环)

主图完整执行生命周期


第六步:入口文件 ​

src/index.ts ​

typescript
import { multiAgentSystem } from "./graph.js";
import { Command } from "@langchain/langgraph";

async function runMultiAgentTask(task: string) {
  console.log("═".repeat(70));
  console.log("🤖 多 Agent 协作系统");
  console.log("═".repeat(70));
  console.log(`\n📋 主任务: ${task}`);
  
  const config = {
    configurable: {
      thread_id: `multi-agent-${Date.now()}`,
    },
  };
  
  const startTime = Date.now();
  
  let result = await multiAgentSystem.invoke(
    {
      mainTask: task,
      humanApproval: { required: true },
    },
    config
  );
  
  while (true) {
    const state = await multiAgentSystem.getState(config);
    
    if (!state.next || state.next.length === 0) {
      break;
    }
    
    const interruptValue = state.tasks?.[0]?.interrupts?.[0]?.value;
    if (interruptValue) {
      console.log("\n" + "─".repeat(70));
      console.log("👤 人工审核");
      console.log("─".repeat(70));
      
      const decision = await simulateHumanReview(interruptValue);
      result = await multiAgentSystem.invoke(
        new Command({ resume: decision }),
        config
      );
    } else {
      break;
    }
  }
  
  const totalTime = Date.now() - startTime;
  
  console.log("\n" + "═".repeat(70));
  console.log("📊 执行结果");
  console.log("═".repeat(70));
  
  console.log(`\n⏱️  总耗时: ${totalTime}ms`);
  console.log(`📝 子任务数: ${result.subTasks?.length || 0}`);
  console.log(`✅ 完成任务: ${result.agentResults?.length || 0}`);
  
  if (result.agentResults && result.agentResults.length > 0) {
    console.log("\n📋 各 Agent 执行情况:");
    result.agentResults.forEach((r: any, i: number) => {
      const icon = r.success ? "✅" : "❌";
      console.log(`   ${i + 1}. ${icon} [${r.role}] ${r.duration}ms`);
      if (r.insights && r.insights.length > 0) {
        console.log(`      洞察: ${r.insights.slice(0, 2).join("; ")}...`);
      }
    });
  }
  
  if (result.synthesis) {
    console.log("\n" + "─".repeat(70));
    console.log("📝 执行摘要:");
    console.log("─".repeat(70));
    console.log(result.synthesis.summary);
    
    if (result.synthesis.keyFindings.length > 0) {
      console.log("\n🔍 关键发现:");
      result.synthesis.keyFindings.forEach((f: string, i: number) => {
        console.log(`   ${i + 1}. ${f}`);
      });
    }
    
    if (result.synthesis.recommendations.length > 0) {
      console.log("\n💡 建议:");
      result.synthesis.recommendations.forEach((r: string, i: number) => {
        console.log(`   ${i + 1}. ${r}`);
      });
    }
    
    console.log("\n" + "─".repeat(70));
    console.log("📄 完整报告:");
    console.log("─".repeat(70));
    console.log(result.synthesis.finalReport);
  }
  
  if (result.humanApproval) {
    console.log("\n" + "─".repeat(70));
    console.log("👤 审核状态:");
    console.log(`   ${result.humanApproval.approved ? "✅ 已通过" : "❌ 未通过"}`);
    if (result.humanApproval.feedback) {
      console.log(`   反馈: ${result.humanApproval.feedback}`);
    }
  }
  
  console.log("\n" + "═".repeat(70));
  
  return result;
}

async function simulateHumanReview(interruptValue: any): Promise<any> {
  console.log(`\n   类型: ${interruptValue.type}`);
  console.log(`   消息: ${interruptValue.message}`);
  
  if (interruptValue.synthesis) {
    console.log(`   摘要预览: ${interruptValue.synthesis.summary?.slice(0, 100)}...`);
  }
  
  if (interruptValue.agentResults) {
    console.log(`   Agent 执行情况:`);
    interruptValue.agentResults.forEach((r: any) => {
      console.log(`      - ${r.role}: ${r.success ? "成功" : "失败"} (${r.duration}ms)`);
    });
  }
  
  await new Promise(r => setTimeout(r, 500));
  
  return {
    action: "approve",
    feedback: "报告内容完整,分析深入,同意发布",
  };
}

async function main() {
  await runMultiAgentTask(
    "分析人工智能对未来教育的影响,并提出应对策略建议"
  );
}

main().catch(console.error);

第七步:运行测试 ​

bash
npm install

npm run dev

预期输出 ​

══════════════════════════════════════════════════════════════════════
🤖 多 Agent 协作系统
══════════════════════════════════════════════════════════════════════

📋 主任务: 分析人工智能对未来教育的影响,并提出应对策略建议

🎯 协调者: 任务规划
   主任务: 分析人工智能对未来教育的影响,并提出应对策略建议
   📋 分解为 3 个子任务:
      1. [researcher] 研究AI在教育领域的应用现状和发展趋势
      2. [analyst] 分析AI对教育的正面和负面影响
      3. [writer] 撰写综合分析报告和策略建议

📤 协调者: 分发任务
   → 分发研究任务: 研究AI在教育领域的应用现状和发展趋势
   → 分发分析任务: 分析AI对教育的正面和负面影响
   → 分发写作任务: 撰写综合分析报告和策略建议

   🔬 执行研究任务: 研究AI在教育领域的应用现状和发展趋势
      🔬 研究 Agent 开始工作...
      ✅ 研究完成,发现 4 个关键点

   📊 执行分析任务: 分析AI对教育的正面和负面影响
      📊 分析 Agent 开始工作...
      ✅ 分析完成

   ✍️  执行写作任务: 撰写综合分析报告和策略建议
      ✍️  写作 Agent 开始工作...
      ✅ 写作完成,2456 字符

📥 协调者: 综合结果
   📝 综合报告生成完成

──────────────────────────────────────────────────────────────────────
👤 人工审核
──────────────────────────────────────────────────────────────────────

   类型: final_review
   消息: 请审核最终报告
   摘要预览: 人工智能正在深刻改变教育领域,从个性化学习到智能评估,AI技术...
   Agent 执行情况:
      - researcher: 成功 (1234ms)
      - analyst: 成功 (1567ms)
      - writer: 成功 (2345ms)
   ✅ 人工审核通过

══════════════════════════════════════════════════════════════════════
📊 执行结果
══════════════════════════════════════════════════════════════════════

⏱️  总耗时: 6234ms
📝 子任务数: 3
✅ 完成任务: 3

📋 各 Agent 执行情况:
   1. ✅ [researcher] 1234ms
      洞察: AI个性化学习系统快速普及; 智能评估工具提升效率...
   2. ✅ [analyst] 1567ms
      洞察: 教育公平性可能受到影响; 教师角色将发生转变...
   3. ✅ [writer] 2345ms

──────────────────────────────────────────────────────────────────────
📝 执行摘要:
──────────────────────────────────────────────────────────────────────
人工智能正在深刻改变教育领域,带来个性化学习、智能评估等创新应用,
同时也引发教育公平、教师角色转变等挑战。本报告综合分析了AI对教育的
多维度影响,并提出了循序渐进、人机协作、重视伦理的应对策略。

🔍 关键发现:
   1. AI个性化学习系统可将学习效率提升40%
   2. 教师角色正从知识传授者转变为学习引导者
   3. 教育资源不平等可能因技术差距而加剧
   4. 学生数据隐私保护成为核心关注点

💡 建议:
   1. 制定AI教育应用的伦理准则和监管框架
   2. 加强教师AI素养培训,实现人机协作
   3. 建立教育AI公共服务平台,促进资源共享
   4. 保护学生数据隐私,确保算法透明可解释

──────────────────────────────────────────────────────────────────────
📄 完整报告:
──────────────────────────────────────────────────────────────────────
[完整的综合报告内容...]

──────────────────────────────────────────────────────────────────────
👤 审核状态:
   ✅ 已通过
   反馈: 报告内容完整,分析深入,同意发布

══════════════════════════════════════════════════════════════════════

完整执行时间线


多 Agent 协作模式详解 ​

架构对比 ​

┌─────────────────────────────────────────────────────────────────┐
│                    多 Agent 协作架构                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│                    ┌──────────────┐                             │
│                    │  协调者 Agent │ ← 任务分解、分发、汇总      │
│                    └──────┬───────┘                             │
│                           │                                     │
│            ┌──────────────┼──────────────┐                      │
│            │              │              │                      │
│            ▼              ▼              ▼                      │
│     ┌──────────┐   ┌──────────┐   ┌──────────┐                  │
│     │研究 Agent│   │分析 Agent│   │写作 Agent│  ← 专业子图      │
│     └─────┬────┘   └─────┬────┘   └─────┬────┘                  │
│           │              │              │                       │
│           └──────────────┼──────────────┘                       │
│                          │                                      │
│                          ▼                                      │
│                   ┌────────────┐                                │
│                   │ 结果汇总   │                                │
│                   └─────┬──────┘                                │
│                         │                                       │
│                         ▼                                       │
│                   ┌────────────┐                                │
│                   │ 人工审核   │                                │
│                   └────────────┘                                │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

协作模式对比 ​

模式特点适用场景
顺序执行Agent 按固定顺序执行有严格依赖关系的任务
并行执行多个 Agent 同时执行可独立完成的子任务
层级协作主 Agent 协调子 Agent复杂的多阶段任务
对等协作Agent 之间平等通信需要频繁交互的任务

四种多 Agent 协作模式对比


项目总结 ​

核心实现 ​

功能实现方式
任务分解协调者 Agent + LLM 规划
并行执行Send API 分发到子图
专业 Agent独立子图封装
结果汇总综合节点 + LLM 整合
人工审核interrupt() + 条件循环

系统架构回顾 ​

┌───────────────────────────────────────────────────────────┐
│                      主图(协调者)                        │
├───────────────────────────────────────────────────────────┤
│                                                           │
│  planning → dispatch → [并行子图] → synthesize → review   │
│                                                           │
├───────────────────────────────────────────────────────────┤
│                        子图层                              │
├───────────────────────────────────────────────────────────┤
│                                                           │
│  ┌────────────┐  ┌────────────┐  ┌────────────┐          │
│  │ Researcher │  │  Analyst   │  │   Writer   │          │
│  │   子图     │  │   子图     │  │   子图     │          │
│  └────────────┘  └────────────┘  └────────────┘          │
│                                                           │
└───────────────────────────────────────────────────────────┘

关键代码模式 ​

Send API 分发:

typescript
function dispatchNode(state: MultiAgentStateType): Send[] {
  return state.subTasks.map(task => 
    new Send(`execute${capitalize(task.role)}`, { currentTask: task })
  );
}

子图调用:

typescript
const result = await researcherAgent.invoke({
  task: task.description,
});

结果汇聚:

typescript
const allResults = state.agentResults
  .map(r => `[${r.role}]\n${r.output}`)
  .join("\n\n");

核心要点回顾 ​

  1. 协调者模式 —— 中央 Agent 负责任务分解、分发和汇总
  2. 子图封装 —— 每个专业 Agent 独立为一个子图
  3. Send API 并行 —— 动态分发任务到不同子图
  4. 结果聚合 —— 追加 Reducer 自动收集所有 Agent 输出
  5. 人工审核闭环 —— interrupt() 实现最终确认

多 Agent 协作核心要点总结


系列教程总结 ​

恭喜你完成了 LangGraph 系列教程 的全部学习!

学习路径回顾 ​

篇章核心内容
基础入门篇LangGraph 概述、安装、快速开始
核心概念篇Graph API、State、Reducer、Edges
工作流模式篇6 种核心工作流模式
持久化与记忆篇Checkpointer、Memory、时间旅行
流式处理篇5 种流模式、Token 流
人机协作篇interrupt()、Command({ resume })
高级架构篇子图、应用结构
开发工具篇LangSmith Studio、部署、可观测性
项目实战篇6 个完整项目实战

掌握的核心技能 ​

  1. ✅ 使用 StateGraph 构建复杂工作流
  2. ✅ 设计合理的状态结构和 Reducer
  3. ✅ 实现持久化和多轮对话记忆
  4. ✅ 使用流式输出提升用户体验
  5. ✅ 通过 interrupt() 实现人机协作
  6. ✅ 使用子图模块化复杂应用
  7. ✅ 使用 Send API 实现动态并行
  8. ✅ 构建自主决策的 Agent
  9. ✅ 设计多 Agent 协作系统

下一步建议 ​

  1. 深入实践 —— 将所学应用到实际项目中
  2. 探索进阶 —— 研究 LangGraph 源码和高级特性
  3. 社区贡献 —— 分享你的经验和最佳实践
  4. 持续学习 —— 关注 LangGraph 的最新更新和功能

感谢你的学习!祝你在 AI 应用开发的道路上越走越远! 🚀

读文档、看源码、写代码,理解 AI Agent 本质 🤖