深入浅出 LangChain —— 第六章:记忆与状态管理

1 阅读14分钟

📖 本章学习目标

  • ✅ 理解 LLM 的"失忆"问题及其对应用开发的影响
  • ✅ 使用 thread_id 自动管理多轮对话历史
  • ✅ 选择合适的状态持久化方案(MemorySaver vs PostgresSaver)
  • ✅ 扩展 Agent 状态,存储自定义业务数据
  • ✅ 实现基于向量检索的长期记忆系统
  • ✅ 使用摘要记忆控制 Token 消耗
  • ✅ 避免常见的记忆管理陷阱

一、LLM 的"失忆"问题

大语言模型是无状态的。每次 API 调用都是独立的——模型不记得上一次你说了什么,也不知道用户的历史偏好。

1、为什么 LLM 是无状态的?

这个特性在技术上是合理的:

  • 便于横向扩展:每个请求可以路由到不同的服务器
  • 简化架构:不需要维护会话状态
  • 降低成本:无需为每个用户保持连接

但给应用开发带来了挑战。

2、没有记忆管理的后果

如果没有记忆管理,Agent 会:

问题具体表现用户体验
无法维持多轮对话下一轮不知道上一轮说了什么"我刚才不是告诉过你了吗?"
无法记住用户偏好每次都要重新告诉它你喜欢什么格式重复说明,效率低下
无法复现任务结果历史工作结果丢失需要重新执行相同操作

这就有点像你跟一个有严重健忘症的人聊天:

  • 你说:"我叫张三"
  • 他回答:"好的,张三"
  • 下一秒你再问:"我叫什么名字?"
  • 他回答:"我不知道"

这就是没有记忆管理的 Agent 的表现。

3、LangChain.js 的记忆方案

LangChain.js 提供了完整的记忆管理方案,分为两个层次:

flowchart TB
    subgraph Short["短期记忆(当前会话内)"]
        H["对话历史<br/>Messages History"]
        S["自定义状态<br/>Custom State"]
    end

    subgraph Long["长期记忆(跨会话)"]
        DB["外部存储<br/>Database / Vector Store"]
        Summary["记忆摘要<br/>Memory Summary"]
    end

    Agent --> Short
    Agent <-->|读取/写入| Long

    style Short fill:#e8f4fd,stroke:#1890ff,stroke-width:3px
    style Long fill:#f6ffed,stroke:#52c41a,stroke-width:3px

记忆类型对比:

类型作用范围存储位置典型用途
短期记忆当前会话内内存或数据库维持多轮对话连贯性
长期记忆跨会话、跨设备向量数据库记住用户偏好、历史任务

二、短期记忆:对话历史的管理

短期记忆解决的核心问题是:如何让 Agent 在多轮对话中保持上下文连贯

1、手动管理消息历史(基础方式)

最直观的方式是手动拼接消息历史。

示例代码

import "dotenv/config";
import { createAgent } from "langchain";

const agent = createAgent({ 
  model: "openai:gpt-4o", 
  tools: [] 
});

// 第一轮对话
const result1 = await agent.invoke({
  messages: [{ role: "user", content: "我叫张三,今年 28 岁。" }],
});

// 第二轮对话:手动带上第一轮的消息
const result2 = await agent.invoke({
  messages: [
    // 第一轮的用户消息
    { role: "user", content: "我叫张三,今年 28 岁。" },
    
    // 第一轮的 AI 回复
    result1.messages.at(-1)!,
    
    // 第二轮的新问题
    { role: "user", content: "我叫什么名字,多大了?" },
  ],
});

console.log(result2.messages.at(-1)?.content);
// 输出:你叫张三,今年 28 岁。

代码解读:

  • 第 10-12 行:第一轮对话,告知个人信息
  • 第 16-25 行:第二轮对话,手动拼接历史消息
    • 包含第一轮的用户消息
    • 包含第一轮的 AI 回复
    • 添加第二轮的新问题
  • 第 28 行:获取最终回答

问题所在:

  • ❌ 手动维护很繁琐
  • ❌ 容易遗漏历史消息
  • ❌ 代码可读性差

2、使用 thread_id 自动管理(推荐)

LangChain.js 的 Agent 支持通过 thread_id(会话 ID)自动持久化和恢复对话历史,无需手动维护消息列表。

第一步:配置 Checkpointer

import "dotenv/config";
import { createAgent } from "langchain";
import { MemorySaver } from "@langchain/langgraph";

// 创建内存中的状态存储
// 适合开发测试,生产环境用数据库存储
const checkpointer = new MemorySaver();

const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [],
  checkpointer,  // 传入状态持久化器
});

什么是 Checkpointer?

  • Checkpointer 负责保存和恢复 Agent 的状态
  • MemorySaver 是最简单的实现,把状态存在内存中
  • 还有其他实现:PostgresSaverRedisSaver

第二步:使用 thread_id

// 配置 thread_id,同一 thread_id 下的对话会自动保存和恢复
const config = { 
  configurable: { 
    thread_id: "user-zhangsan-session-001" 
  } 
};

// 第一次对话
await agent.invoke(
  { messages: [{ role: "user", content: "我叫张三,喜欢 TypeScript。" }] },
  config  // 传入 thread_id
);

// 第二次对话(历史自动从 checkpointer 恢复)
const result = await agent.invoke(
  { messages: [{ role: "user", content: "我叫什么名字,喜欢什么编程语言?" }] },
  config  // 同一个 thread_id
);

console.log(result.messages.at(-1)?.content);
// 输出:你叫张三,你说你喜欢 TypeScript。

执行流程:

sequenceDiagram
    participant U as 用户
    participant A as Agent
    participant C as Checkpointer

    U->>A: 第一次对话:"我叫张三"
    A->>C: 保存状态(thread_id + messages)
    A-->>U: "好的,张三"
    
    U->>A: 第二次对话:"我叫什么名字?"
    A->>C: 根据 thread_id 恢复状态
    C-->>A: 返回历史消息
    A-->>U: "你叫张三"

优势:

  • ✅ 自动管理历史,无需手动拼接
  • ✅ 代码简洁,可读性好
  • ✅ 支持多会话隔离

💡 thread_id 的设计建议

thread_id 是区分不同会话的唯一标识符。在实际应用中,可以用 userId + sessionId 的组合:

// 最佳实践:用户ID + 会话ID
const config = {
  configurable: {
    thread_id: `user-${userId}-session-${sessionId}`
  }
};

// 示例:
// user-12345-session-abc123
// user-12345-session-def456  (同一用户的不同会话)
// user-67890-session-ghi789  (不同用户)

好处:

  • 既能区分不同用户
  • 也能在同一用户的不同会话间切换
  • 便于调试和问题追踪

3、生产环境的状态持久化

MemorySaver 把状态保存在内存里,进程重启后数据就丢了,只适合开发测试。

方案对比

方案优点缺点适用场景
MemorySaver简单快速,零配置进程重启数据丢失开发测试
PostgresSaver持久化,支持复杂查询需要 PostgreSQL 数据库生产环境首选
RedisSaver高性能,支持过期策略需要 Redis 服务高并发场景
SQLiteSaver轻量级,单文件不支持并发写入小型应用

使用 PostgreSQL 持久化

第一步:安装依赖
pnpm add @langchain/langgraph-checkpoint-postgres pg
第二步:配置数据库连接
import { PostgresSaver } from "@langchain/langgraph-checkpoint-postgres";
import pg from "pg";

// 创建数据库连接池
const pool = new pg.Pool({
  connectionString: process.env.DATABASE_URL,
});

// 创建 PostgresSaver 实例
const checkpointer = PostgresSaver.fromConnString(process.env.DATABASE_URL!);

// 初始化数据库表(只需运行一次)
await checkpointer.setup();

// 创建 Agent
const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [],
  checkpointer,  // 使用 PostgreSQL 持久化
});
第三步:使用(与 MemorySaver 完全一样)
const config = { 
  configurable: { 
    thread_id: "user-12345-session-001" 
  } 
};

// 对话历史会自动保存到 PostgreSQL
await agent.invoke(
  { messages: [{ role: "user", content: "你好!" }] },
  config
);

数据存储位置:

PostgreSQL 中会创建以下表:

  • checkpoints:存储检查点数据
  • checkpoint_blobs:存储大的状态数据
  • checkpoint_writes:存储待写入的操作

⚠️ 重要提示

  • 生产环境必须使用持久化存储
  • 定期备份数据库,防止数据丢失
  • 监控数据库性能,必要时添加索引

三、自定义状态:扩展 Agent 的上下文

除了对话历史,很多时候我们需要在 Agent 的状态里保存业务数据。

1、默认状态结构

LangChain.js Agent 的默认状态只有 messages 字段:

// Agent 的默认状态结构
{
  messages: BaseMessage[]  // 对话历史
}

局限性:

  • 只能存储消息
  • 无法存储用户偏好、任务状态等业务数据

2、为什么要自定义状态?

实际场景举例:

假设你在构建一个智能客服 Agent,需要:

  • 记录用户的会员等级(影响优惠策略)
  • 保存当前的订单号(用于查询订单状态)
  • 标记是否已经验证过用户身份

这些信息不适合放在对话历史中,应该作为独立的状态字段。

3、定义自定义状态 Schema

通过 LangGraph 的 Annotation 可以定义包含更多字段的自定义状态。

完整示例

import { 
  Annotation, 
  MessagesAnnotation 
} from "@langchain/langgraph";

// 定义自定义状态
const AgentState = Annotation.Root({
  // 继承默认的 messages 字段(带消息合并逻辑)
  ...MessagesAnnotation.spec,

  // 添加自定义字段:用户偏好
  userPreferences: Annotation<{
    language: string;
    responseStyle: "concise" | "detailed";
    timezone: string;
  }>({
    reducer: (_, next) => next,  // 简单覆盖更新
    default: () => ({
      language: "zh-CN",
      responseStyle: "concise",
      timezone: "Asia/Shanghai",
    }),
  }),

  // 添加自定义字段:任务上下文
  taskContext: Annotation<string | null>({
    reducer: (_, next) => next,
    default: () => null,
  }),
});

代码分步解读:

  1. 第 9 行:继承默认状态

    • MessagesAnnotation.spec 包含 messages 字段
    • 自带消息合并逻辑(追加新消息)
  2. 第 11-23 行:定义用户偏好

    • 类型:包含语言、回复风格、时区
    • reducer:定义如何更新(这里直接覆盖)
    • default:提供默认值
  3. 第 26-30 行:定义任务上下文

    • 类型:字符串或 null
    • 用于存储当前任务的临时信息

🔍 Annotation 和 Reducer 是什么?

LangGraph 的状态是不可变的,每次更新都产生一个新状态。reducer 定义了如何把旧值和新值合并:

常见 Reducer 类型:

// 1. 直接覆盖(适合普通字段)
reducer: (_, next) => next

// 2. 数组追加(适合消息列表)
reducer: (current, next) => [...current, ...next]

// 3. 对象合并(适合配置项)
reducer: (current, next) => ({ ...current, ...next })

// 4. 自定义逻辑
reducer: (current, next) => {
  // 你的合并逻辑
  return merged;
}

这种设计保证了状态变更的可追踪性,是 LangGraph 能够支持时间旅行调试和断点续传的基础。

4、在 Agent 中使用自定义状态

import { StateGraph } from "@langchain/langgraph";

// 创建工作流
const workflow = new StateGraph(AgentState);

// 添加节点
workflow.addNode("agent", async (state) => {
  // 读取自定义状态
  const preferences = state.userPreferences;
  const taskContext = state.taskContext;
  
  console.log(`用户语言:${preferences.language}`);
  console.log(`回复风格:${preferences.responseStyle}`);
  
  // ...Agent 逻辑
  
  return {
    messages: [...],  // 更新消息
    taskContext: "新任务",  // 更新自定义字段
  };
});

// 编译工作流
const app = workflow.compile();

关键点:

  • 可以在节点中读写自定义状态字段
  • 返回的对象会合并到当前状态
  • 不同类型的字段使用不同的 reducer

四、长期记忆:跨会话的信息持久化

短期记忆只在当前进程有效。当你需要跨会话甚至跨设备保留用户信息时,需要长期记忆。

1、短期记忆 vs 长期记忆

维度短期记忆长期记忆
作用范围当前会话内跨会话、跨设备
存储内容完整对话历史精选的重要信息
存储位置内存或关系数据库向量数据库
检索方式按 thread_id 精确匹配语义相似度检索
典型用途维持对话连贯性记住用户偏好、历史经验

2、基于向量检索的长期记忆

长期记忆的挑战在于:当记忆量很大时,不可能把所有历史都塞进上下文(Token 限制)。

解决方案: 把重要信息以向量形式存储,在需要时通过语义相似度检索最相关的记忆。

让我们以构建一个能记住用户信息的个人助手为例。

第一步:初始化向量存储
import { OpenAIEmbeddings } from "@langchain/openai";
import { MemoryVectorStore } from "langchain/vectorstores/memory";
import { Document } from "@langchain/core/documents";

// 初始化向量存储(作为长期记忆库)
const embeddings = new OpenAIEmbeddings();
const memoryStore = new MemoryVectorStore(embeddings);

说明:

  • OpenAIEmbeddings:将文本转换为向量
  • MemoryVectorStore:内存中的向量存储(生产环境用 Pinecone、Chroma 等)
第二步:定义"保存记忆"工具
import { tool } from "@langchain/core/tools";
import { z } from "zod";

const saveMemory = tool(
  async ({ content, category }) => {
    // 将信息保存到向量存储
    await memoryStore.addDocuments([
      new Document({
        pageContent: content,
        metadata: {
          category,  // 记忆类别
          timestamp: new Date().toISOString(),
        },
      }),
    ]);
    
    return "记忆已保存";
  },
  {
    name: "save_memory",
    description: "保存重要信息到长期记忆,用于将来的对话中使用。适合保存用户偏好、重要事实、任务进度等。",
    schema: z.object({
      content: z.string().describe("要保存的信息内容"),
      category: z.enum(["preference", "fact", "task"]).describe("记忆类别:preference=偏好,fact=事实,task=任务"),
    }),
  }
);

代码解读:

  • 第 4-14 行:执行函数
    • 创建 Document 对象
    • 包含内容和元数据(类别、时间戳)
    • 添加到向量存储
  • 第 17-24 行:元数据
    • 工具名称和描述
    • 参数 Schema(内容和类别)
第三步:定义"检索记忆"工具
const recallMemory = tool(
  async ({ query, k = 3 }) => {
    // 语义搜索相关记忆
    const results = await memoryStore.similaritySearch(query, k);
    
    if (results.length === 0) {
      return "没有找到相关记忆";
    }
    
    // 格式化返回结果
    return results.map((doc, i) =>
      `记忆 ${i + 1}${doc.pageContent}(时间:${doc.metadata.timestamp})`
    ).join("\n");
  },
  {
    name: "recall_memory",
    description: "从长期记忆中检索与当前问题相关的信息。在回答问题前,先调用此工具查看是否有相关历史记忆。",
    schema: z.object({
      query: z.string().describe("检索关键词或问题描述"),
      k: z.number().optional().describe("返回最多几条记忆,默认 3"),
    }),
  }
);

工作原理:

  1. 将查询文本转换为向量
  2. 计算与存储向量的余弦相似度
  3. 返回最相似的 K 条记忆
第四步:创建 Agent
import { createAgent } from "langchain";

const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [saveMemory, recallMemory],
  
  systemPrompt: `你是一个有长期记忆的助手。

行为准则:
1. 当用户告诉你重要信息(姓名、偏好、任务等)时,主动调用 save_memory 保存
2. 当回答问题时,先调用 recall_memory 检索相关的历史记忆,再给出回答
3. 如果检索到相关记忆,在回答中引用这些信息

记忆类别:
- preference:用户偏好(如喜欢的食物、颜色、编程语言的偏好等)
- fact:客观事实(如用户的生日、职业、所在城市等)
- task:任务相关信息(如正在进行的项目、待办事项等)`,
});
第五步:测试
// 第一轮:保存信息
const result1 = await agent.invoke({
  messages: [{ role: "user", content: "我叫张三,是一名前端工程师,喜欢 React 和 TypeScript。" }]
});

// Agent 应该自动调用 save_memory 保存这些信息

// 第二轮:询问之前保存的信息
const result2 = await agent.invoke({
  messages: [{ role: "user", content: "我是做什么工作的?我喜欢什么技术?" }]
});

console.log(result2.messages.at(-1)?.content);
// 输出:你是一名前端工程师,喜欢 React 和 TypeScript。

执行流程:

  1. 第一轮:Agent 识别出这是重要信息,调用 save_memory 保存
  2. 第二轮:Agent 先调用 recall_memory 检索相关记忆
  3. 基于检索到的记忆回答问题

3、对话摘要记忆

当对话历史很长时,全量传入会超出 Context Window。摘要记忆是一种策略:当历史消息超过一定数量,对早期消息做摘要,只保留摘要和最近 N 条消息。

使用 ConversationSummaryBufferMemory

import { ChatOpenAI } from "@langchain/openai";
import { ConversationSummaryBufferMemory } from "langchain/memory";

// 创建摘要记忆
const memory = new ConversationSummaryBufferMemory({
  llm: new ChatOpenAI({ 
    model: "gpt-4o-mini"  // 用小模型做摘要(省钱)
  }),
  maxTokenLimit: 2000,  // 超过 2000 Token 就开始摘要
  returnMessages: true,
});

// 加载历史(包含摘要 + 最近消息)
const { history } = await memory.loadMemoryVariables({});

console.log(history);
// 输出:[
//   SystemMessage { content: "之前的对话摘要:用户介绍了自己的基本信息..." },
//   HumanMessage { content: "最近的一条消息" },
//   AIMessage { content: "最近的回复" }
// ]

工作原理:

flowchart LR
    A["完整对话历史<br/>10000 tokens"] --> B["超过阈值?"]
    B -- 是 --> C["对早期消息生成摘要<br/>500 tokens"]
    B -- 否 --> D["保留全部历史"]
    C --> E["摘要 + 最近 N 条消息<br/>2000 tokens"]
    D --> F["发送给模型"]
    E --> F

优势:

  • ✅ 控制 Token 消耗
  • ✅ 保留关键信息
  • ✅ 平衡成本和效果

成本对比:

方案Token 消耗成本信息完整性
保留全部历史10000 tokens$0.10100%
摘要 + 最近消息2000 tokens$0.0280%
仅最近 5 条500 tokens$0.00540%

五、常见记忆模式总结

根据不同的使用场景,选择合适的记忆方案。

1. 决策矩阵

场景推荐方案说明复杂度
单轮或短对话无需专门管理直接传入 messages
多轮对话(进程内)MemorySaver + thread_id简单快速,开发首选⭐⭐
多轮对话(持久化)PostgresSaver / RedisSaver生产环境必选⭐⭐⭐
跨会话用户记忆向量存储 + recall_memory 工具语义检索,扩展性好⭐⭐⭐⭐
超长历史压缩ConversationSummaryBufferMemory平衡 Token 消耗和上下文保留⭐⭐⭐
结构化业务数据自定义 State + LangGraph需要在状态中存非消息数据⭐⭐⭐⭐

2. 组合使用示例

在实际项目中,通常会组合使用多种方案:

// 短期记忆:PostgreSQL 持久化
const checkpointer = PostgresSaver.fromConnString(DATABASE_URL);

// 长期记忆:向量存储
const memoryStore = new PineconeStore(embeddings);

// 自定义状态:存储业务数据
const AgentState = Annotation.Root({
  ...MessagesAnnotation.spec,
  userId: Annotation<string>(),
  orderId: Annotation<string | null>(),
});

// Agent 配置
const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [saveMemory, recallMemory],
  checkpointer,
});

六、常见踩坑指南

记忆管理看似简单,但有很多隐藏的陷阱。

⚠️ 踩坑 1:Context Window 溢出

问题: 不加限制地累积对话历史,最终会超出模型的 Context Window。

症状:

Error: This model's maximum context length is 128000 tokens. 
However, your messages resulted in 150000 tokens.

解决方案:

// 方案 1:限制消息数量
const MAX_MESSAGES = 20;
if (messages.length > MAX_MESSAGES) {
  messages = messages.slice(-MAX_MESSAGES);  // 只保留最近 20 条
}

// 方案 2:使用摘要记忆
const memory = new ConversationSummaryBufferMemory({
  maxTokenLimit: 2000,  // 设置合理的上限
});

// 方案 3:定期清理不重要的历史
function cleanupHistory(messages: BaseMessage[]) {
  return messages.filter(msg => {
    // 保留系统消息和用户的重要消息
    return msg.role === "system" || isImportantMessage(msg);
  });
}

最佳实践:

  • 设置合理的 Token 上限(通常为 Context Window 的 70-80%)
  • 优先保留最近的消息和系统消息
  • 对长期运行的 Agent,定期清理历史

⚠️ 踩坑 2:thread_id 冲突导致数据泄露

问题: 如果多个用户共用同一个 thread_id,他们的对话历史会混在一起。

❌ 危险示例:

// 所有用户共用一个 thread_id
const config = { 
  configurable: { thread_id: "global-session" } 
};

// 用户 A 说:"我的密码是 123456"
// 用户 B 问:"上一个用户说了什么?"
// 结果:用户 B 能看到用户 A 的密码!

✅ 安全做法:

// 每个用户独立的 thread_id
const config = { 
  configurable: { 
    thread_id: `user-${req.userId}-session-${Date.now()}` 
  } 
};

// 或者更简洁
const config = { 
  configurable: { thread_id: req.userId } 
};

安全检查清单:

  • ✅ thread_id 必须包含用户标识符
  • ✅ 不同用户的 thread_id 绝对不能重复
  • ✅ 在生产环境中进行权限校验
  • ✅ 定期审计访问日志

⚠️ 踩坑 3:记忆粒度不当

问题: 长期记忆的粒度影响检索质量。

太精细的问题:

// 每条消息都保存
saveMemory({ content: "你好", category: "fact" });
saveMemory({ content: "今天天气不错", category: "fact" });
saveMemory({ content: "我吃了午饭", category: "fact" });

后果: 大量无关记忆混入,检索噪音多

太宽泛的问题:

// 一整天的对话保存为一条
saveMemory({ 
  content: "今天聊了很多话题,包括工作、生活、兴趣爱好...", 
  category: "fact" 
});

后果: 关键信息被稀释,检索不准确

✅ 推荐做法:

// 按信息类别分开存储
// 1. 用户偏好(相对稳定)
saveMemory({ 
  content: "用户喜欢 TypeScript 和 React", 
  category: "preference" 
});

// 2. 重要事实(偶尔变化)
saveMemory({ 
  content: "用户是一名前端工程师,在北京工作", 
  category: "fact" 
});

// 3. 当前任务(频繁变化)
saveMemory({ 
  content: "正在开发一个电商网站的项目", 
  category: "task" 
});

// 检索时带类别过滤
recallMemory({ 
  query: "用户的职业是什么?",
  category: "fact"  // 只检索事实类记忆
});

⚠️ 踩坑 4:忘记清理过期记忆

问题: 长期记忆不断累积,占用存储空间,降低检索效率。

解决方案:

// 定期清理过期记忆
async function cleanupOldMemories(daysToKeep = 90) {
  const cutoffDate = new Date();
  cutoffDate.setDate(cutoffDate.getDate() - daysToKeep);
  
  // 删除 90 天前的记忆
  await memoryStore.delete({
    filter: {
      timestamp: { $lt: cutoffDate.toISOString() }
    }
  });
  
  console.log("已清理过期记忆");
}

// 每天凌晨执行
setInterval(cleanupOldMemories, 24 * 60 * 60 * 1000);

七、本章小结

记忆系统让 Agent 从"一次性问答"升级为"有上下文感知的持续对话"。

📝 核心知识点回顾

知识点关键要点适用场景
短期记忆MemorySaver + thread_id 自动管理多轮对话
持久化存储PostgresSaver / RedisSaver生产环境
自定义状态LangGraph Annotation 扩展字段存储业务数据
长期记忆向量存储 + 语义检索跨会话记忆
摘要记忆压缩早期历史,控制 Token超长对话

🎯 动手练习

尝试完成以下练习,巩固所学知识:

练习 1:实现多会话管理 创建一个支持多用户的聊天应用:

  • 每个用户有独立的 thread_id
  • 使用 MemorySaver 管理短期记忆
  • 测试用户 A 和用户 B 的对话不会互相干扰

练习 2:持久化改造 将练习 1 的 MemorySaver 替换为 PostgresSaver

  • 安装 PostgreSQL
  • 配置数据库连接
  • 验证进程重启后对话历史仍然保留

练习 3:长期记忆系统 构建一个能记住用户偏好的助手:

  • 实现 save_memoryrecall_memory 工具
  • 测试保存用户信息(姓名、喜好、职业等)
  • 测试在新会话中检索这些信息

练习 4:摘要记忆优化 模拟一个长对话场景(50+ 轮对话):

  • 不使用摘要:观察 Token 消耗
  • 使用 ConversationSummaryBufferMemory:对比效果
  • 调整 maxTokenLimit,找到最佳的平衡点

📚 延伸阅读


下一章:《第七章 —— Agent 架构深度解析与LangGraph核心概念》