Skip to content
Agent 记忆架构:状态管理、长期记忆与知识积累机制
Agent 记忆架构需要解决三类问题:在多轮交互中保持状态,在跨会话场景中积累知识,在有限的上下文窗口中高效利用信息。这些问题分别对应状态管理、长期记忆和知识积累三条主线。
1. 概述
基于大语言模型(LLM)的 Agent 以“感知-思考-行动”的循环方式运行。每一次循环都需要接收来自环境或用户的消息,结合当前目标与已有知识,生成下一步动作。没有记忆的 Agent 在每次请求时都会丢失此前交互的信息,因此无法进行多轮对话、延续任务或从历史经验中改进。
记忆架构为 Agent 提供以下能力:
- 跨步骤保持连续性;
- 将重要信息从短期上下文转移到长期存储;
- 在需要时检索并恢复相关信息;
- 通过遗忘或压缩控制存储增长与噪声。
2. 记忆的基本概念与分类
2.1 工作记忆与长期记忆
工作记忆(Working Memory)是 Agent 在当前一次运行或一个会话中保留的信息。它通常位于上下文窗口内,表现为对话历史、中间推理结果和当前任务状态。工作记忆容量受限于模型的上下文窗口长度。
长期记忆(Long-term Memory)是跨会话保留的信息。它可以存储在外部系统(如数据库、向量索引、文件)中,并在需要时被检索注入上下文。长期记忆不受上下文窗口限制,但需要显式的写入、检索和更新机制。
边界并不固定:一段信息在工作记忆中出现多次后,可以被提炼成长期记忆;长期记忆被检索后,又临时进入工作记忆。这个边界由 Agent 的记忆管理策略决定。
2.2 语义记忆、情景记忆与程序性记忆
一种常见的划分方式来自认知科学:
- 情景记忆(Episodic Memory):记录具体发生过的事件。例如“用户昨天询问了退款政策”。
- 语义记忆(Semantic Memory):记录一般性事实和概念。例如“用户喜欢用 Markdown 写笔记”。
- 程序性记忆(Procedural Memory):记录如何完成某类任务的流程或工具使用方法。例如“遇到计算错误时先检查单位转换”。
这种分类有助于设计不同的存储结构:情景记忆适合用带时间索引的事件表;语义记忆适合用向量数据库或知识图谱;程序性记忆则可能体现为 Agent 的工作流或工具调用模板。
2.3 记忆与上下文窗口的关系
上下文窗口是 LLM 的硬性约束。Agent 无法把全部历史信息放入上下文,因此需要选择“对当前决策最有帮助”的信息。记忆系统的一个核心功能就是执行这种选择:从长期存储中召回候选信息,再按相关性或重要性排序,最终拼装成不超过窗口限制的上下文。
上下文窗口越大,工作记忆能够容纳的原始信息越多,但这不意味着长期记忆不再必要。长期记忆的价值在于跨会话持久化,而非单纯扩容。
3. 状态管理:Agent 循环中的状态追踪
3.1 状态表示与状态转移
状态是 Agent 在某一时刻的数据快照。它可能包括对话消息、用户信息、任务进度、中间结果、工具返回值等。在框架层面,状态通常被定义为一个可序列化的对象或类型。
以 TypeScript 为例,一个简单状态可以定义为:
typescript
interface AgentState {
messages: Array<{ role: string; content: string }>;
currentStep: string;
taskProgress: Record<string, unknown>;
userPreferences?: Record<string, unknown>;
}状态转移发生在 Agent 循环的各个节点:接收消息、调用工具、更新进度、生成回复。每一次转移都产生一个新状态,旧状态可以丢弃或保存。
3.2 检查点与状态恢复
检查点(Checkpoint)是保存某个时刻状态副本的机制。它的用途包括:
- 从失败中恢复;
- 支持人工介入后的回退;
- 多轮会话的连续运行。
根据 LangGraph 官方文档,检查点由 Checkpointer 组件管理。一个线程(Thread)对应一条连续的会话链,线程 ID 用于区分不同会话。每次运行结束时,图引擎会把状态写入检查点存储;下一次使用相同线程 ID 运行时,可以读取之前的状态继续执行。
以下是一个使用 LangGraph 的 Python 示意(LangGraph 同样提供 TypeScript API):
python
from langgraph.checkpoint.memory import InMemorySaver
checkpointer = InMemorySaver()
graph = workflow.compile(checkpointer=checkpointer)
config = {"configurable": {"thread_id": "thread-1"}}
# 假设图的状态中包含一条 conversation 列表
initial_state = {"conversation": [{"role": "user", "content": "你好"}]}
result = graph.invoke(initial_state, config)
# 后续调用同一 thread_id,可以基于上次的状态继续注意:InMemorySaver 只在进程内有效,服务重启后信息丢失。若需要持久化,应使用 SqliteSaver、PostgresSaver 等后端。此外,检查点会持续增加,需要定期清理旧检查点,否则存储会无限增长。
3.3 状态序列化与持久化
将状态写入外部存储时,需要把状态对象序列化为 JSON、字节串或数据库记录。序列化时需要注意:
- 状态中不能包含不可序列化对象(如数据库连接、文件句柄);
- 大字段需要拆分或压缩;
- 需要记录状态版本,以便在 Agent 逻辑升级后执行数据迁移。
持久化后端可以是关系数据库、对象存储或文档数据库。选择依据是读写频率、事务要求和部署环境。
4. 长期记忆的存储方案
4.1 向量数据库与语义索引
向量数据库将文本嵌入为高维向量,并支持相似度检索。它适合存储语义记忆,因为用户可能会用不同的措辞表达同一意图。
一个基本的写入与检索流程是:
- 将文本分块;
- 调用嵌入模型生成向量;
- 将向量和原文存入向量数据库;
- 查询时,将查询文本编码为向量,执行 top-k 相似度搜索。
使用 Node.js 时的伪代码:
typescript
import { embed } from "some-embedding-api";
import { VectorStore } from "some-vector-store";
async function saveMemory(text: string) {
const embedding = await embed(text);
await vectorStore.insert({ id: randomUUID(), text, embedding });
}
async function retrieveMemory(query: string, k = 5) {
const embedding = await embed(query);
return vectorStore.search(embedding, k);
}文本分块长度、嵌入模型和相似度阈值都会影响召回质量。向量数据库负责快速搜索,但不承担语义理解,因此常与关键词检索组合使用。
4.2 图数据库与关系数据库
图数据库适合存储实体及其关系,例如“用户A 喜欢 产品B”“产品B 属于 团队C”。这种结构支持多跳查询,适合构建知识图谱。关系数据库则适合存储结构化事实、事件日志和时间序列。
例如,情景记忆可以用关系表保存:
sql
CREATE TABLE episodic_memory (
id INTEGER PRIMARY KEY,
agent_id TEXT,
user_id TEXT,
event TEXT,
created_at TIMESTAMP
);图数据库和关系数据库都可以与向量检索结合:先通过向量检索找到候选实体,再通过图遍历获取关联信息。
4.3 混合存储架构
实际系统通常使用混合架构:
- 短期检查点:存储在内存或键值存储中,保留最近若干轮;
- 事件日志:追加到文档数据库或对象存储,作为原始记录;
- 语义索引:由事件经过摘要和嵌入后得到,存入向量数据库;
- 知识图谱:从事件中抽取实体关系,存入图数据库。
混合架构的写入流程可以概括为:原始消息先进入上下文,随后被异步处理,生成摘要、嵌入和图谱三元组,分别写入不同存储。查询时,从多个存储检索候选信息,再做融合排序。
5. 记忆的写入、检索与遗忘
5.1 记忆写入与编码
记忆写入不是简单地把原文存下来。由于存储容量和检索效率有限,Agent 需要对信息进行编码:
- 选择关键信息:过滤寒暄、噪声和无意义内容;
- 归一化:统一实体名称、时间格式;
- 结构化:提取为三元组、事件记录或摘要文本。
编码方式决定后续检索的上限。如果写入时没有提取实体,后续就无法按实体查询;如果没有生成摘要,后续只能检索原始片段。
5.2 检索技术:相似度、重排与混合检索
检索的目标是从长期存储中找到与当前问题相关的记忆。常用策略包括:
- 向量相似度检索:适合语义匹配;
- 关键词/全文检索:适合精确匹配,如用户名、订单号;
- 图遍历:适合关系推理;
- 重排序(Rerank):先用粗粒度方法召回较多候选,再用精排模型重新打分,保留 top-k。
一个典型的混合检索流程是:
- 对查询同时执行向量检索和关键词检索;
- 合并两个结果集;
- 去重后按融合分数重排;
- 截取前 k 条作为上下文。
可选地,可以在最后一步调用 LLM 对候选记忆进行相关性判断,但这会增加延迟和成本。
5.3 遗忘策略与冲突消解
记忆存储不能无限增长,需要遗忘机制。遗忘策略包括:
- 时效衰减:超过一定时间的记忆降低权重;
- 访问频率:长期未被访问的记忆被归档或删除;
- 容量上限:达到容量阈值后淘汰最不重要的记忆;
- 摘要合并:将多条旧记忆压缩为一条高级摘要。
冲突消解发生在多个记忆互相矛盾时。例如,用户先表示“喜欢咖啡”,后又说“戒咖啡了”。Agent 需要根据时间戳或明确的更正信息判定后写优先,或保留带冲突标记的记录,让模型在推理时自行判断。
6. 知识积累机制
6.1 自动摘要与信息抽取
在多轮对话中,Agent 可以把对话历史提炼为结构化笔记。例如,将“我下个月去上海出差,需要订一个离虹桥机场近的酒店”抽取为:
用户行程:城市=上海,目的=出差,偏好=离虹桥机场近,时间=下个月自动摘要有两种做法:
- 基于规则:使用正则或小型模型抽取实体和关键词;
- 基于 LLM:使用提示词让模型生成摘要或 JSON 结构。
LLM 摘要可以生成更概括的内容,但需要注意幻觉和遗漏。抽取结果应经过校验再写入长期存储,避免污染知识库。
6.2 知识图谱构建
知识图谱是知识积累的高级形态。Agent 从记忆文本中抽取“实体-关系-实体”三元组,将分散的信息连接成可推理的网络。例如,从多个对话中抽取:
- (小明, 喜欢, 极简风格)
- (小明, 计划去, 上海)
- (上海, 有, 虹桥机场)
图数据库可以回答“小明在去上海时可能关心哪些交通信息”这类跨记忆查询。构建流程包括实体识别、关系抽取、消歧和融合。
6.3 记忆与 RAG 的融合
检索增强生成(RAG)将外部知识注入上下文。Agent 的长期记忆可以被视为一种特殊的外部知识源,因此记忆模块与 RAG 常常共用同一套基础设施。
区别在于:RAG 通常面向静态文档库,而 Agent 记忆面向动态、个人化、随交互更新的数据。记忆系统需要处理写入路径、更新通知和删除同步。融合方式有两种:
- 将记忆存储作为 RAG 的检索源之一;
- 在 RAG 检索结果中过滤和重排与当前用户或任务相关的记忆。
无论哪种方式,都需要一个统一的查询接口,让 Agent 能够同时访问文档库、对话记忆和知识图谱。
7. 工程实践:主流框架与模块设计
7.1 LangGraph 的 Checkpointer 与 Store
LangGraph 是用于构建有状态 Agent 图的框架。根据其官方文档,持久化层分为两部分:
- Checkpointer:保存图的实时状态,用于短期、线程范围内的记忆。典型应用包括多轮对话的连续性和断点恢复。
- Store:保存跨线程的长期数据,例如用户偏好、事实和共享知识。Store 是键值式存储,可以通过命名空间组织数据。
官方文档给出的 Quickstart 示例(Python)如下:
python
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.store.memory import InMemoryStore
checkpointer = InMemorySaver()
store = InMemoryStore()
graph = workflow.compile(checkpointer=checkpointer, store=store)
config = {"configurable": {"thread_id": "thread-1"}}
# 在某个节点中,可以通过 store 的命名空间写入长期记忆
result = graph.invoke(initial_state, config)具体写入接口由 Store 后端提供,例如 store.put(namespace, key, value)。不同版本的 API 可能调整,使用时以官方文档为准。定义值对象时,应保证数据格式一致,例如使用 Pydantic 或 dataclass。
注意:InMemorySaver 和 InMemoryStore 都是内存实现,服务重启后数据丢失。若需要跨重启持久化,应使用 PostgresSaver、SqliteSaver 等后端。此外,checkpoint 会持续增长,建议设置定时清理任务,删除超过保留期限的 checkpoint。
7.2 MemGPT/Letta 的虚拟上下文管理
MemGPT 项目提出了“虚拟上下文”的概念,并在后续以 Letta 名义继续发展。该设计把 LLM 的上下文窗口视为操作系统的内存,将外部存储视为磁盘。Agent 根据当前上下文是否溢出,决定将哪些信息保存到外部存储(“换出”)或从外部存储读回(“换入”)。
这种设计模仿操作系统中的分页机制,使 Agent 可以处理超出上下文窗口的长时间对话。根据 MemGPT 的设计,其核心机制包括:
- 主上下文:当前正在使用的消息和工具调用;
- 外部上下文:存储在数据库中的历史消息、摘要和事实;
- 自我编辑:Agent 调用记忆管理工具,主动写入、搜索或删除记忆。
Letta 将这一设计实现为平台,支持定义记忆模块和自动管理工具。工程集成时,通常需要配置对话循环中的记忆管理函数。不同版本的 API 会持续变化,使用时应以官方文档为准。
7.3 自定义 Memory 模块实现
如果现有框架不满足需求,可以实现一个最小记忆模块。核心接口包括:
typescript
interface MemoryStore {
save(item: MemoryItem): Promise<void>;
search(query: string, limit?: number): Promise<MemoryItem[]>;
delete(id: string): Promise<void>;
summarize(history: MemoryItem[]): Promise<string>;
}一个基于向量存储的简单实现可以组合嵌入模型和向量数据库。以下示例只保存最近 N 条记忆,并支持关键词过滤:
typescript
class SimpleMemory {
private items: MemoryItem[] = [];
private limit: number;
constructor(limit: number) {
this.limit = limit;
}
async save(item: MemoryItem) {
this.items.push(item);
if (this.items.length > this.limit) {
this.items.shift(); // 淘汰最旧记忆
}
}
async search(query: string, limit = 5) {
// 实际项目中可替换为向量检索
return this.items
.filter(item => item.text.includes(query))
.slice(0, limit);
}
}该实现不具备语义检索和持久化,但展示了记忆模块的基本控制流:写入时限制容量,检索时按简单匹配返回。若要支持语义检索,可以将 search 替换为向量相似度计算,并在 save 时生成并保存向量。更完整的实现还需要考虑并发、事务和存储后端。
8. 记忆系统的测试与评估
8.1 评测指标
记忆系统的评测需要同时关注“记忆能力”和“下游任务表现”。常用指标包括:
- 信息召回率:与当前问题相关的历史信息是否被检索到;
- 检索精度:返回的记忆中有多少是真正有用的;
- 存储利用率:在有限存储下覆盖了多少重要信息;
- 任务成功率:在需依赖长期记忆的任务中,Agent 是否正确使用记忆。
对于知识积累模块,还可以评估摘要的忠实度、信息抽取的准确率和知识图谱的完备性。
8.2 公开基准与调试
已有公开工作提出了适用于长期记忆场景的基准测试集,例如 LongMemEval 和 LOCOMO。这些基准包含模拟多轮对话和问题集,能够在统一协议下对比不同记忆实现。
在实际开发中,可以从一个可复现的固定评测集开始。例如构造 100 个模拟用户交互,记录每一轮的问题和正确答案,然后运行 Agent,检查它能否在后续相关轮次中正确引用先前的信息。评测应覆盖:
- 跨会话记忆;
- 长时间对话;
- 信息更新和冲突;
- 记忆检索的鲁棒性。
调试时,可以增加记忆操作日志,记录每次保存、检索、更新和遗忘的触发条件与内容,以便定位问题。
9. 边界与权衡
9.1 一致性与可扩展性
记忆系统需要处理数据一致性和系统扩展性之间的冲突。例如,检查点需要原子写入以保证状态不丢失,但在分布式场景下,事务开销会限制吞吐。Store 需要支持快速读写,但复杂索引会降低写入性能。
设计时可以考虑:
- 将实时状态写入与异步分析分离;
- 使用事件溯源,让状态可以从事件重建;
- 定期压缩旧事件以减少存储成本。
一致性要求取决于应用场景。对于客服 Agent,状态丢失可能导致重复回复;对于个人助手,丢失一条偏好记录可能只是影响推荐质量。应根据需求选择不同的一致性等级。
9.2 隐私、成本与延迟
记忆与隐私密切相关。Agent 长时间存储用户数据,可能包含敏感信息。需要在设计中考虑:
- 用户是否有权查看和删除记忆;
- 记忆是否加密存储;
- 是否允许基于记忆的内容分发。
成本方面,长期记忆会持续增加存储用量和检索计算量。可以使用分级存储:热数据放内存或快速数据库,冷数据放廉价对象存储。
延迟方面,检索和重排会增加每次请求的时间。可以通过缓存常用查询结果、限制候选集大小和异步预取来缓解。
10. 未来方向与生态
10.1 记忆标准化与 MCP
当不同 Agent 使用不同的记忆接口时,迁移和互操作成本很高。标准化接口能够允许 Agent 通过统一协议访问外部记忆服务。模型上下文协议(MCP)是这一方向的一种探索,它定义了工具和资源的标准化访问方式,未来可能让 Agent 调用“记忆资源”就像调用文件或数据库一样。
标准化需要解决语义问题:不同系统对“用户”“对话”“事实”的表示不同,需要共享本体或模式。
10.2 Agent OS 与个人数据存储
另一种趋势是把长期记忆从单个 Agent 中剥离出来,形成独立的“个人数据存储”。Agent 不再直接管理数据库,而是通过 API 读写一个统一存储层。这样可以实现同一用户在不同 Agent 之间共享记忆,同时保持用户对数据的控制权。
这个方向与“Agent OS”的设想一致:Agent 运行在操作系统之上,记忆是操作系统的文件系统。Agent 可以创建、读取、更新、删除记忆文件,而文件系统负责索引、备份和安全。
如需进一步了解 LongMemEval 与 LOCOMO,可查阅其论文与官方仓库;MemGPT/Letta 的用法请参考其官方文档。
11. 参考链接
- LangGraph Persistence 官方文档:https://docs.langchain.com/oss/python/langgraph/persistence
- LangGraph 文档中关于内存后端限制与 checkpoint 增长的说明:https://docs.langchain.com/oss/python/langgraph/persistence
- MemGPT/Letta 官方文档:https://docs.letta.com/
