把 Agent 的记忆写进文件:内存 vs 文件,两把钥匙搞定多会话

把 Agent 的记忆写进文件:内存 vs 文件,两把钥匙搞定多会话

上一篇我讲了 Agent 的 Memory 怎么在上下文预算里做截断 。这一篇换一个方向,讲 Agent 的"记事本"到底存在哪

还是先给结论:同样的对话历史,可以存进内存,也可以落进文件。 存哪个,决定你的 Agent 是"关掉就失忆",还是"重启依然记得你昨天聊过什么"。

我手上有三个 LangChain 的小 demo,正好是一套完整的演进:

  • history-test:内存记忆(最基础)
  • history-test2:文件记忆 · 写入
  • history-test3:文件记忆 · 恢复后续聊

这一篇就顺着这三步,讲透一个概念------记忆的存储介质,决定了 Agent 的生命周期

一个概念:Agent 的"记住"有生命周期

很多刚写 Agent 的人会有个错觉:加个 memory,模型就"一直记住了"。不是的。

Chat 模型本身无状态,所谓的记忆,其实是你每轮把历史塞回 messages。那么问题就变成:这些"塞回去的东西",你存在哪、能活多久?

text 复制代码
内存        -> 快,但程序一停,记忆清零(进程级)
文件 / 存储  -> 慢一点,但能躺着,重启不丢(跨进程、跨会话)
向量库      -> 最"在线",配合检索(RAG + Memory)

这一篇只玩前两个:内存文件

第一站:内存记忆(InMemoryChatMessageHistory

最直接的实现是 InMemoryChatMessageHistory------一个放在内存里的历史对象,你往里 addMessage,再 getMessages 取回来。

js 复制代码
import { ChatOpenAI } from '@langchain/openai';
import { InMemoryChatMessageHistory } from '@langchain/core/chat_history';
import { HumanMessage, SystemMessage } from '@langchain/core/messages';

const history = new InMemoryChatMessageHistory();
const systemMessage = new SystemMessage("你是一个幽默的做菜助手");

// 第一轮
await history.addMessage(new HumanMessage("你今天吃的什么?"));
const messages1 = [systemMessage, ...(await history.getMessages())];
const response1 = await model.invoke(messages1);
await history.addMessage(response1);            // 记得把回复也写回 history

// 第二轮,history 已经带上上一轮记忆
await history.addMessage(new HumanMessage("好吃吗?"));
const messages2 = [systemMessage, ...(await history.getMessages())];
const response2 = await model.invoke(messages2);

console.log(`共保存 ${(await history.getMessages()).length} 条对话`);

关键动作 :每一轮,既要把用户说的话 addMessage,也要把模型的回复 addMessage------否则历史链条会断,模型看不到自己刚才说过什么。

但它有个死穴:InMemory,对象一销毁、进程一停,全没了。 适合单次会话,适合演示,不适合要"记得住"的生产。

第二站:文件记忆,写入(FileSystemChatMessageHistory

要跨进程持久化,LangChain 给了文件版。它的构造函数需要两把钥匙

js 复制代码
const filePath = path.join(process.cwd(), 'chat_history.json');
const sessionId = 'user_session_001';   // 多用户:一个用户一把钥匙

const history = new FileSystemChatMessageHistory({ filePath, sessionId });
  • filePath:记忆写在哪个文件
  • sessionId:同一个文件里,区分"这是谁的会话"

之后 API 和内存版一模一样------addMessage / getMessages 照用,但历史会真正落盘成一个 JSON 文件。

js 复制代码
const systemMessage = new SystemMessage("你是一个幽默的做菜助手");

// 第一轮
await history.addMessage(new HumanMessage("红烧肉怎么做?"));
const messages1 = [systemMessage, ...(await history.getMessages())];
const response1 = await model.invoke(messages1);
await history.addMessage(response1);

// 第二轮,自动带上文件里的历史
await history.addMessage(new HumanMessage("好吃吗?"));
const messages2 = [systemMessage, ...(await history.getMessages())];
const response2 = await model.invoke(messages2);

const all = await history.getMessages();
console.log(`共保存 ${all.length} 条对话`);

跑完你会发现,chat_history.json 里真的多出一段 JSON------对话被写进了硬盘。

第三站:文件记忆,恢复后续聊(history-test3

文件版的真正价值在"换一个进程也能接上 "。重启 Node,重新 new FileSystemChatMessageHistory(同样的 filePath + sessionId),历史就从文件里"回来"了:

js 复制代码
const restoredHistory = new FileSystemChatMessageHistory({ filePath, sessionId });
const restoredMessages = await restoredHistory.getMessages();

console.log(`从文件中恢复了 ${restoredMessages.length} 条历史记录`);
restoredMessages.forEach((msg, i) => {
  console.log(`${i + 1}. ${msg.type === 'human' ? '用户' : '助手'}:` +
              `${msg.content.substring(0, 50)}...`);
});

// 接着续聊第三轮,模型记得前两轮
await restoredHistory.addMessage(new HumanMessage("需要哪些食材"));
const messages3 = [systemMessage, ...(await restoredHistory.getMessages())];
const response3 = await model.invoke(messages3);
await restoredHistory.addMessage(response3);
console.log(response3.content);

看到没?前面两轮的记忆"存活"到了第三轮,因为它躺在文件里,而不是藏在早已销毁的内存对象里。

一张表看懂三站

InMemory FileSystem
存储介质 内存 磁盘 JSON
进程重启 清零 保留,可恢复
多用户区分 需要自己管 sessionId
典型场景 单次会话 / 演示 跨会话、需持久化

一个反直觉的点:记忆"放哪",比"多聪明"更早决定体验

你花大价钱把 prompt 优化得再聪明,如果记忆只存在内存里,用户重启浏览器换个进程,Everything 全忘------体验直接断崖。

所以搭 Agent 的时候,先问的不是"记忆怎么割",而是:这次对话,它该活多久? 活一场 → 内存;活几场 → 文件;要"大海捞针"地记 → 向量库(RAG + Memory)。

而这三种存储介质,管的还是同一件事:把该记得的,从"窗口塞回去"这件事,做得又稳又持久。


相关推荐
天空属于哈夫克31 天前
企业微信二次开发:精准实现关键词自动回复
架构·企业微信
子兮曰1 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
1点东西1 天前
做了近两年的Agent开发,其实真正要学的就是这五件事
llm·agent·ai编程
晨米酱1 天前
AGENTS.md:Agent 的上下文策略层
面试·架构·agent
这个DBA有点耶1 天前
MVCC深入:Read View、版本链与快照读——InnoDB并发控制的内核
数据库·mysql·架构
invicinble1 天前
记录一个学习技术栈的想法和思路
agent
染指11101 天前
122.Agent-LangChain核心组件-中间件-动态提示词(dynamic_promapt)
人工智能·langchain·agent·agents
是Dream呀1 天前
中秋国庆回家不背电脑,用ToDesk远程反连学校设备,查资料、改作业
人工智能·agent·todesk
漂着的圆木1 天前
Agent 功能参与度:Copilot 怎么算
sql·数据分析·agent·githubcopilot·度量
码流子1 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构