🔥圻底搞懂 AI AgentLangGraph 从入闚到实战附完敎源码

从零匀始圻底掌握 AI Agent 的构建之道 ------ 让 AI 从「只胜诎」进化到「胜思考、胜行劚、胜记忆」 😊若䜠第䞀次听诎LangChain可以浏览我埀期文章快速构建讀知䜓系

技术栈 LangChain v0.3 | LangGraph v0.2 | Node.js 18+


🚀 代码仓库 & 运行环境

📊 本文所有代码瀺䟋均已䞊䌠 GitHub请攟心食甚

GitHub 仓库地址

🔗 github.com/Lidh1023/no...

运行环境芁求

bash 倍制代码
# 环境芁求
Node.js >= 18.0.0
npm >= 9.0.0

# 克隆代码
git clone https://github.com/Lidh1023/nodejs-basic.git
cd nodejs-basic/langchain-learning

# 安装䟝赖
npm install

# 配眮环境变量创建 .env 文件
DEEPSEEK_API_KEY=your_api_key_here

# 运行瀺䟋
node src/agent.js

䟝赖包版本

包名 版本 诎明
@langchain/langgraph ^0.2.x LangGraph 栞心库
@langchain/core ^0.3.x LangChain 栞心组件
@langchain/deepseek ^0.1.x DeepSeek 暡型支持
zod ^3.x 参数校验
dotenv ^16.x 环境变量管理

💡 Tips: 拉取代码后只需配眮奜 API Key即可盎接运行所有瀺䟋代码


📖 写圚前面

䜠是吊想过这些问题

  • 🀔 䞺什么 ChatGPT 只胜聊倩䞍胜垮我真正做事
  • 🀔 劂䜕让 AI 自己决定什么时候查资料、什么时候计算
  • 🀔 AI Agent 到底是什么和普通的 AI 对话有什么区别
  • 🀔 LangChain Agent 和 LangGraph 到底是什么关系

本文将垊䜠圻底理解 Agent 的抂念、原理和实现

读完本文䜠将胜借

  • ✅ 理解 LangChain 侎 LangGraph 的关系
  • ✅ 掌握 Agent 的本莚和工䜜原理
  • ✅ 掌握 ReAct 暡匏掚理 + 行劚
  • ✅ 䜿甚 LangGraph 构建自己的 Agent
  • ✅ 䞺 Agent 添加记忆功胜实现倚蜮对话
  • ✅ 理解 Agent 侎 Tools 的协䜜关系

📚 文章倧纲

yaml 倍制代码
📖 Part 1: 基础抂念
   ├── LangChain 侎 LangGraph 的关系
   ├── 什么是 Agent
   └── Agent vs 普通 LLM

🔄 Part 2: ReAct 暡匏
   ├── ReAct 暡匏诊解
   └── ReAct 的栞心埪环

🧩 Part 3: Agent 栞心组件
   ├── 组件架构囟
   ├── LLM倧脑
   ├── Tools工具
   ├── State状态
   └── Graph流皋囟

🛠 Part 4: 构建 Agent
   ├── 环境准倇
   ├── 完敎代码瀺䟋
   └── Agent 的工䜜流皋

💟 Part 5: 记忆功胜
   ├── 䞺什么需芁记忆
   ├── MemorySaver 诊解
   └── thread_id 线皋标识

🎯 Part 6: 实战案䟋
   ├── 倚蜮对话机噚人
   ├── 垊记忆的 Agent
   └── 智胜客服 Agent

✅ Part 7: 最䜳实践

❓ Part 8: 垞见问题 FAQ

🚀 Part 9: 进阶䞻题

Part 1: 基础抂念

LangChain 侎 LangGraph 的关系

💡 这是埈倚初孊者的困惑点让我们先把这䞪问题搞枅楚

䞀句话回答

Agent 是䞀䞪通甚抂念䜆圚 LangChain 生态䞭构建倍杂 Agent 的胜力䞻芁由 LangGraph 提䟛。

䞀者的定䜍区别

scss 倍制代码
┌─────────────────────────────────────────────────────────────────┐
│                    LangChain 生态系统                            │
├──────────────────────────────────────────────────────────────────
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                    LangChain                             │   │
│   │                                                         │   │
│   │   📊 基础组件库                                          │   │
│   │   • LLM倧语蚀暡型                                    │   │
│   │   • Prompt提瀺词暡板                                 │   │
│   │   • Tools工具定义                                    │   │
│   │   • Memory记忆组件                                   │   │
│   │   • 简单组合pipe()、RunnableSequence                   │   │
│   │   • 䞻芁倄理线性流皋                                   │   │
│   └─────────────────────────────────────────────────────────┘   │
│                              │                                  │
│                              â–Œ                                  │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                    LangGraph                             │   │
│   │                                                         │   │
│   │   🔄 工䜜流猖排框架                                       │   │
│   │   • 状态管理StateGraph                               │   │
│   │   • 倍杂流皋分支、埪环、并行                            │   │
│   │   • Agent 暡匏ReAct                                  │   │
│   │   • 检查点/记忆Checkpointer                          │   │
│   │   • 䞻芁倄理非线性、有状态的倍杂流皋                    │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

诊细对比

层面 LangChain LangGraph
定䜍 基础组件库 工䜜流猖排框架
提䟛 LLM、Prompt、Tools、Memory 状态管理、埪环、条件分支
流皋 线性流皋 倍杂的非线性流皋
Agent 早期有简单 Agent API 掚荐的 Agent 构建方匏
适甚场景 简单的 Prompt → LLM → Parser 条件分支、埪环迭代、倍杂 Agent

配合䜿甚瀺䟋

javascript 倍制代码
// LangChain 组件
import { ChatDeepSeek } from "@langchain/deepseek";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { DynamicStructuredTool } from "@langchain/core/tools";

// LangGraph 猖排
import { StateGraph, Annotation } from "@langchain/langgraph";

// 组合䜿甚
const llm = new ChatDeepSeek({ model: "deepseek-chat" });
const tools = [
  new DynamicStructuredTool({
    /* ... */
  }),
];
const llmWithTools = llm.bindTools(tools); // LangChain 胜力

const graph = new StateGraph(State) // LangGraph 猖排
  .addNode("agent", async (state) => {
    const response = await llmWithTools.invoke(state.messages);
    return { messages: [response] };
  });

选择指南

场景 选择
简单的 Prompt → LLM → Parser LangChain pipe()
RAG 检玢问答 LangChain
倚步骀生成流皋 䞀者郜可
条件分支逻蟑 LangGraph
埪环/迭代任务 LangGraph
倍杂 Agent LangGraph
倚 Agent 协䜜 LangGraph

䞺什么 Agent 芁甚 LangGraph

Agent 的 ReAct 暡匏需芁

  • ✅ 埪环迭代 - LangGraph 原生支持
  • ✅ 条件分支 - 根据工具调甚结果决定䞋䞀步
  • ✅ 状态管理 - 自劚管理对话历史和䞭闎状态

这些胜力 LangChain 的简单 pipe() 隟以实现䜆 LangGraph 原生支持。

💡 总结 Agent 的抂念和组件 劂 Tools来自 LangChain䜆构建和猖排 Agent 的胜力䞻芁由 LangGraph 提䟛。现圚官方掚荐䜿甚 LangGraph 来构建生产级的 Agent。


什么是 Agent

🀔 䞀句话解释

Agent智胜代理是胜借自䞻思考、决策并执行任务的 AI 系统。

它䞍仅胜"诎"生成文本还胜"做"调甚工具执行操䜜。

圢象比喻

想象䜠雇了䞀䞪助理

类型 行䞺特点
普通 AI 只䌚回答问题"倩气我䞍知道䜠自己查吧"
AI Agent 䌚䞻劚行劚"我垮䜠查䞀䞋... 北京今倩 15°C"

Agent = 有手有脚的 AI

Agent 的栞心胜力

scss 倍制代码
┌─────────────────────────────────────────────────────────────┐
│                      Agent 的栞心胜力                        │
├──────────────────────────────────────────────────────────────
│                                                             │
│  🧠 掚理胜力 (Reasoning)                                    │
│     理解甚户意囟分解任务制定计划                          │
│                                                             │
│  🔧 工具䜿甚 (Tool Use)                                     │
│     调甚倖郚工具搜玢、计算、API、数据库等                   │
│                                                             │
│  🔄 自䞻埪环 (Autonomous Loop)                              │
│     思考 → 行劚 → 观察 → 再思考盎到完成任务                 │
│                                                             │
│  📝 记忆胜力 (Memory)                                       │
│     记䜏对话历史和䞊䞋文保持连莯性                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Agent vs 普通 LLM

关键区别

对比绎床 普通 LLM Agent
胜力蟹界 只胜生成文本 可以调甚工具、执行操䜜
信息来源 仅限训练数据 可获取实时信息搜玢、API
任务执行 䞀问䞀答被劚响应 自䞻规划、倚步执行
决策方匏 无 根据情况自䞻决定䞋䞀步
倍杂任务 隟以倄理 可分解并逐步完成

实际对比瀺䟋

场景甚户问「垮我订䞀匠明倩去䞊海的机祚」

普通 LLM 的回答
markdown 倍制代码
抱歉我无法垮悚订机祚。悚可以通过以䞋方匏预订
1. 访问携皋、去哪儿等眑站
2. 䞋蜜航空公叞 App
3. 拚打航空公叞客服电话
...
Agent 的行䞺
ini 倍制代码
[思考] 甚户想订机祚我需芁
  1. 确讀出发地
  2. 搜玢航班
  3. 选择合适的航班
  4. 完成预订

[行劚 1] 调甚 search_flights(from="北京", to="䞊海", date="明倩")
[观察 1] 扟到 15 䞪航班最䜎价 Â¥550

[行劚 2] 调甚 get_flight_details(flight_id="CA1234")
[观察 2] CA123408:00-10:30¥680

[思考] 需芁甚户确讀航班选择...

[回答] 我扟到了 15 䞪航班掚荐以䞋选项
  - CA123408:00-10:30¥680
  - MU567810:00-12:30¥550
  请问悚想预订哪䞪

Part 2: ReAct 暡匏

ReAct 暡匏诊解

什么是 ReAct

ReAct = Reasoning + Acting掚理 + 行劚

这是构建 Agent 最流行的范匏源自 2022 幎的论文《ReAct: Synergizing Reasoning and Acting in Language Models》。

ReAct 的栞心埪环

倍制代码
┌────────────────────────────────────────────────────────────┐
│                     ReAct 埪环流皋                          │
├─────────────────────────────────────────────────────────────
│                                                            │
│    ┌─────────┐                                             │
│    │ Thought │ 思考分析圓前状态决定䞋䞀步               │
│    └────┬────┘                                             │
│         │                                                  │
│         â–Œ                                                  │
│    ┌─────────┐                                             │
│    │ Action  │ 行劚调甚工具执行操䜜                       │
│    └────┬────┘                                             │
│         │                                                  │
│         â–Œ                                                  │
│    ┌─────────────┐                                         │
│    │ Observation │ 观察获取工具返回的结果                  │
│    └──────┬──────┘                                         │
│           │                                                │
│           â–Œ                                                │
│    ┌──────────────┐                                        │
│    │   再次思考    │ 是吊需芁继续                          │
│    └──────┬───────┘                                        │
│           │                                                │
│     ┌─────┮─────┐                                          │
│     │           │                                          │
│     â–Œ           â–Œ                                          │
│   继续埪环    生成最终答案                                   │
│                                                            │
└────────────────────────────────────────────────────────────┘

具䜓瀺䟋

甚户问北京比䞊海冷倚少床

scss 倍制代码
[Thought 1]
甚户想知道枩床差我需芁
1. 查询北京倩气
2. 查询䞊海倩气
3. 计算枩床差

[Action 1]
调甚 get_weather(city="北京")

[Observation 1]
{"city": "北京", "temperature": "5°C", "condition": "晎倩"}

[Thought 2]
已获取北京枩床 5°C现圚需芁查䞊海

[Action 2]
调甚 get_weather(city="䞊海")

[Observation 2]
{"city": "䞊海", "temperature": "12°C", "condition": "倚云"}

[Thought 3]
北京 5°C䞊海 12°C需芁计算差倌

[Action 3]
调甚 calculator(expression="12 - 5")

[Observation 3]
12 - 5 = 7

[Thought 4]
计算完成䞊海比北京高 7 床可以回答了

[Final Answer]
目前北京气枩 5°C䞊海气枩 12°C䞊海比北京高 7°C。
北京今倩䌚比蟃冷出闚记埗倚穿衣服

䞺什么 ReAct 有效

䌘势 诎明
可解释性 每䞀步思考郜可见䟿于调试和理解
准确性 通过工具获取真实数据避免 LLM 幻觉
灵掻性 可根据䞭闎结果劚态调敎策略
可扩展性 只需添加新工具即可扩展 Agent 胜力

Part 3: Agent 栞心组件

组件架构囟

yaml 倍制代码
┌─────────────────────────────────────────────────────────────┐
│                         Agent 架构                          │
├──────────────────────────────────────────────────────────────
│                                                             │
│  ┌───────────────────────────────────────────────────────┐  │
│  │                      🧠 LLM倧脑                    │  │
│  │  • 理解甚户意囟                                        │  │
│  │  • 掚理和决策                                          │  │
│  │  • 生成回答                                            │  │
│  └───────────────────────────────────────────────────────┘  │
│                             │                               │
│                             â–Œ                               │
│  ┌───────────────────────────────────────────────────────┐  │
│  │                    🔧 Tools工具                    │  │
│  │  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐      │  │
│  │  │  倩气   │ │  搜玢   │ │  计算   │ │ 数据库  │ ...  │  │
│  │  └─────────┘ └─────────┘ └─────────┘ └─────────┘      │  │
│  └───────────────────────────────────────────────────────┘  │
│                             │                               │
│                             â–Œ                               │
│  ┌───────────────────────────────────────────────────────┐  │
│  │                    📋 State状态                    │  │
│  │  • messages: 对话历史                                  │  │
│  │  • 其他䞊䞋文信息                                      │  │
│  └───────────────────────────────────────────────────────┘  │
│                             │                               │
│                             â–Œ                               │
│  ┌───────────────────────────────────────────────────────┐  │
│  │                   🔄 Graph流皋囟                   │  │
│  │  定义节点之闎的流蜬逻蟑                                 │  │
│  └───────────────────────────────────────────────────────┘  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1. LLM倧脑

LLM 是 Agent 的栞心莟莣

  • 理解解析甚户意囟
  • 掚理分析问题制定策略
  • 决策选择合适的工具
  • 生成产出最终回答
javascript 倍制代码
import { ChatDeepSeek } from "@langchain/deepseek";

const llm = new ChatDeepSeek({
  model: "deepseek-chat",
  temperature: 0, // 工具调甚建议䜎枩床
});

2. Tools工具

工具是 Agent 的"双手"扩展 Agent 的胜力蟹界

javascript 倍制代码
import { DynamicStructuredTool } from "@langchain/core/tools";
import { z } from "zod";

// 瀺䟋倩气查询工具
const weatherTool = new DynamicStructuredTool({
  name: "get_weather",
  description: "获取城垂倩气信息。圓甚户询问倩气时䜿甚。",
  schema: z.object({
    city: z.string().describe("城垂名称"),
  }),
  func: async ({ city }) => {
    // 调甚倩气 API
    return JSON.stringify({ city, temp: "15°C", condition: "晎倩" });
  },
});

3. State状态

状态保存 Agent 的"记忆"

javascript 倍制代码
import { Annotation } from "@langchain/langgraph";

const AgentState = Annotation.Root({
  messages: Annotation({
    reducer: (prev, next) => [...prev, ...next], // 环加消息
    default: () => [],
  }),
});

消息类型

类型 诎明
HumanMessage 甚户发送的消息
AIMessage AI 的回倍可胜包含 tool_calls
ToolMessage 工具执行的结果
SystemMessage 系统指什

4. Graph流皋囟

䜿甚 LangGraph 定义 Agent 的执行流皋

javascript 倍制代码
import { StateGraph, START, END } from "@langchain/langgraph";

const graph = new StateGraph(AgentState)
  .addNode("agent", agentNode) // 思考节点
  .addNode("tools", toolNode) // 工具节点
  .addEdge(START, "agent")
  .addConditionalEdges("agent", shouldCallTools, {
    tools: "tools",
    end: END,
  })
  .addEdge("tools", "agent"); // 关键埪环

Part 4: 构建 Agent

环境准倇

bash 倍制代码
# 安装䟝赖
npm install @langchain/langgraph @langchain/core @langchain/deepseek zod dotenv
javascript 倍制代码
// .env 文件
DEEPSEEK_API_KEY = your_api_key;

完敎代码瀺䟋

javascript 倍制代码
/**
 * 䜿甚 LangGraph 构建 ReAct Agent
 */
import { StateGraph, Annotation, START, END } from "@langchain/langgraph";
import { ToolNode } from "@langchain/langgraph/prebuilt";
import { ChatDeepSeek } from "@langchain/deepseek";
import { DynamicStructuredTool } from "@langchain/core/tools";
import { HumanMessage } from "@langchain/core/messages";
import { z } from "zod";
import "dotenv/config";

// 1. 定义工具
const tools = [
  new DynamicStructuredTool({
    name: "get_weather",
    description: "获取城垂倩气",
    schema: z.object({ city: z.string() }),
    func: async ({ city }) => {
      const data = { 北京: "15°C 晎", 䞊海: "20°C 倚云" };
      return data[city] || "22°C 晎倩";
    },
  }),
  new DynamicStructuredTool({
    name: "calculator",
    description: "数孊计算",
    schema: z.object({ expression: z.string() }),
    func: async ({ expression }) => {
      return String(Function(`"use strict"; return (${expression})`)());
    },
  }),
];

// 2. 初始化 LLM 并绑定工具
const llm = new ChatDeepSeek({ model: "deepseek-chat", temperature: 0 });
const llmWithTools = llm.bindTools(tools);

// 3. 定义状态
const AgentState = Annotation.Root({
  messages: Annotation({
    reducer: (prev, next) => [...prev, ...next],
    default: () => [],
  }),
});

// 4. 定义节点
async function agentNode(state) {
  const response = await llmWithTools.invoke(state.messages);
  return { messages: [response] };
}

const toolNode = new ToolNode(tools);

// 5. 定义路由
function shouldCallTools(state) {
  const last = state.messages[state.messages.length - 1];
  return last.tool_calls?.length > 0 ? "tools" : "end";
}

// 6. 构建囟
const graph = new StateGraph(AgentState)
  .addNode("agent", agentNode)
  .addNode("tools", toolNode)
  .addEdge(START, "agent")
  .addConditionalEdges("agent", shouldCallTools, {
    tools: "tools",
    end: END,
  })
  .addEdge("tools", "agent");

// 7. 猖译并䜿甚
const agent = graph.compile();

const result = await agent.invoke({
  messages: [new HumanMessage("北京倩气怎么样")],
});

console.log(result.messages[result.messages.length - 1].content);

代码解析

步骀 1-2定义工具并绑定
javascript 倍制代码
// 创建工具
const tools = [weatherTool, calculatorTool];

// 绑定到 LLM关键
const llmWithTools = llm.bindTools(tools);

bindTools() 告诉 LLM 有哪些工具可甚LLM 䌚

  • 圚需芁时返回 tool_calls
  • 包含工具名称和参数
步骀 3定义状态
javascript 倍制代码
const AgentState = Annotation.Root({
  messages: Annotation({
    reducer: (prev, next) => [...prev, ...next], // 环加
    default: () => [],
  }),
});

䞺什么甚环加暡匏

  • 对话需芁保留历史
  • LLM 需芁完敎䞊䞋文
  • 工具结果需芁远加
步骀 4定义节点
javascript 倍制代码
// Agent 节点调甚 LLM 做决策
async function agentNode(state) {
  const response = await llmWithTools.invoke(state.messages);
  return { messages: [response] };
}

// Tool 节点执行工具䜿甚内眮 ToolNode
const toolNode = new ToolNode(tools);

ToolNode 自劚倄理

  1. 解析 tool_calls
  2. 执行对应工具
  3. 包装结果䞺 ToolMessage
步骀 5定义路由
javascript 倍制代码
function shouldCallTools(state) {
  const last = state.messages[state.messages.length - 1];
  // 有 tool_calls → 去执行工具
  // 没有 → 结束
  return last.tool_calls?.length > 0 ? "tools" : "end";
}
步骀 6构建囟
javascript 倍制代码
const graph = new StateGraph(AgentState)
  .addNode("agent", agentNode)
  .addNode("tools", toolNode)
  .addEdge(START, "agent") // 入口
  .addConditionalEdges("agent", shouldCallTools, {
    tools: "tools",
    end: END,
  })
  .addEdge("tools", "agent"); // 埪环回 agent

关键tools → agent 圢成埪环

这让 Agent 可以倚次调甚工具盎到完成任务。


Agent 的工䜜流皋

流皋囟

scss 倍制代码
                    甚户蟓入
                       │
                       ▌
              ┌────────────────┐
              │   START        │
              └───────┬────────┘
                      │
                      ▌
              ┌────────────────┐
              │   Agent 节点   │◄──────────────┐
              │   (LLM 思考)   │               │
              └───────┬────────┘               │
                      │                        │
                      â–Œ                        │
              ┌────────────────┐               │
              │   路由刀断      │               │
              │ 有 tool_calls? │               │
              └───────┬────────┘               │
                      │                        │
           ┌──────────┮──────────┐             │
           │ Yes                 │ No          │
           â–Œ                     â–Œ             │
    ┌────────────┐        ┌────────────┐       │
    │ Tools 节点 │        │    END     │       │
    │ (执行工具) │         │  蟓出结果   │       │
    └─────┬──────┘        └────────────┘       │
          │                                    │
          └────────────────────────────────────┘
                   工具结果返回

消息流蜬瀺䟋

以「北京倩气怎么样」䞺䟋

javascript 倍制代码
// 初始状态
messages: [
  HumanMessage("北京倩气怎么样")
]

// Agent 节点执行后
messages: [
  HumanMessage("北京倩气怎么样"),
  AIMessage({
    content: "",
    tool_calls: [{ name: "get_weather", args: { city: "北京" } }]
  })
]

// Tools 节点执行后
messages: [
  HumanMessage("北京倩气怎么样"),
  AIMessage({ tool_calls: [...] }),
  ToolMessage({ content: '{"city":"北京","temp":"15°C"}' })
]

// Agent 节点再次执行后最终
messages: [
  HumanMessage("北京倩气怎么样"),
  AIMessage({ tool_calls: [...] }),
  ToolMessage({ content: '...' }),
  AIMessage({ content: "北京今倩倩气晎朗气枩15°C适合出行" })
]

Part 5: 记忆功胜

䞺什么需芁记忆

没有记忆的问题

javascript 倍制代码
// ❌ 没有记忆的对话每次郜是党新的

// 第䞀次对话
await app.invoke({ messages: [new HumanMessage("我叫小明")] });
// AI: "䜠奜小明"

// 第二次对话AI 完党䞍记埗
await app.invoke({ messages: [new HumanMessage("我叫什么名字")] });
// AI: "抱歉我䞍知道䜠的名字䜠还没告诉我呢"  ← 導尬

有记忆后的效果

javascript 倍制代码
// ✅ 有记忆的对话连莯自然

// 第䞀次对话
await app.invoke(
  { messages: [new HumanMessage("我叫小明")] },
  { configurable: { thread_id: "user_001" } }
);
// AI: "䜠奜小明"

// 第二次对话同䞀䞪 thread_idAI 记埗
await app.invoke(
  { messages: [new HumanMessage("我叫什么名字")] },
  { configurable: { thread_id: "user_001" } }
);
// AI: "䜠叫小明呀"  ← 完矎

记忆功胜的应甚场景

场景 描述 䞺什么需芁记忆
客服机噚人 倄理甚户问题 记䜏甚户身仜、之前的问题、倄理进床
䞪人助理 日皋管理、任务跟螪 记䜏甚户偏奜、埅办事项、䞊䞋文
教育蟅富 䞀对䞀教孊 记䜏孊习进床、薄匱点、孊习风栌
枞戏 NPC 亀互匏对话 记䜏剧情进展、玩家选择、关系状态
心理咚询 陪䌎对话 记䜏甚户情况、历史对话、情绪变化

MemorySaver 诊解

什么是 MemorySaver

MemorySaver = 让 AI 记䜏对话历史的工具

想象䞀䞋䜠和朋友聊倩

  • ❌ 没有 MemorySaver每句话 AI 郜圓䜜新对话完党䞍记埗之前诎了什么
  • ✅ 有 MemorySaverAI 胜记䜏䜠诎过的每䞀句话像真人䞀样连莯对话

圢象比喻

less 倍制代码
┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│   📝 MemorySaver 就像䞀本「对话日记」                             │
│                                                                 │
│   ┌───────────────────────────────────────────────────────┐    │
│   │  对话日记 (thread_id: "user_001")                      │    │
│   │  ─────────────────────────────────────────────────    │    │
│   │  [蜮次 1] 甚户: 䜠奜我叫小明                          │    │
│   │          AI:   䜠奜小明有什么可以垮䜠的              │    │
│   │  ─────────────────────────────────────────────────    │    │
│   │  [蜮次 2] 甚户: 我喜欢猖皋                              │    │
│   │          AI:   猖皋埈棒小明䜠䞻芁甚什么语蚀呢       │    │
│   │  ─────────────────────────────────────────────────    │    │
│   │  [蜮次 3] 甚户: 我叫什么名字                          │    │
│   │          AI:   䜠叫小明呀因䞺我记埗              │    │
│   └───────────────────────────────────────────────────────┘    │
│                                                                 │
│   📌 关键点AI 胜回忆起之前诎的"小明"和"喜欢猖皋"              │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

栞心抂念

🔹 Checkpointer检查点噚

通俗解释就像枞戏里的「存档功胜」

  • 枞戏存档保存枞戏进床䞋次可以继续玩
  • Checkpointer保存对话状态䞋次可以继续聊
css 倍制代码
枞戏存档                          LangGraph Checkpointer
─────────                        ─────────────────────
存档䜍眮: 第3关Boss前              存档䜍眮: 第5蜮对话后
角色等级: 50级                     消息历史: [msg1, msg2, ...]
背包物品: [剑, 盟, 药氎]           状态数据: { topic: "猖皋", ... }
🔹 MemorySaver

通俗解释将存档保存圚「内存」里的存档噚

  • 䌘点速床快、䜿甚简单
  • 猺点皋序关闭后存档䞢倱就像没有插记忆卡的枞戏机
javascript 倍制代码
import { MemorySaver } from "@langchain/langgraph";

const memory = new MemorySaver(); // 创建䞀䞪"内存存档噚"

基本䜿甚步骀

javascript 倍制代码
import { StateGraph, Annotation, START, END } from "@langchain/langgraph";
import { MemorySaver } from "@langchain/langgraph"; // 1⃣ 富入

// 2⃣ 创建 MemorySaver 实䟋
const memory = new MemorySaver();

// 3⃣ 定义状态
const ChatState = Annotation.Root({
  messages: Annotation({
    reducer: (prev, next) => [...prev, ...next],
    default: () => [],
  }),
});

// 4⃣ 构建囟
const graph = new StateGraph(ChatState)
  .addNode("chat", chatNode)
  .addEdge(START, "chat")
  .addEdge("chat", END);

// 5⃣ 猖译时䌠入 checkpointer
const app = graph.compile({
  checkpointer: memory, // 关键添加记忆功胜
});

// 6⃣ 调甚时指定 thread_id
const result = await app.invoke(
  { messages: [new HumanMessage("䜠奜")] },
  { configurable: { thread_id: "my_thread_123" } } // 关键指定对话线皋
);

💡 关键理解 compile() 䞍䌠 checkpointer 时应甚没有记忆功胜䌠了才有


thread_id 线皋标识

什么是 thread_id

thread_id 是对话的「身仜证号」甚来区分䞍同的对话。

php 倍制代码
┌─────────────────────────────────────────────────────────────────┐
│                    thread_id 的䜜甚                              │
├──────────────────────────────────────────────────────────────────
│                                                                 │
│   想象䞀䞪客服系统同时服务倚䞪甚户                              │
│                                                                 │
│   甚户 A (thread_id: "user_a_session")                          │
│   ├── "我芁退莧" → AI记䜏                                        │
│   └── "订单号是123" → AI关联到退莧请求                            │
│                                                                 │
│   甚户 B (thread_id: "user_b_session")                          │
│   ├── "掚荐䞀欟手机" → AI记䜏                                     │
│   └── "预算3000" → AI结合掚荐需求                                 │
│                                                                 │
│   䞀䞪甚户的对话完党独立互䞍干扰                               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

thread_id 的呜名建议

javascript 倍制代码
// ✅ 奜的 thread_id 呜名
{
  thread_id: "user_12345";
} // 甚户ID
{
  thread_id: "session_abc123";
} // 䌚话ID
{
  thread_id: "user_12345_chat_1";
} // 甚户ID + 对话序号
{
  thread_id: "order_inquiry_67890";
} // 䞚务类型 + ID

// ❌ 䞍奜的 thread_id 呜名
{
  thread_id: "1";
} // 倪简单容易冲突
{
  thread_id: "test";
} // 䞍具䜓
{
  thread_id: "";
} // 空字笊䞲

倚甚户场景瀺䟋

javascript 倍制代码
const memory = new MemorySaver();
const app = graph.compile({ checkpointer: memory });

// 甚户 A 的对话
async function chatWithUserA() {
  const config = { configurable: { thread_id: "user_a" } };

  await app.invoke({ messages: [new HumanMessage("我是甚户A")] }, config);
  await app.invoke({ messages: [new HumanMessage("我喜欢Python")] }, config);

  // 甚户 A 的对话历史只包含甚户 A 诎的话
}

// 甚户 B 的对话
async function chatWithUserB() {
  const config = { configurable: { thread_id: "user_b" } };

  await app.invoke({ messages: [new HumanMessage("我是甚户B")] }, config);
  await app.invoke({ messages: [new HumanMessage("我喜欢Java")] }, config);

  // 甚户 B 的对话历史只包含甚户 B 诎的话
}

// 䞀䞪甚户的对话互䞍圱响
await chatWithUserA();
await chatWithUserB();

Part 6: 实战案䟋

案䟋 1倚蜮对话机噚人

需求分析

构建䞀䞪胜借

  1. 记䜏甚户名字
  2. 记䜏对话历史
  3. 基于䞊䞋文回答问题

完敎代码

javascript 倍制代码
import { StateGraph, Annotation, START, END } from "@langchain/langgraph";
import { MemorySaver } from "@langchain/langgraph";
import { ChatDeepSeek } from "@langchain/deepseek";
import {
  HumanMessage,
  AIMessage,
  SystemMessage,
} from "@langchain/core/messages";
import "dotenv/config";

// 1. 创建组件
const memory = new MemorySaver();
const llm = new ChatDeepSeek({ model: "deepseek-chat", temperature: 0.7 });

// 2. 定义状态
const ChatbotState = Annotation.Root({
  messages: Annotation({
    reducer: (prev, next) => [...prev, ...next],
    default: () => [],
  }),
});

// 3. 定义聊倩节点
async function chatNode(state) {
  // 添加系统提瀺让 AI 知道芁记䜏䞊䞋文
  const systemPrompt = new SystemMessage(
    "䜠是䞀䞪友奜的助手。请记䜏甚户圚对话䞭提到的信息劂名字、偏奜等" +
      "并圚后续对话䞭自然地䜿甚这些信息。保持对话连莯性。"
  );

  // 组合消息系统提瀺 + 历史消息
  const messagesWithSystem = [systemPrompt, ...state.messages];

  const response = await llm.invoke(messagesWithSystem);
  return { messages: [response] };
}

// 4. 构建囟
const chatbot = new StateGraph(ChatbotState)
  .addNode("chat", chatNode)
  .addEdge(START, "chat")
  .addEdge("chat", END)
  .compile({ checkpointer: memory });

// 5. 对话凜数
async function chat(threadId, userMessage) {
  const config = { configurable: { thread_id: threadId } };

  const result = await chatbot.invoke(
    { messages: [new HumanMessage(userMessage)] },
    config
  );

  // 获取最后䞀条 AI 回倍
  const aiResponse = result.messages[result.messages.length - 1];
  return aiResponse.content;
}

// 6. 测试倚蜮对话
async function main() {
  const threadId = "demo_conversation";

  console.log("🀖 匀始倚蜮对话挔瀺\n");
  console.log("=".repeat(50));

  // 第䞀蜮
  console.log("👀 甚户: 䜠奜我叫小明");
  let response = await chat(threadId, "䜠奜我叫小明");
  console.log(`🀖 AI: ${response}\n`);

  // 第二蜮
  console.log("👀 甚户: 我喜欢猖皋特别是 JavaScript");
  response = await chat(threadId, "我喜欢猖皋特别是 JavaScript");
  console.log(`🀖 AI: ${response}\n`);

  // 第䞉蜮测试记忆
  console.log("👀 甚户: 我叫什么名字我喜欢什么");
  response = await chat(threadId, "我叫什么名字我喜欢什么");
  console.log(`🀖 AI: ${response}\n`);

  console.log("=".repeat(50));
  console.log("✅ 挔瀺完成AI 成功记䜏了甚户信息");
}

main();

执行效果

yaml 倍制代码
🀖 匀始倚蜮对话挔瀺

==================================================
👀 甚户: 䜠奜我叫小明
🀖 AI: 䜠奜小明埈高兎讀识䜠有什么可以垮䜠的吗

👀 甚户: 我喜欢猖皋特别是 JavaScript
🀖 AI: 倪棒了小明JavaScript 是䞪埈奜的选择
      䜠是做前端匀发还是党栈匀发呢

👀 甚户: 我叫什么名字我喜欢什么
🀖 AI: 䜠叫小明䜠喜欢猖皋特别是 JavaScript

==================================================
✅ 挔瀺完成AI 成功记䜏了甚户信息

案䟋 2垊记忆的 Agent

需求分析

构建䞀䞪胜借

  1. 记䜏对话历史
  2. 䜿甚工具计算噚、倩气查询
  3. 倚蜮亀互完成倍杂任务

栞心代码结构

javascript 倍制代码
import { StateGraph, Annotation, START, END } from "@langchain/langgraph";
import { MemorySaver } from "@langchain/langgraph";
import { ToolNode } from "@langchain/langgraph/prebuilt";
import { ChatDeepSeek } from "@langchain/deepseek";
import { DynamicStructuredTool } from "@langchain/core/tools";
import { HumanMessage } from "@langchain/core/messages";
import { z } from "zod";
import "dotenv/config";

// 1. 创建记忆存傚
const memory = new MemorySaver();

// 2. 定义工具
const tools = [
  new DynamicStructuredTool({
    name: "calculator",
    description: "数孊计算",
    schema: z.object({ expression: z.string() }),
    func: async ({ expression }) => {
      return String(eval(expression)); // 泚意生产环境需芁安党倄理
    },
  }),
  // ... 其他工具
];

// 3. 绑定工具到 LLM
const llm = new ChatDeepSeek({ model: "deepseek-chat", temperature: 0 });
const llmWithTools = llm.bindTools(tools);

// 4. 定义状态
const AgentState = Annotation.Root({
  messages: Annotation({
    reducer: (prev, next) => [...prev, ...next],
    default: () => [],
  }),
});

// 5. 定义节点
async function agentNode(state) {
  const response = await llmWithTools.invoke(state.messages);
  return { messages: [response] };
}

const toolNode = new ToolNode(tools);

// 6. 路由凜数
function shouldCallTools(state) {
  const lastMessage = state.messages[state.messages.length - 1];
  return lastMessage.tool_calls?.length > 0 ? "tools" : "end";
}

// 7. 构建囟并添加记忆
const agent = new StateGraph(AgentState)
  .addNode("agent", agentNode)
  .addNode("tools", toolNode)
  .addEdge(START, "agent")
  .addConditionalEdges("agent", shouldCallTools, {
    tools: "tools",
    end: END,
  })
  .addEdge("tools", "agent")
  .compile({ checkpointer: memory }); // 关键添加记忆

// 8. 䜿甚
const config = { configurable: { thread_id: "agent_session_1" } };

// 第䞀蜮计算
await agent.invoke(
  { messages: [new HumanMessage("垮我计算 100 * 5")] },
  config
);

// 第二蜮基于䞊䞋文继续记埗䞊次算了 500
await agent.invoke({ messages: [new HumanMessage("再乘以 2")] }, config);

记忆圚 Agent 䞭的䜜甚

css 倍制代码
┌─────────────────────────────────────────────────────────────────┐
│                 垊记忆的 Agent 执行流皋                          │
├──────────────────────────────────────────────────────────────────
│                                                                 │
│  第䞀蜮对话 (thread_id: "session_1")                            │
│  ──────────────────────────────────────                         │
│  甚户: "垮我计算 100 * 5"                                        │
│    ↓                                                            │
│  Agent 决定调甚 calculator                                       │
│    ↓                                                            │
│  Tool 返回: "500"                                                │
│    ↓                                                            │
│  AI 回倍: "100 × 5 = 500"                                        │
│    ↓                                                            │
│  💟 保存到 memory包含完敎对话                                 │
│                                                                 │
│  第二蜮对话 (同䞀䞪 thread_id)                                    │
│  ──────────────────────────────────────                         │
│  甚户: "再乘以 2"                                                 │
│    ↓                                                            │
│  📖 从 memory 读取历史知道䞊次算了 500                        │
│    ↓                                                            │
│  Agent 理解䞊䞋文调甚 calculator("500 * 2")                    │
│    ↓                                                            │
│  AI 回倍: "500 × 2 = 1000"                                       │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

案䟋 3智胜客服 Agent

场景

电商客服胜查询订单、倄理退欟

javascript 倍制代码
// 订单查询工具
const orderTool = new DynamicStructuredTool({
  name: "query_order",
  description: "查询订单状态",
  schema: z.object({
    order_id: z.string().describe("订单号"),
  }),
  func: async ({ order_id }) => {
    // 调甚订单系统
    return JSON.stringify({
      order_id,
      status: "已发莧",
      shipping: "顺䞰快递",
      expected: "明倩送蟟",
    });
  },
});

// 退欟申请工具
const refundTool = new DynamicStructuredTool({
  name: "request_refund",
  description: "申请退欟",
  schema: z.object({
    order_id: z.string(),
    reason: z.string(),
  }),
  func: async ({ order_id, reason }) => {
    // 调甚退欟系统
    return JSON.stringify({
      refund_id: "RF" + Date.now(),
      status: "审栞䞭",
      message: "退欟申请已提亀预计1-3䞪工䜜日倄理",
    });
  },
});

// 构建客服 Agent
const customerServiceAgent = new StateGraph(AgentState)
  .addNode("agent", agentNode)
  .addNode("tools", new ToolNode([orderTool, refundTool]))
  // ... 其他配眮
  .compile({ checkpointer: memory });

对话瀺䟋

css 倍制代码
甚户我的订单 12345 什么时候到

Agent:
[思考] 甚户查询订单状态需芁调甚订单查询工具
[行劚] query_order(order_id="12345")
[观察] {"status":"已发莧","shipping":"顺䞰","expected":"明倩送蟟"}
[回答] 悚的订单 12345 已经发莧啊由顺䞰快递配送预计明倩送蟟。
       请保持手机畅通快递小哥䌚提前联系悚~

Part 7: 最䜳实践

✅ 1. 工具讟计原则

javascript 倍制代码
// ✅ 奜的工具讟计
const goodTool = {
  // 名称简掁、描述性
  name: "search_products",

  // 描述诊细、包含䜿甚场景
  description:
    "搜玢商品信息。" +
    "圓甚户询问商品价栌、库存、规栌时䜿甚。" +
    "返回商品名称、价栌、库存数量。",

  // 参数每䞪郜有枅晰的 describe
  schema: z.object({
    keyword: z.string().describe("搜玢关键词劂商品名称"),
    category: z.string().optional().describe("商品类别劂'电子产品'"),
    max_results: z.number().optional().describe("最倧返回数量默讀10"),
  }),

  // 返回结构化 JSON
  func: async (params) => {
    const results = await searchProducts(params);
    return JSON.stringify(results);
  },
};

✅ 2. 控制 Agent 行䞺

javascript 倍制代码
// 䜿甚 SystemMessage 讟定 Agent 人讟和行䞺规范
const messages = [
  new SystemMessage(`
䜠是䞀䞪䞓䞚的客服助手。

规则
1. 始终保持瀌貌和䞓䞚
2. 劂果䞍确定请䜿甚搜玢工具查询
3. 涉及退欟等敏感操䜜先确讀甚户身仜
4. 劂果问题超出胜力范囎建议蜬人工客服
  `),
  new HumanMessage(userQuestion),
];

✅ 3. 限制和兜底

javascript 倍制代码
// 讟眮合理的限制
const agent = graph.compile({
  checkpointer: memory,
  recursionLimit: 15, // 最倧埪环次数
});

// 超时倄理
const result = await Promise.race([
  agent.invoke(input),
  new Promise((_, reject) =>
    setTimeout(() => reject(new Error("超时")), 30000)
  ),
]);

✅ 4. 消息状态䜿甚环加 reducer

javascript 倍制代码
// ✅ 正确䜿甚环加 reducer
messages: Annotation({
  reducer: (prev, next) => [...prev, ...next],  // 环加
  default: () => [],
}),

// ❌ 错误䜿甚替换 reducer䌚䞢倱历史
messages: Annotation({
  reducer: (prev, next) => next,  // 替换
  default: () => [],
}),

✅ 5. 限制消息历史长床

javascript 倍制代码
// 圓消息过倚时可胜超出 LLM 䞊䞋文限制
// 解决方案圚节点䞭裁剪历史
async function chatNode(state) {
  // 只保留最近 20 条消息
  const recentMessages = state.messages.slice(-20);

  const response = await llm.invoke(recentMessages);
  return { messages: [response] };
}

✅ 6. 日志和监控

javascript 倍制代码
// 记圕 Agent 的每䞀步操䜜
async function agentNodeWithLogging(state) {
  const startTime = Date.now();

  console.log(`[${new Date().toISOString()}] Agent 匀始思考`);
  console.log(`蟓入消息数: ${state.messages.length}`);

  const response = await llmWithTools.invoke(state.messages);

  console.log(`耗时: ${Date.now() - startTime}ms`);
  console.log(`是吊调甚工具: ${response.tool_calls?.length > 0}`);

  return { messages: [response] };
}

Part 8: 垞见问题 FAQ

Q1: Agent 陷入死埪环怎么办

问题Agent 䞍断调甚工具无法停止

解决方案

javascript 倍制代码
// 方法 1限制最倧迭代次数
const agent = graph.compile({
  recursionLimit: 10, // 最倚 10 次埪环
});

// 方法 2圚路由凜数䞭检查
function shouldCallTools(state) {
  if (state.messages.length > 20) {
    console.log("譊告蟟到最倧消息数区制结束");
    return "end";
  }
  // ... 正垞逻蟑
}

Q2: Agent 选错了工具怎么办

问题Agent 调甚了䞍盞关的工具

解决方案

javascript 倍制代码
// 1. 䌘化工具描述
const weatherTool = {
  name: "get_weather",
  // ❌ 䞍奜的描述
  description: "查询倩气",

  // ✅ 奜的描述
  description:
    "获取指定城垂的倩气信息包括枩床、倩气状况、风力等。" +
    "圓甚户询问倩气、枩床、是吊䞋雚、是吊需芁垊䌞时䜿甚歀工具。",
};

// 2. 䜿甚 SystemMessage 给 Agent 明确指什
const messages = [
  new SystemMessage(
    "䜠是䞀䞪智胜助手。请仔细分析甚户问题选择最合适的工具。" +
      "劂果问题䞍需芁工具盎接回答即可。"
  ),
  new HumanMessage("甚户问题..."),
];

Q3: 劂䜕调试 Agent

javascript 倍制代码
// 1. 圚节点䞭添加日志
async function agentNode(state) {
  console.log("=== Agent 节点 ===");
  console.log("圓前消息数:", state.messages.length);
  console.log("最后䞀条消息:", state.messages.slice(-1));

  const response = await llmWithTools.invoke(state.messages);

  console.log("LLM 返回:", response);
  console.log("tool_calls:", response.tool_calls);

  return { messages: [response] };
}

// 2. 䜿甚 LangGraph 的流匏蟓出查看䞭闎状态
const stream = await agent.stream({
  messages: [new HumanMessage("问题")],
});

for await (const chunk of stream) {
  console.log("Chunk:", JSON.stringify(chunk, null, 2));
}

Q4: 䞺什么 AI 没有记䜏我诎的话

可胜原因

  1. 没有添加 checkpointer
javascript 倍制代码
// ❌ 忘记添加 checkpointer
const app = graph.compile();

// ✅ 正确
const app = graph.compile({ checkpointer: memory });
  1. thread_id 䞍䞀臎
javascript 倍制代码
// ❌ 每次甚䞍同的 thread_id
await app.invoke(input, { configurable: { thread_id: "thread_1" } });
await app.invoke(input, { configurable: { thread_id: "thread_2" } }); // 新线皋

// ✅ 䜿甚盞同的 thread_id
const threadId = "my_conversation";
await app.invoke(input, { configurable: { thread_id: threadId } });
await app.invoke(input, { configurable: { thread_id: threadId } });
  1. 消息 reducer 讟眮错误
javascript 倍制代码
// ❌ 䜿甚替换 reducer
reducer: (prev, next) => next; // 每次郜替换䞢倱历史

// ✅ 䜿甚环加 reducer
reducer: (prev, next) => [...prev, ...next]; // 保留历史

Q5: 皋序重启后记忆䞢倱了

解答MemorySaver 存傚圚内存䞭皋序结束后数据就没了。劂需持久化请䜿甚 SqliteSaver 或其他持久化 Checkpointer。

垞见 Checkpointer 对比

类型 存傚䜍眮 持久化 适甚场景
MemorySaver 内存 ❌ 匀发测试
SqliteSaver SQLite 文件 ✅ 本地应甚
PostgresSaver PostgreSQL ✅ 生产环境
RedisSaver Redis ✅ 高性胜场景
MongoSaver MongoDB ✅ 文档型存傚

Q6: 倚䞪甚户䌚共享记忆吗

䞍䌚只芁䜿甚䞍同的 thread_id每䞪甚户的对话是完党隔犻的。

javascript 倍制代码
// 甚户 A 和甚户 B 䜿甚䞍同的 thread_id
const userAConfig = { configurable: { thread_id: "user_a" } };
const userBConfig = { configurable: { thread_id: "user_b" } };
// 䞀者的对话历史互䞍圱响

Part 9: 进阶䞻题

1. 倚 Agent 协䜜

javascript 倍制代码
// äž» Agent 调床倚䞪子 Agent
const researchAgent = buildResearchAgent();
const writerAgent = buildWriterAgent();
const reviewerAgent = buildReviewerAgent();

// 工䜜流研究 → 写䜜 → 审栞
const workflow = new StateGraph(State)
  .addNode("research", researchAgent)
  .addNode("write", writerAgent)
  .addNode("review", reviewerAgent)
  .addEdge(START, "research")
  .addEdge("research", "write")
  .addEdge("write", "review")
  .addEdge("review", END);

2. 人工介入Human-in-the-Loop

javascript 倍制代码
// 圚关键步骀等埅人工确讀
const graph = new StateGraph(AgentState)
  .addNode("agent", agentNode)
  .addNode("tools", toolNode)
  .addNode("human_review", async (state) => {
    // 等埅人工确讀
    console.log("请确讀是吊执行以䞋操䜜...");
    // 实际应甚䞭这里䌚等埅甚户蟓入
    return { messages: [new HumanMessage("已确讀")] };
  })
  .addConditionalEdges(
    "agent",
    (state) => {
      // 敏感操䜜需芁人工确讀
      const last = state.messages.slice(-1)[0];
      if (isSensitiveOperation(last.tool_calls)) {
        return "human_review";
      }
      return "tools";
    },
    {
      human_review: "human_review",
      tools: "tools",
      end: END,
    }
  );

3. 错误恢倍

javascript 倍制代码
// 工具倱莥时的倄理
async function toolNodeWithRetry(state) {
  const toolNode = new ToolNode(tools);

  try {
    return await toolNode.invoke(state);
  } catch (error) {
    console.log("工具调甚倱莥尝试重试...");

    // 返回错误信息给 Agent让它决定䞋䞀步
    return {
      messages: [
        new ToolMessage({
          content: `工具调甚倱莥: ${error.message}。请尝试其他方法。`,
          tool_call_id: state.messages.slice(-1)[0].tool_calls[0].id,
        }),
      ],
    };
  }
}

4. 并行工具调甚

javascript 倍制代码
// LangGraph 的 ToolNode 自劚支持并行调甚
// 圓 AI 返回倚䞪 tool_calls 时䌚并行执行

// AI 返回
{
  tool_calls: [
    { name: "get_weather", args: { city: "北京" } },
    { name: "get_weather", args: { city: "䞊海" } },
    { name: "get_time", args: {} },
  ];
}

// ToolNode 䌚并行执行这 3 䞪工具调甚

5. 状态查看䞎调试

javascript 倍制代码
// 䜿甚 getState 方法查看圓前状态
const state = await app.getState({ configurable: { thread_id: "my_thread" } });

console.log("圓前状态:", state.values);
console.log("消息数量:", state.values.messages.length);

// 获取所有历史状态检查点
const history = app.getStateHistory({
  configurable: { thread_id: "my_thread" },
});

for await (const checkpoint of history) {
  console.log("æ—¶é—Ž:", checkpoint.createdAt);
  console.log("消息数:", checkpoint.values.messages.length);
  console.log("---");
}

总结

🎯 栞心芁点

  1. LangChain vs LangGraph

    • LangChain 提䟛基础组件LLM、Tools、Prompt
    • LangGraph 提䟛猖排胜力埪环、分支、状态管理
    • 构建倍杂 Agent 掚荐䜿甚 LangGraph
  2. Agent = LLM + Tools + 自䞻决策

    • LLM 莟莣思考和掚理
    • Tools 提䟛执行胜力
    • 埪环机制实现自䞻决策
  3. ReAct 暡匏是 Agent 的栞心

    • Thought → Action → Observation → Thought...
    • 埪环盎到完成任务
  4. MemorySaver 让 Agent 拥有记忆

    • checkpointer 保存对话状态
    • thread_id 区分䞍同对话
    • 消息䜿甚环加 reducer
  5. 工具讟计决定 Agent 胜力

    • 枅晰的描述
    • 合理的参数
    • 皳定的返回栌匏

💡 记䜏这句话

Agent 的区倧䞍圚于它有倚聪明而圚于它胜甚工具做倚少事。

工具越䞰富、越可靠Agent 的胜力就越区。


孊习路埄建议

📁 配套实战文件

🔗 仓库地址github.com/Lidh1023/no...

文件 内容 预计甚时 GitHub 铟接
src/agent.js Agent 入闚 Demo 30 分钟 📄 查看代码
src/langgraph/06-react-agent.js ReAct Agent 诊解 30 分钟 📄 查看代码
src/langgraph/07-memory-basic.js MemorySaver 基础 20 分钟 📄 查看代码
src/langgraph/08-memory-chatbot.js 倚蜮对话机噚人 30 分钟 📄 查看代码
src/langgraph/09-memory-agent.js 垊记忆的 Agent 30 分钟 📄 查看代码
src/tools-demo.js Tools 䜿甚诊解 20 分钟 📄 查看代码

🎯 孊习路线

阶段 1理解抂念1 小时

  1. ✅ 阅读本文档理解 Agent、ReAct、MemorySaver 的抂念
  2. ✅ 运行 src/agent.js观察 Agent 的工䜜过皋
  3. ✅ 尝试修改问题观察 Agent 的䞍同行䞺

阶段 2劚手实践2 小时

  1. 🔥 添加新的工具劂翻译、数据库查询
  2. 🔥 实现䞀䞪特定场景的 Agent劂客服、助手
  3. 🔥 尝试倄理倍杂的倚步骀任务

阶段 3进阶掌握3+ 小时

  1. 💎 å­Šä¹  MemorySaver 实现对话记忆
  2. 💎 实现人工介入的审栞流皋
  3. 💎 探玢倚 Agent 协䜜

参考资源

官方文档

盞关文章

  • 《ReAct: Synergizing Reasoning and Acting in Language Models》
  • 《Tool Learning with Foundation Models》

䜜者寄语

Agent 是 AI 应甚的未来。理解了 Agent䜠就掌握了让 AI "做事"而䞍仅仅是"诎话"的胜力。

从简单的 ReAct Agent 匀始逐步探玢曎倍杂的场景。记䜏

  • 先理解原理再堆功胜
  • 从简单场景匀始逐步增加倍杂床
  • 倚调试、倚观察 Agent 的行䞺

劂果䜠完成了本教皋的所有练习恭喜䜠䜠已经具倇了构建生产级 AI Agent 的基础胜力。

Happy Coding! 🚀


💡 孊习建议: 先理解 LangChain 和 LangGraph 的关系再从简单的 Agent 匀始逐步添加记忆功胜。每䞀步郜观察 AI 是劂䜕"思考"和"行劚"的

盞关掚荐
Python私教2 小时前
把匀源 Agent 打包成"解压双击即甚"的 Windows 䟿携包䞀条呜什的完敎实现
node.js
冬奇Lab3 小时前
Agent 系列18成本䞎性胜䌘化——省钱䞔曎快
人工智胜·llm·agent
颜酱4 小时前
让 Agent 䞍再倱忆LangChain 短期记忆实战
langchain·agent
后䜳浩4 小时前
Hermes vs OpenClaw基于源码的 Agent Loop 党面分析
人工智胜·llm·agent
没事别瞎琢磚5 小时前
十䞀、审计䞎 Run Session——每䞀步操䜜郜被记圕
人工智胜·node.js
没事别瞎琢磚5 小时前
十六、AgentSandbox——把所有暡块䞲起来的猖排类
人工智胜·node.js
江倏尧5 小时前
Peri Code 的工具分层——LLM 面对 50 䞪工具时䌚停止调甚工具
agent
没事别瞎琢磚5 小时前
十二、眑络代理䞎癜名单规则匕擎
人工智胜·node.js
没事别瞎琢磚5 小时前
十四、Git Worktree 隔犻执行
人工智胜·node.js
没事别瞎琢磚6 小时前
十、统䞀 Runner 入口——胜力检测䞎暡匏回退
人工智胜·node.js