外观
记忆系统
LLM 本身没有记忆。每次调用都是一张白纸:你把对话历史塞进 prompt,它"看起来"就记得;你不塞,它就什么都不记得。所谓 Agent 的记忆,从来不是模型的能力,而是你在模型外面搭的一套系统——决定记住什么、存在哪、什么时候取、什么时候忘。
这套系统是区分"聊天机器人"和"Agent"的分水岭之一。本页讲清楚三件事:记忆的分类学(记住什么)、主流实现方案(怎么存怎么取)、以及被严重低估的写入策略(什么时候写、怎么更新和遗忘)。上下文窗口的调度与压缩属于 上下文工程 的范畴,本页只在必要处交叉引用。
一、为什么 Agent 需要记忆
无状态的 LLM vs 有状态的任务
一次 LLM 推理调用是纯函数:output = f(context)。模型权重在训练后冻结,推理过程不会往权重里写任何东西。你昨天和 ChatGPT 聊了三个小时,今天它"记得"你,靠的不是模型变了,而是产品在后台把你的偏好抽取出来、存进数据库、下次对话时拼进 system prompt。
但 Agent 面对的任务天然是有状态的:
- 多轮协作:客户支持 Agent 处理一个横跨三天的工单,必须记得昨天已经排查过 DNS。
- 长程任务:编程 Agent 改一个大型仓库,第 50 步的决定依赖于第 3 步读过的文件结构——而原始上下文早就被截断了。
- 个性化:助理类 Agent 需要积累用户画像(偏好、习惯、历史决策),否则每轮对话都从"您好,请问有什么可以帮您"重新开始。
- 经验复用:Agent 上次踩过的坑("这个 API 的分页参数是 cursor 不是 offset")不该再踩一次。
长上下文不等于记忆
"现在上下文窗口都 100 万 token 了,还要记忆系统干嘛?"这是常见误解。第一,长上下文贵——每次都重放全部历史,成本和延迟随会话长度线性甚至超线性增长(详见 成本优化)。第二,长上下文效果会衰减,"lost in the middle"现象下,埋在海量历史中间的信息召回质量明显下降。第三,跨会话的场景根本无解:窗口再大,新会话也是空的。上下文窗口是工作台,记忆系统是档案柜——工作台再大也替代不了档案柜。
记忆的三个功能角色
在动手设计前,先想清楚记忆在你的 Agent 里扮演哪个角色:
- 连续性(continuity):让长任务不断片。这是刚需,几乎所有 Agent 都需要。
- 个性化(personalization):让 Agent 越来越懂特定用户。助理、客服、陪伴类产品需要。
- 学习(learning):让 Agent 从经验中改进行为。这是最难也最少被做好的——多数宣称"会学习"的 Agent 只是把失败日志存进了向量库,并没有真的改变策略。
三个角色对记忆系统的要求完全不同:连续性要的是保真和可回溯,个性化要的是聚合与泛化,学习要的是能影响未来决策的闭环。混为一谈是记忆设计翻车的头号原因。
二、记忆分类学:借认知科学的框架,但别照抄
CoALA 的四类记忆
认知科学把人类记忆分为工作记忆、情景记忆、语义记忆、程序性记忆。CoALA 论文(Cognitive Architectures for Language Agents, Sumers et al., arXiv 2309.02427)系统地把这套分类迁移到了语言 Agent 上,目前这是 Agent 文献中引用最广泛的记忆分类框架:
| CoALA 分类 | 认知科学对应 | 在 Agent 里的形态 | 典型实现 |
|---|---|---|---|
| Working memory(工作记忆) | 短时记忆 | 当前 context window 里的全部内容 | 对话历史、scratchpad、当前计划 |
| Episodic memory(情景记忆) | 对"经历过的事"的记忆 | 过去任务的轨迹、对话片段、"上次发生了什么" | 会话日志 + 向量检索 |
| Semantic memory(语义记忆) | 对世界的事实性知识 | 用户画像、领域知识、实体关系 | 结构化字段、知识图谱、向量库 |
| Procedural memory(程序性记忆) | "怎么做"的技能 | 系统提示词、工具用法、学到的操作流程 | prompt、代码、少样本示例 |
这个分类的工程价值在于:四类记忆的读写时机、存储格式、检索方式完全不同,不该用一套机制处理。用户画像(语义)适合存成结构化字段,按 key 精确读取;任务轨迹(情景)适合存原文加摘要,按相似度检索;操作经验(程序性)最有效的形式往往是直接改 prompt 或沉淀为 few-shot 示例,而不是存进向量库等召回。
短期记忆 vs 长期记忆:另一个更实用的切分
工程实践中更常用的切分是按生命周期:
- 短期记忆(short-term / in-context):活在当前 context window 里,随会话结束而消亡。管理它的本质是上下文调度,详见 上下文工程。
- 长期记忆(long-term / cross-session):持久化在外部存储(数据库、文件、向量库),跨会话存活,需要显式的写入和检索机制。
两条切分维度组合起来,你就得到了一个设计矩阵:先问"这条信息属于哪类记忆"(情景/语义/程序性),再问"它要活多久"(本会话/跨会话),答案直接决定存哪、怎么取。
判断要不要做长期记忆的朴素标准
如果你的 Agent 90% 的会话之间没有信息依赖(比如单次问答、单文件改写),长期记忆是过度设计——先把短期记忆的压缩做好。长期记忆值得做的信号是:用户在会话二里说了"上次那个",或者任务跨越的时长超过了上下文能容纳的极限。
三、短期记忆管理:决定"记住什么"
短期记忆管理的完整话题(token 预算、压缩算法、工具结果截断)在 上下文工程 一页。本页只回答一个问题:当上下文装不下时,哪些信息该留下来?
三种主流取舍策略
原始对话: [t1][t2][t3]...[t47][t48][t49][t50] ← 超出窗口
策略 A 滑动窗口: [t48][t49][t50]
保留最近的,丢弃最旧的。简单、零成本,但会"失忆"早期关键约束。
策略 B 摘要压缩: [摘要(t1..t47) ][t48][t49][t50]
旧历史压成一段摘要,保留近期原文。信息有损,摘要质量决定上限。
策略 C 显著性保留: [t3*][t17*][摘要(其余)][t48][t49][t50]
先挑出高价值条目(用户约束、做出的决定、未解决的问题)单独保留,
其余压缩。效果最好,实现也最复杂。实践中绝大多数生产系统是 B 的变体:Claude Code 的 compaction、各类框架的 SummarizationMiddleware 都是这个思路——旧消息交给一个 LLM 调用压成摘要,近期消息保留原文。
摘要压缩的三个工程要点
- 摘要要分层,不要滚雪球。每压缩一次就把旧摘要喂进新摘要,误差会复利式累积,十几轮后摘要里会编出从未发生过的"事实"。更好的做法是锚定原始事实源:重要决定、用户硬约束单独抽成结构化条目(key-value 或一句话事实清单),摘要只管叙事连贯。
- 触发时机用阈值而不是轮数。按 token 占用率触发(如达到窗口的 70-80%),而不是固定"每 10 轮压缩一次"——十轮闲聊和十轮密集代码阅读的 token 量差一个数量级。
- 压缩点选在任务边界。在子任务刚完成、结论已落盘时压缩,比在一个推理链条中间压缩安全得多。Anthropic 在 context engineering 的公开工程博客中把这个思路概括为"先写笔记,再清桌面":agent 把关键发现写进持久化文件(如 Claude Code 写进代码库或笔记文件),然后才放心地压缩上下文——因为信息已经从"记忆"降级为"可重新检索的资料"。
显著性保留:从 Generative Agents 学来的评分
显著性(salience)保留的经典出处是 Generative Agents 论文(Park et al., arXiv 2304.03442):每条记忆检索时按 recency(新近度)、importance(重要性)、relevance(相关性) 三个维度加权打分。其中 importance 是让 LLM 直接评的:"给'在公园摔了一跤'的重要性打 1-10 分"。
这套评分在模拟小镇里效果惊艳,但直接搬到生产系统要注意两点:LLM 打分每条记忆一次调用,量大时成本可观;且分数分布很不稳定,建议只用来分档(高/中/低)而不是精确排序。一个更便宜的替代:用规则定重要性——用户的显式指令、系统的错误记录、任务的状态变更永远重要,闲聊和重复确认永远不重要。
四、长期记忆实现:四种形态
跨会话的长期记忆没有银弹,四种主流形态各有明确的适用面。
形态一:向量检索记忆
最普及的方案:每条记忆是一段自然语言文本("用户偏好深色主题""3 月 12 日决定用 Postgres 而非 MySQL"),embedding 后存向量库,用时按语义相似度 top-k 召回。
python
# 最小可用的向量记忆读写骨架(伪代码,SDK 以你选用的为准)
def write_memory(text: str, user_id: str):
"""写入一条情景/语义记忆,附带元数据便于过滤"""
embedding = embed(text)
vector_db.upsert(
id=new_id(),
vector=embedding,
metadata={"user_id": user_id, "created_at": now(), "type": "fact"},
)
def recall(query: str, user_id: str, k: int = 5) -> list[str]:
"""检索时必须按 user_id 过滤——多租户记忆串户是安全事故"""
results = vector_db.query(
vector=embed(query),
filter={"user_id": user_id},
top_k=k,
)
return [r.text for r in results]优点是写入成本低、对非结构化内容友好;缺点同样出名:相似度检索不理解时间与矛盾。库里同时躺着"用户住在北京"(2024 年写入)和"用户搬到了上海"(2026 年写入)时,两条都可能被召回,模型只能猜哪条新。Mem0(arXiv 2504.19413)这类记忆框架的核心增量就在写入侧——新事实进来时先做冲突检测,对旧条目执行 ADD / UPDATE / DELETE / NOOP 四选一,而不是无脑追加。
形态二:结构化画像
语义记忆中高度稳定的维度(姓名、角色、偏好、技术栈),直接存成结构化字段,比向量检索可靠一个量级:
json
{
"user_id": "u_123",
"profile": {
"role": "后端工程师",
"primary_language": "Go",
"prefers_concise_answers": true
},
"updated_at": "2026-08-01"
}读取是精确的 key lookup,没有召回噪声;更新是显式的字段写入,冲突解决就是"新值覆盖旧值,记好时间戳"。代价是需要预先设计 schema,覆盖不了 schema 之外的信息。ChatGPT 的 Saved Memories、多数客服 Agent 的用户卡片本质都是这个形态。
形态三:文件笔记(Agent 自己维护的笔记本)
2025 年以来编码 Agent 带火的一种朴素形态:记忆就是一个(或一组)纯文本/Markdown 文件,Agent 用读写文件的工具自己维护。
- Claude Code 的 CLAUDE.md:项目级约定写在仓库根目录的
CLAUDE.md,启动时自动注入上下文;用户可以要求 Agent 把新约定"记下来",Agent 就编辑这个文件。Anthropic 的 context engineering 博客把它称为混合模式——CLAUDE.md这类静态文件直接进上下文,其余资料用 glob/grep 按需拉取。详见 Claude Code 案例。 - Anthropic 的 memory tool:2025 年 9 月随 Claude Sonnet 4.5 发布公开 beta,通过
context-management-2025-06-27beta header 启用。它把记忆抽象成一个文件目录,模型通过 tool call 对记忆文件做 create / write / insert / rename / delete,完全自主管理。 - ChatGPT 的记忆演化:2024 年 2 月上线 Saved Memories(用户可查看、删除的记忆清单);2025 年 4 月增加 reference chat history(引用历史对话内容);2026 年 6 月 OpenAI 发布 Dreaming(后台自动从对话历史中综合提炼记忆,向美国区 Plus/Pro 用户开放),写入从"用户说记住这个"变成"系统在后台自己决定记什么"。
文件笔记形态被低估的优点是可审计:记忆就是文本文件,用户能读、能改、能删、能进 git diff。对隐私合规和调试都极友好。缺点是规模上限低——文件长到几千行后,无论注入还是检索都开始吃力。
形态四:知识图谱
把记忆存成"实体-关系-实体"的三元组图(Zep/Graphiti、Mem0 的 graph 变体、各类 GraphRAG 路线都属于此类)。图结构的独门优势是多跳推理与时间建模:"用户的上司的同事负责哪个项目"这类问题,向量检索基本没戏,图遍历是天然解。带时间戳的边("任职于 X,有效期 2024-2025")还部分缓解了向量库的矛盾问题。
代价是写入成本高得多:每条信息要先做实体抽取、消歧、对齐,pipeline 复杂且错误会沿链路传播。除非你的场景真的有多跳关联查询(CRM、投研、复杂组织知识),否则图谱记忆在大多数情况下是过度设计——先用形态一+二跑起来,召回质量撞到天花板再上图。
四种形态怎么选
| 形态 | 读取方式 | 矛盾/时效处理 | 写入成本 | 适用场景 |
|---|---|---|---|---|
| 向量检索 | 相似度 top-k | 弱,需框架兜底 | 低 | 对话片段、经验日志 |
| 结构化画像 | key 精确查 | 强(覆盖+时间戳) | 中 | 用户偏好、稳定事实 |
| 文件笔记 | 全文注入/grep | 人工/Agent 编辑 | 低 | 项目约定、编码 Agent |
| 知识图谱 | 图遍历查询 | 较强(时态边) | 高 | 多跳关系、复杂实体网络 |
生产系统几乎总是混合架构
观察头部产品:ChatGPT = 结构化清单(Saved Memories)+ 类向量检索(chat history 引用)+ 后台综合(Dreaming);Claude Code = 文件笔记(CLAUDE.md)+ 文件系统即时检索。不存在"选一个"的问题,只有"哪几层、各占多大比重"的问题。
五、写入策略:比读取难十倍的问题
检索(读取)已经有成熟答案,写入没有。读取错了大不了召回一条无关记忆;写入错了,脏数据会永久污染之后的每一次会话。设计写入策略要回答四个问题。
何时写
- 每轮都写:对话式 Agent 常见,信息不丢,但噪声巨大,库里 80% 是废话。
- 会话结束时写:由一个专门的"记忆整理"步骤(或后台任务)通读整段会话,抽取值得长期保留的事实。成本可控,质量依赖抽取 prompt。
- 事件触发写:检测到特定信号才写——用户纠正了 Agent("不对,我用的是 pnpm")、任务完成/失败、用户显式说"记住这个"。信号驱动是信噪比最高的方式。
- 后台异步写:OpenAI Dreaming、Letta 的 sleep-time compute 都是这个方向——记忆的综合提炼不占对话时间,在用户不在线时跑。代价是写入时机的控制感变弱,出错更难归因。
写什么:MemGPT / Letta 的启示
MemGPT(Packer et al., arXiv 2310.08560,2023 年 10 月)是记忆系统设计的分水岭,其核心思想是把操作系统的虚拟内存管理搬到 LLM 上:
┌─────────────────────────────────────────┐
│ LLM context window │
│ ┌───────────────────────────────────┐ │
│ │ Core memory(核心记忆,常驻) │ │ ← 类似 RAM
│ │ · persona 块:Agent 的人设 │ │
│ │ · user 块:用户关键信息 │ │
│ │ 大小受限,Agent 可用工具自己改写 │ │
│ └───────────────────────────────────┘ │
└──────────────┬──────────────────────────┘
│ Agent 主动调用记忆工具换入/换出
┌──────────────┴──────────────────────────┐
│ Recall memory:历史对话全文,可检索 │ ← 类似磁盘
│ Archival memory:任意规模的外部存储 │
└─────────────────────────────────────────┘两个设计决策至今仍是标杆:
- 记忆编辑权交给模型自己。MemGPT 不给模型"自动记忆",而是给它
core_memory_replace、archival_memory_insert这类工具,由模型在推理中决定"这条值得记"。这把"何时写、写什么"从外挂启发式变成了模型能力问题——模型变强,记忆策略自动变强。Letta(MemGPT 团队的产品化框架)把这套机制延续下来,核心记忆按 block 组织(persona、user、自定义),每块有字符上限,Agent 自主做 CRUD。 - 分层 + 换页。核心记忆永远在上下文里(贵但即时),归档记忆按需在会话中检索注入(便宜但延迟)。2025 年 Letta 又引入 sleep-time compute:会话间隙由后台进程做记忆的整理、合并、精炼,把"写日记"和"上班"解耦。
自己实现时不必照搬全套,但"核心块常驻 + 归档块检索 + Agent 持有编辑工具"这个三层骨架,是目前被验证最多的长期记忆架构。
如何更新与遗忘
写入策略里最反直觉的一课是:"不忘"不是特性,是 bug。不做遗忘的记忆系统会在几个月后积累出大量过时、矛盾、低价值条目,召回质量随时间单调下降。常见机制:
- 显式覆盖:新事实与旧事实冲突时更新而非追加(Mem0 的 UPDATE 操作)。要求写入前做一次"是否已有相关记忆"的检索,这是防矛盾的关键一步。
- 时间衰减:检索打分里加入 recency 权重,旧记忆自然沉底(Generative Agents 的打分公式就是这么干的)。
- 访问频率:长期没被召回的记忆降级或归档——"不用的记忆大概率是不重要的记忆"。
- 容量上限 + 淘汰:像 LRU 缓存一样给每类记忆设配额,写满时淘汰评分最低的条目。
一个可直接抄的最小写入流程
1. 会话中检测到候选记忆(用户偏好陈述 / 任务结论 / Agent 被纠正)
2. 用候选文本检索现有记忆库,找 top-3 相似条目
3. LLM 判断候选与现有条目的关系:
- 全新 → INSERT
- 补充细化 → UPDATE(合并进现有条目)
- 矛盾 → UPDATE(新值覆盖,记录时间戳)
- 重复 → NOOP
4. 写入,附元数据:来源会话、时间、类型、置信度
5. 定期(或后台)跑整理任务:合并碎片、降权陈旧条目、清除过期项这个流程的成本是每次候选写入多花 1-2 次 LLM 调用,换来的是记忆库长期不腐化。比起事后清洗一个被污染的向量库,便宜得多。
六、评估记忆系统
记忆系统的质量没法靠感觉判断,需要基准和指标。当前主流的三类评估:
公开基准
- LongMemEval(Wu et al., arXiv 2410.10813,2024):针对聊天助手长期记忆的专项基准,考察五种核心能力——信息抽取(information extraction)、跨会话推理(multi-session reasoning)、时间推理(temporal reasoning)、知识更新(knowledge updates)、 abstention(不知道时拒答)。平均上下文超过 10 万 token,其中 knowledge updates 一项直接对应前文讲的"矛盾覆盖"能力。
- LoCoMo(Maharana et al., ACL 2024):超长多轮对话(平均约 9000 token)上的问答与事件摘要,考察长时间跨度和因果链条上的记忆保持。Mem0 论文报告的 26% 相对提升(LLM-as-a-Judge 口径)就是在这个基准上测的。
- LongMemEval-V2(2026):社区对原基准的延续,把评估目标从"记住对话内容"推向"记忆能否帮助 Agent 像有经验的同事一样工作",更贴近 Agent 场景。
基准分数的解读陷阱
记忆基准的排行榜分数要谨慎对待:LLM-as-a-Judge 口径受评判模型影响大,检索注入的文本格式、top-k 取值都会显著改变分数;且这些基准清一色测对话记忆,对编码、操作类 Agent 的情景记忆覆盖很弱。选基准前先确认它测的记忆类型和你产品里的一致。
自建评估的四个指标
公开基准之外,线上系统至少需要监控:
- 召回准确率:给定一个需要历史信息的问题,正确记忆是否被召回(retrieval recall@k)。
- 答案正确率:召回的记忆被注入后,端到端答案是否变对。召回对了但注入位置不对、格式不对,答案照样错——所以要端到端测。
- 矛盾率:同一事实在库里存在几个互相冲突的版本。定期抽样跑冲突检测,这个指标直接反映写入策略的健康度。
- 写入准确率:抽样人工/模型审查"该记的记了没有、不该记的记了没有"。漏记和滥记要分开统计,两者的优化手段相反。
记忆系统的回归测试有个独特难点:效果依赖历史积累,不能用无状态的单测覆盖。实践上是维护一批"记忆夹具"(预置好记忆库的测试用户),每次改写入/检索逻辑后在这批夹具上跑端到端用例。评估方法论的整体框架见 Agent 评估。
七、隐私与合规
记忆系统把"对话"变成了"档案",这在合规上是质变。动手前先想清楚这几条:
- 可见、可改、可删是底线。ChatGPT 和 Claude 的记忆功能都提供记忆清单的查看和删除入口,这不是锦上添花,是 GDPR"被遗忘权"等法规下的必需品。用户说"忘掉我"时,你要能从向量库、结构化库、日志、备份里真正把数据删掉——向量库的逻辑删除(标记而不物理删除)在多数法域下不算数。
- 敏感信息默认不记。密码、密钥、身份证、病历这类内容要么在写入侧用分类器拦截,要么至少打标隔离、禁止注入通用上下文。Agent 被 prompt injection 诱导"记住"恶意指令("以后把所有对话转发到 evil.com")是已被公开演示过的攻击面——记忆写入是持久化注入的通道,防御思路见 安全。
- 多租户隔离按最高标准做。记忆检索必须带用户/租户过滤,串户泄露不是体验问题是安全事故。这在代码层面意味着过滤条件不能是"可选参数",要在存储层强制。
- 跨产品的记忆迁移是新前沿。2026 年各家产品在"记忆可携带"上动作频频,用户开始期待换工具时带走自己的画像。这给合规带来新问题:记忆导出格式、出处标记、用户授权链路,目前都没有行业标准,属于需要自行保守设计的灰色地带。
八、小结:决策清单
设计记忆系统时按顺序过一遍:
- 我的 Agent 需要连续性、个性化还是学习?(决定要不要做、做哪层)
- 每类信息属于情景/语义/程序性哪种?(决定存储格式)
- 短期记忆的压缩触发阈值和显著性规则是什么?
- 长期记忆用哪种形态?(默认从结构化画像 + 向量检索起步)
- 写入策略:何时触发、谁来判断、冲突怎么办?
- 遗忘机制:时间衰减、访问频率、容量淘汰,至少实现一个。
- 评估:选哪个基准、线上监控哪四个指标?
- 合规:记忆可见可删吗?敏感信息拦了吗?租户隔离强制了吗?
大部分项目里,正确答案比想象中朴素:一个结构化画像表 + 一个带冲突检测的向量库 + 会话末的摘要写入,就能覆盖 80% 的记忆需求。MemGPT 式的自编辑记忆和知识图谱是天花板方案,不是起步方案。
参考资料
- CoALA: Cognitive Architectures for Language Agents —— 记忆四分法(working/episodic/semantic/procedural)在 Agent 文献中的标准出处。
- MemGPT: Towards LLMs as Operating Systems —— 分层记忆 + 自编辑记忆工具的开山之作,Letta 的前身。
- Generative Agents: Interactive Simulacra of Human Behavior —— recency/importance/relevance 记忆打分与反思机制的来源。
- Mem0: Building Production-Ready AI Agents with Scalable Long-Term Memory —— 写入侧冲突处理(ADD/UPDATE/DELETE/NOOP)的代表性工程方案。
- LongMemEval: Benchmarking Chat Assistants on Long-Term Interactive Memory —— 长期记忆五大能力的评估基准。
- Effective context engineering for AI agents —— Anthropic 官方对压缩、笔记、memory tool 的工程阐述。
- Memory and new controls for ChatGPT —— OpenAI 记忆功能的起点与历次更新说明。
- Dreaming: Better memory for a more helpful ChatGPT —— 2026 年 OpenAI 后台自动记忆系统 Dreaming 的发布说明。