篇四:记忆 —— 让 Agent 记住之前说过什么

前三篇我们解决了 Agent 的三个核心问题:第一篇搞清楚了 Agent 是什么(大模型 + 工具调用能力),第二篇手写了"模型决策 + 代码执行"的循环,第三篇把循环交给了 LangGraph 框架。这一篇我们要解决最后一个问题:怎么让 Agent 记住之前说过什么、做过什么。

先放结论:LangChain 的记忆机制已经发生了根本性变化------旧版 ConversationBufferMemory 已被淘汰,新版记忆是 LangGraph 图状态的一部分,天然支持持久化、断点续跑、多会话隔离。

为什么大模型天生"失忆"

做个实验就能验证:

arduino 复制代码
// 第一次调用
await model.invoke('你好,我叫张三');
// 第二次调用
await model.invoke('我叫什么名字?');

第二次调用时,模型完全不知道"张三"是谁。原因很简单:大模型本身是无状态的,每次调用都是一次全新的请求,它不记得上一轮对话说了什么。

我们平时用的 ChatGPT、通义千问这些产品之所以能"记住",是因为应用程序在模型外面建了一套记忆系统------把每一轮对话存下来,下一次调用时把历史消息一起发给模型。

LangChain 的记忆模块,做的就是这件事。

旧版记忆:ConversationBufferMemory(已淘汰)

早期的 LangChain 用 ConversationBufferMemory 来管理记忆:

javascript 复制代码
// 旧版写法,已废弃
import { ConversationBufferMemory } from 'langchain/memory';
import { ConversationChain } from 'langchain/chains';

const memory = new ConversationBufferMemory();
const chain = new ConversationChain({ llm, memory });
await chain.invoke({ input: '你好,我叫张三' });
await chain.invoke({ input: '我叫什么名字?' }); // 能记住

它的问题很明显:

  • 只能存内存:程序一重启,全部丢失
  • 附加在 Chain 上:和 Agent/Graph 体系割裂,多轮工具调用时记忆容易乱
  • 没有会话隔离:多用户场景下记忆会串
  • 不支持断点恢复:程序崩溃后无法从中间状态继续

所以新版 LangChain 已经把它淘汰了。

新版记忆:LangGraph Checkpoint

新版记忆的核心思路是:把记忆变成图状态的一部分,而不是外挂的组件。

第三篇我们定义的 AgentState 里,messages 字段就是记忆:

javascript 复制代码
const AgentState = {
    messages: {
        value: (x, y) => x.concat(y), // Reducer:追加,不覆盖
        default: () => [],
    },
};

所有节点读写同一个中央状态,多轮对话历史天然就存在 messages 数组里。但这还不够------默认情况下状态只存在于内存,程序重启就丢。要让它持久化,需要加一个 Checkpointer

从内存到数据库:三种存储后端

1. 内存存储(测试用)

ini 复制代码
import { InMemorySaver } from '@langgraph/checkpoint-memory';

const checkpointer = new InMemorySaver();
const app = workflow.compile({ checkpointer });

// 调用时传入 thread_id 区分会话
const config = { configurable: { thread_id: 'session_1' } };
await app.invoke({ messages: [...] }, config);

InMemorySaver 把状态存在内存里,同一个 thread_id 的多次调用能共享历史。但程序重启后数据丢失,只适合测试。

2. SQLite 存储(开发/轻量生产)

ini 复制代码
import { SqliteSaver } from '@langgraph/checkpoint-sqlite';

const checkpointer = SqliteSaver.fromConnString('./agent.db');
const app = workflow.compile({ checkpointer });

一行代码,状态自动持久化到 SQLite 文件。程序重启后,用同一个 thread_id 调用,能完整恢复之前的对话历史和工具调用记录。

3. PostgreSQL 存储(生产环境)

ini 复制代码
import { PostgresSaver } from '@langgraph/checkpoint-postgres';

const checkpointer = PostgresSaver.fromConnString(
    'postgresql://user:pass@localhost:5432/mydb'
);
checkpointer.setup(); // 自动创建表结构
const app = workflow.compile({ checkpointer });

setup() 会自动创建四张表:

  • checkpoints:主表,存每个 thread 的 checkpoint 快照
  • checkpoint_blobs:存复杂 channel 值(比如很长的消息列表)
  • checkpoint_writes:存中间写入/pending writes
  • checkpoint_migrations:迁移版本表

生产环境推荐 PostgreSQL,支持 ACID 事务、高可用、水平扩展。

实战:让 Agent 记住用户名字

arduino 复制代码
import { createAgent } from '@langchain/core/agents';
import { InMemorySaver } from '@langgraph/checkpoint-memory';

const agent = createAgent({
    model: modelWithTools,
    tools: [readFileTool],
    checkpointer: new InMemorySaver(),
});

const config = { configurable: { thread_id: 'user_zhangsan' } };

// 第一轮
await agent.invoke({
    messages: [new HumanMessage('你好,我叫张三')],
}, config);

// 第二轮------Agent 能记住
const result = await agent.invoke({
    messages: [new HumanMessage('我叫什么名字?')],
}, config);

console.log(result.messages[result.messages.length - 1].content);
// 输出:你叫张三。

关键点:

  • checkpointer:创建 Agent 时传入,开启记忆功能
  • thread_id :调用时通过 config.configurable.thread_id 传入,区分不同用户/会话
  • 同一个 thread_id 的多次调用共享状态 ,不同 thread_id 完全隔离

记忆的两个维度:短期 vs 长期

上面的 Checkpoint 机制解决的是短期记忆 (线程级上下文)------记住当前会话里之前说了什么。但生产环境还需要长期记忆

维度 存储位置 作用
短期记忆 Checkpointer(内存/SQLite/Postgres) 记住当前会话的对话历史
长期记忆 LangGraph Store / 向量数据库 记住跨会话的用户偏好、关键事实

长期记忆的典型实现是用 LangGraph Store,通过 store.put()store.search() 主动读写:

csharp 复制代码
// 存储用户偏好
await store.put(['user_preferences', 'user_123'], 'likes_music', {
    value: '轻音乐',
    context: '用户主动声明',
});

// 检索用户偏好
const prefs = await store.search(['user_preferences', 'user_123']);

短期记忆保证"当前对话不断片",长期记忆保证"换了会话还记得你是谁"。两者配合,Agent 才真正拥有"记忆"。

记忆管理的三个策略

对话轮次多了之后,messages 数组会越来越长,最终超出模型的上下文窗口。这时候需要管理策略:

窗口截断:只保留最近 N 轮对话,自动淘汰老旧内容。简单粗暴,但会丢失早期关键信息。

摘要压缩:用 LLM 把历史对话生成摘要,用摘要替代原始消息。节省 Token,但可能丢失细节,且每轮都要额外调用一次模型。

混合策略(生产首选) :近期对话完整保留(窗口模式),超出窗口的历史自动生成摘要。兼顾细节保留与长度控制。

小结

  • 旧版 ConversationBufferMemory 已淘汰,新版记忆是 LangGraph 图状态的一部分
  • 短期记忆靠 CheckpointerInMemorySaver(测试)、SqliteSaver(开发)、PostgresSaver(生产),通过 thread_id 区分会话
  • 长期记忆靠 LangGraph Store:跨会话存储用户偏好、关键事实
  • 记忆管理三策略:窗口截断、摘要压缩、混合策略(生产首选)
相关推荐
武子康1 小时前
TP、PP、DP、EP 如何组合:八张卡,怎样淘汰不合适的配置
人工智能·llm·agent
爱丶不疚2 小时前
Skill的形态有哪些?什么样的Skill 叫做好Skill?
人工智能·agent
粥里有勺糖2 小时前
视野修炼第133期 | Native 回春了?
前端·github·agent
李溪白2 小时前
篇三:从手写循环到 LangGraph —— 把 Agent 循环交给框架
agent
4SAPI2 小时前
大模型接口管理平台推荐:多模型时代的API Gateway架构与选型分析
人工智能·agent
Luhui Dev3 小时前
大模型 Token 与成本优化工程指南
人工智能·ai·agent·luhuidev
星火10244 小时前
【从 0 到 1 动手造 Agent】(组件篇)06、向量库:让 Agent 按「意思」找东西
人工智能·agent
蜡台4 小时前
AI Agent:大模型基础、底层架构与核心工作原理(深度技术拆解)
ai·agent