一、什么是 Agent 的记忆
在大语言模型(LLM)驱动的智能体(Agent)系统中,记忆(Memory) 是指 Agent 存储、检索和利用历史交互信息的能力。与人类的记忆类似,Agent 的记忆使其能够理解上下文、保持对话连贯性,并基于历史经验做出更合理的决策。
本文基于 LangChain 框架的 InMemoryChatMessageHistory 实现,从变量数据类型的粒度深入剖析 Agent 记忆处理的底层机制。
二、记忆系统的核心数据结构
2.1 消息(Message):记忆的基本单元
消息是构成对话历史的最小单元。在 LangChain 中,消息有多种类型,每种类型对应不同的角色和数据结构。
2.1.1 消息基类结构
每条消息本质上是一个具有以下核心属性的对象:
| 属性名 | 数据类型 | 说明 | |
|---|---|---|---|
content | string | 消息的文本内容 | |
type | string | 消息类型标识,如 'human'、'system'、'ai' | |
name | `string | undefined` | 可选的发送者名称 |
additional_kwargs | Record<string, any> | 额外的关键字参数,用于扩展功能 |
2.1.2 三种核心消息类型
1. SystemMessage(系统消息)
const systemMessage = new SystemMessage("现在开始你的身份是一个友好,幽默的做菜助手...");
- 类型标识:
type = 'system' - 作用:定义 AI 的角色、行为准则和输出风格
- 生命周期:通常在对话开始时设置,贯穿整个会话
- 数据特征:
content为string类型,内容由开发者预设
2. HumanMessage(人类消息)
const userMessage1 = new HumanMessage("你今天吃什么?");
-
类型标识:
type = 'human' -
作用:代表用户输入的消息
-
数据特征:
content:string类型,用户输入的文本- 可包含多媒体内容(图片、文件等),此时
content为数组类型
3. AIMessage(AI 消息)
const response1 = await model.invoke(messages1);
// response1 是 AIMessage 实例
-
类型标识:
type = 'ai' -
作用:代表模型生成的回复
-
数据特征:
content:string类型,模型输出的文本additional_kwargs:可能包含tool_calls(工具调用信息)等扩展字段response_metadata:Record<string, any>类型,包含 token 使用量、完成原因等元数据
2.2 ChatMessageHistory:记忆的容器
InMemoryChatMessageHistory 是 LangChain 提供的内存级消息历史存储类,它是 Agent 短期记忆的核心载体。
2.2.1 内部数据结构
class InMemoryChatMessageHistory extends BaseChatMessageHistory {
private messages: BaseMessage[]; // 核心存储:消息数组
}
| 属性名 | 数据类型 | 说明 |
|---|---|---|
messages | BaseMessage[] | 消息数组,按时间顺序存储所有对话消息 |
- 数据结构本质:一个
BaseMessage类型的数组(Array) - 存储顺序:按对话发生的时间顺序线性存储
- 内存特性:存储在进程内存中,进程结束即丢失
2.2.2 核心方法签名
| 方法名 | 参数类型 | 返回值类型 | 作用 |
|---|---|---|---|
addMessage(message) | BaseMessage | Promise<void> | 向记忆中追加一条消息 |
addMessages(messages) | BaseMessage[] | Promise<void> | 批量追加多条消息 |
getMessages() | 无 | Promise<BaseMessage[]> | 获取全部历史消息 |
clear() | 无 | Promise<void> | 清空所有记忆 |
三、记忆的完整生命周期
3.1 初始化:创建记忆容器
const history = new InMemoryChatMessageHistory();
执行过程:
- 调用构造函数
new InMemoryChatMessageHistory() - 内部初始化一个空数组
messages = [] - 返回一个
InMemoryChatMessageHistory实例
此时的内存状态:
history: InMemoryChatMessageHistory {
messages: [] // length = 0
}
3.2 写入:将消息存入记忆
const userMessage1 = new HumanMessage("你今天吃什么?");
await history.addMessage(userMessage1);
addMessage 的执行流程:
- 参数校验:检查传入的
message是否为BaseMessage类型 - 追加操作:执行
this.messages.push(message) - 异步返回:返回
Promise<void>(内存操作为同步,但接口设计为异步以兼容持久化实现)
写入后的数据结构:
history.messages = [
HumanMessage {
content: "你今天吃什么?",
type: "human",
name: undefined,
additional_kwargs: {}
}
]
// length = 1
3.3 读取:从记忆中检索上下文
const messages1 = [systemMessage, ...(await history.getMessages())];
getMessages 的执行流程:
- 返回
Promise.resolve(this.messages) - 使用展开运算符
...将数组展开 - 与
systemMessage组合成新的消息数组
组合后的数据结构:
messages1: BaseMessage[] = [
SystemMessage { content: "...", type: "system" },
HumanMessage { content: "你今天吃什么?", type: "human" }
]
// length = 2
3.4 模型调用:记忆 + 推理
const response1 = await model.invoke(messages1);
model.invoke() 接收 BaseMessage[] 类型的输入,返回 AIMessage 类型的输出。这一步中,记忆中的消息作为上下文被送入大模型进行推理。
3.5 更新:将回复写回记忆
await history.addMessage(response1);
模型的回复同样需要被写入记忆,以便下一轮对话时作为上下文使用。
更新后的数据状态:
history.messages = [
HumanMessage { content: "你今天吃什么?", type: "human" },
AIMessage { content: "哈哈,今天我推荐...", type: "ai" }
]
// length = 2
四、完整示例的数据流转分析
以代码中的两轮对话为例,我们来追踪记忆容器中数据的完整变化过程。
4.1 初始状态
| 阶段 | history.messages 长度 | 内容类型 |
|---|---|---|
| 初始化完成 | 0 | [] |
4.2 第一轮对话
// 步骤1:用户消息写入
await history.addMessage(userMessage1); // length: 0 → 1
// 步骤2:读取 + 系统消息拼接
const messages1 = [systemMessage, ...(await history.getMessages())];
// messages1.length = 2 (system + human)
// 步骤3:模型推理
const response1 = await model.invoke(messages1);
// response1 类型: AIMessage
// 步骤4:回复写入记忆
await history.addMessage(response1); // length: 1 → 2
第一轮结束后记忆状态:
history.messages: BaseMessage[] (length = 2)
├─ [0] HumanMessage "你今天吃什么?"
└─ [1] AIMessage "哈哈,今天我推荐..."
4.3 第二轮对话
// 步骤1:用户消息写入
await history.addMessage(userMessage2); // length: 2 → 3
// 步骤2:读取 + 系统消息拼接
const message2 = [systemMessage, ...(await history.getMessages())];
// message2.length = 4 (system + human + ai + human)
// 步骤3:模型推理
const response2 = await model.invoke(message2);
// 步骤4:回复写入记忆
await history.addMessage(response2); // length: 3 → 4
第二轮结束后记忆状态:
history.messages: BaseMessage[] (length = 4)
├─ [0] HumanMessage "你今天吃什么?"
├─ [1] AIMessage "哈哈,今天我推荐..."
├─ [2] HumanMessage "推荐一份美食?"
└─ [3] AIMessage "我推荐番茄炒蛋..."
4.4 遍历输出
const allMessages = await history.getMessages();
allMessages.forEach((msg, index) => {
const type = msg.type; // string
const prefix = type === 'human' ? '用户' : '助手'; // string
console.log(`${index+1}.[${prefix}]:${msg.content.substring(0,50)}...`);
});
变量类型分析:
| 变量 | 类型 | 说明 |
|---|---|---|
allMessages | BaseMessage[] | 完整的消息数组 |
msg | BaseMessage | 当前遍历的消息对象 |
index | number | 数组索引,从 0 开始 |
type | string | 消息类型字符串 |
prefix | string | 三元运算符结果,'用户' 或 '助手' |
五、内存级记忆的优缺点
5.1 优点
| 特性 | 说明 | 数据类型视角 |
|---|---|---|
| 读写速度快 | 直接操作内存数组,无 I/O 开销 | Array.push() 时间复杂度 O(1) |
| 实现简单 | 基于原生数组即可实现 | 无需外部依赖数据库 |
| 类型安全 | 运行时保留完整的类实例信息 | instanceof 检查可用 |
5.2 缺点
| 特性 | 说明 | 数据类型视角 |
|---|---|---|
| 易失性 | 进程重启后数据全部丢失 | 内存(RAM)的固有特性 |
| 容量受限 | 受限于进程可用内存 | BaseMessage[] 无限增长会导致 OOM |
| 无法共享 | 单进程独占,多实例间无法共享 | 内存空间隔离 |
| 无持久化 | 对话历史无法保存 | 没有序列化到磁盘的机制 |
六、记忆系统的扩展方向
基于内存级记忆的局限性,实际生产环境中通常会引入更复杂的记忆架构:
6.1 持久化记忆
将 InMemoryChatMessageHistory 替换为持久化实现,如:
RedisChatMessageHistory— 基于 Redis,类型为string的 JSON 序列化存储PostgresChatMessageHistory— 基于关系型数据库,表结构包含id、session_id、message(JSONB 类型)FileChatHistory— 基于本地文件,通常为 JSON 格式
6.2 分层记忆架构
| 记忆层级 | 存储介质 | 数据结构 | 访问速度 | 容量 |
|---|---|---|---|---|
| 短期记忆 | 内存 | BaseMessage[] | 极快 | 小 |
| 中期记忆 | Redis / 数据库 | 序列化后的消息列表 | 快 | 中 |
| 长期记忆 | 向量数据库 | Embedding[] + 原始文本 | 慢 | 大 |
6.3 记忆的修剪与摘要
当消息数组过长时,需要进行记忆管理:
- 滑动窗口:只保留最近 N 条消息(
messages.slice(-N)) - 摘要压缩:用 AI 总结历史对话,用一条摘要消息替换多条原始消息
- 向量检索:将历史消息向量化存储,按需检索相关片段
七、总结
Agent 的记忆系统本质上是一个消息对象数组的生命周期管理过程。从最基础的 InMemoryChatMessageHistory 入手,我们可以看到:
- 记忆的基本单元是消息对象,每条消息有明确的类型(
system/human/ai)和数据结构 - 记忆容器的核心是数组,通过
addMessage和getMessages实现读写 - 每一轮对话都遵循「读取 → 拼接 → 推理 → 写入」的固定流程
- 内存级记忆简单高效但有局限,生产环境需要持久化和分层架构
理解了这些基础的数据类型和流转机制,就能更好地设计和优化 Agent 的记忆系统,让智能体拥有更"聪明"的记忆能力。