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

📖 本章学习目标

  • ✅ 理解 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["对话历史
Messages History"] S["自定义状态
Custom State"] end subgraph Long["长期记忆(跨会话)"] DB["外部存储
Database / Vector Store"] Summary["记忆摘要
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、手动管理消息历史(基础方式)

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

示例代码

typescript 复制代码
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

typescript 复制代码
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

typescript 复制代码
// 配置 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 的组合:

typescript 复制代码
// 最佳实践:用户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 持久化

第一步:安装依赖
bash 复制代码
pnpm add @langchain/langgraph-checkpoint-postgres pg
第二步:配置数据库连接
typescript 复制代码
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 完全一样)
typescript 复制代码
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 字段:

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

局限性:

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

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

实际场景举例:

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

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

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

3、定义自定义状态 Schema

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

完整示例

typescript 复制代码
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 类型:

typescript 复制代码
// 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 中使用自定义状态

typescript 复制代码
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 限制)。

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

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

第一步:初始化向量存储
typescript 复制代码
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 等)
第二步:定义"保存记忆"工具
typescript 复制代码
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(内容和类别)
第三步:定义"检索记忆"工具
typescript 复制代码
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
typescript 复制代码
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:任务相关信息(如正在进行的项目、待办事项等)`,
});
第五步:测试
typescript 复制代码
// 第一轮:保存信息
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

typescript 复制代码
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["完整对话历史
10000 tokens"] --> B["超过阈值?"] B -- 是 --> C["对早期消息生成摘要
500 tokens"] B -- 否 --> D["保留全部历史"] C --> E["摘要 + 最近 N 条消息
2000 tokens"] D --> F["发送给模型"] E --> F

优势:

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

成本对比:

方案 Token 消耗 成本 信息完整性
保留全部历史 10000 tokens $0.10 100%
摘要 + 最近消息 2000 tokens $0.02 80%
仅最近 5 条 500 tokens $0.005 40%

五、常见记忆模式总结

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

1. 决策矩阵

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

2. 组合使用示例

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

typescript 复制代码
// 短期记忆: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。

症状:

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

解决方案:

typescript 复制代码
// 方案 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,他们的对话历史会混在一起。

❌ 危险示例:

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

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

✅ 安全做法:

typescript 复制代码
// 每个用户独立的 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:记忆粒度不当

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

太精细的问题:

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

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

太宽泛的问题:

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

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

✅ 推荐做法:

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

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

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

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

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

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

解决方案:

typescript 复制代码
// 定期清理过期记忆
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核心概念》

相关推荐
70asunflower1 小时前
从Chatbot到Agentic AI:系统架构、商业模式与产业认知的深度拆解
ai·agent
qq_283720051 小时前
Python+LangChain 调用大模型全方案深度实战:原生调用、统一接口、流式输出、异步、自定义模型全解析
人工智能·langchain·agent·rag
葫三生1 小时前
三生原理文章被AtomGit‌开源社区收录的意义探析?
人工智能·深度学习·神经网络·算法·搜索引擎·开源·transformer
handsomestWei1 小时前
harness概念简介
agent·ai编程·harness
冬奇Lab1 小时前
一天一个开源项目(第90篇):cmux - 为 AI Agent 时代设计的原生终端复用器
人工智能·开源·资讯
玉面大蛟龙1 小时前
可复用的 Agent 评测体系:方法论与实践
ai·agent·agent评测·harness ai
Godspeed Zhao1 小时前
具身智能中的传感器技术41——事件相机1
人工智能·科技·机器学习·具身智能·事件相机
Empty-Filled1 小时前
Claude Gateway 排查教程
网络·数据库·人工智能
深海鱼在掘金1 小时前
深入浅出 LangChain —— 第七章:Agent 架构深度解析与LangGraph 核心概念
人工智能·langchain·agent