上一篇讲了窗口里留什么、卸载什么、何时压缩、如何回取 「AI学习笔记」Agent Memory(一)会话内记忆。这一篇讲一下什么值得长期留下,以及记忆如何形成、更新、检索和遗忘
本文只讨论单个 Agent 如何为同一用户保存跨会话记忆。多人、多 Agent 共用记忆时新增的权限和治理问题,留到第三篇。
会话结束后,Agent 为什么又"不认识你"了
假设你上周告诉旅行 Agent 三件事:你已经从北京搬到上海;出差时优先坐高铁;Agent 已经替你订好 3 月 3 日回上海的车票。今天你打开新会话,只问一句:"我那趟高铁几点?到上海虹桥站后离我现在住的地方远吗?"
要回答这个问题,系统必须连续跨过三道门槛:上周的消息和购票结果有没有被持久化;其中哪些内容已经形成可复用的事实或事件;这次查询能不能取回正确、仍然有效且证据足够的那几条。只保存聊天记录解决了第一道门槛,却没有自动解决后两道。
所以,跨会话记忆不是"给模型接一块硬盘",而是:
把过去交互中值得复用的信息形成可追溯的长期状态,并在未来任务中按条件恢复、更新、纠错或退出。
真正困难的不是"存",而是一条连续的数据链:记什么、凭什么信、如何随事实变化、什么时候找回来、何时忘掉。
一、先用一个案例分清四类记忆与两个边界
同一次订票,为什么会产生四类不同记忆
| 类型 | 回答的问题 | 旅行案例 | 生命周期与用途 |
|---|---|---|---|
| 工作记忆 | 当前正在做什么 | 正在比较 G1373 与 G1375,下一步核对到站后的地址 | 服务当前任务;任务结束后通常退出窗口,必要状态再转成长期记忆 |
| 情景记忆 | 过去发生了什么 | 2026-03-03 购票接口返回 ticket_issued,订单号 CN123 |
保留事件的时间、来源、动作与结果,用于追问、审计和复盘 |
| 语义记忆 | 以后值得知道什么 | 用户当前住上海;出差时通常偏好高铁 | 表达相对稳定的事实、偏好或知识,可由多次经历提炼,也可来自可靠画像 |
| 程序记忆 | 下次应该怎样做 | 订票后必须核验工具回执和订单号,不能只凭 Agent 的自然语言确认 | 保存可复用的做事方式、SOP 和工具约定,指导未来行动 |
四类记忆最容易混淆的地方,是同一份原始材料可以沿时间发生类型转换。购票接口的一次成功回执首先是情景记忆;多次出差都选择高铁后,系统可以将其巩固为"出差时偏好高铁"的语义记忆;复盘发现 Agent 曾在没有回执时误称"已出票",又可能沉淀出"必须以工具回执确认"的程序记忆。当前比较车次的候选列表则只是工作记忆,不应因为内容很多或当时很重要,就自动永久保存。
情景记忆和语义记忆可以用一句话区分:前者保留"某次发生了什么",后者提炼"以后通常值得知道什么"。 语义提炼会丢掉细节,因此最好能回到情景与原始证据重新计算;程序记忆也不应从一次偶然成功中草率总结,否则一次运气会被固化成长期规则。
跨会话记忆既不是历史回放,也不只是 RAG
完整聊天记录是原始材料,不是已经整理好的记忆。历史很少时,直接加载必要记录完全合理;历史增长后,全量回放会增加 token、延迟和噪声,还会把已经失效的"住在北京"与当前事实一起带回来。长上下文决定当前窗口能放多少 ,跨会话记忆决定历史中什么值得留下、何时取回,二者是上下游关系,不是替代关系。
RAG 也不是跨会话记忆的同义词。向量、关键词和全文检索都可以被记忆系统复用,但 RAG 主要回答"哪些片段与问题相关";长期记忆还必须负责内容的形成、冲突演化、时间适用性、人工纠错和遗忘。检索只是生命周期的一段。
把聊天记录直接接到向量库,通常会暴露五类问题。它们也正好对应本文后面的工程路径:
| 失败表现 | 根因 | 需要的能力 |
|---|---|---|
| 寒暄、失败尝试和大段工具输出淹没有效信息 | 什么都存,没有选择 | 巩固与质量门 |
| "优先高铁"被写成"拒绝飞机" | 抽取把偏好升级成硬约束 | 溯源、证据分级与抽样复核 |
| 北京与上海两个地址同时出现 | 新旧事实没有状态与时间关系 | 更新、失效或双时态 |
| 找到"配置"相关内容,却没找到"上周三那次" | 只看语义相关性,没有硬条件 | 结构化过滤与查询路由 |
| 错误摘要被反复召回,越用越像事实 | 派生结果不能纠错或重算 | 原始层、纠错、遗忘与压缩治理 |
二、一张图看懂记忆的完整生命周期

巩固、更新、索引、检索、遗忘和压缩分别做什么
学术综述常将记忆动态拆成六种操作。它们不是必须独立部署的六个服务,而是检查系统是否完整的六个视角:
| 操作 | 输入与动作 | 产物 | 旅行案例 | 常见失败 |
|---|---|---|---|---|
| 巩固(consolidation) | 从消息、工具回执和业务事件中筛选值得长期保留的内容 | 情景、语义或程序记忆 | 从聊天中保留搬家事实、购票回执与稳定偏好 | 全量保存噪声;把一次选择误当长期偏好 |
| 更新(update) | 新事实到来后,追加、覆盖、标记被取代或调整有效期 | 可表达当前状态与历史变化的记录 | "住北京"被"搬到上海"取代,但历史仍可追溯 | 静默覆盖丢历史;只追加却无法判断当前值 |
| 索引(indexing) | 为记忆建立 owner、时间、状态、关键词、向量或实体访问路径 | 面向不同查询的索引与元数据 | 地址按 owner 和有效时间过滤,订单号进入精确索引 | 只建向量索引;主存纠正后索引仍返回旧值 |
| 检索(retrieval) | 围绕当前任务先过滤适用范围,再组合时间、关键词、语义或实体信号 | 有限、带证据的候选记忆 | 找到 CN123 的车次,同时排除旧北京地址 |
相关但不适用;证据不足仍强行注入 |
| 遗忘(forgetting) | 让过期、低价值、被取代或依法应删除的内容退出使用 | 降权、失效、TTL 或删除传播结果 | 行程结束后临时接送计划失效 | 把"物理删一行"误当完整删除;稳定偏好被机械过期 |
| 压缩(compression) | 合并重复事件或把多次经历提炼为更紧凑的表示 | 可回溯、可重算的摘要或稳定事实 | 多次高铁选择提炼成"出差时偏好高铁" | 摘要失真;压缩后失去来源,无法纠错 |
其中有两组概念尤其容易混淆。巩固决定哪些经验有资格成为长期记忆,压缩决定同样的信息如何更紧凑地表示 ;索引决定通过哪些路径找到数据,检索则在具体问题到来时真正选择和使用这些路径。一个系统可以把多项操作放进同一个异步任务,但不能因此省略它们承担的数据责任。
六种操作如何落到四条工程路径
工程实现时,可以把六种操作重新组织为四条更容易建设和观测的路径:
- 写入路径:原始对话或工具事件经过巩固、提取与质量门,形成派生记忆,并建立索引;
- 演化路径:新旧事实比较后追加、覆盖、显式失效或合并压缩;
- 读取路径:先过滤 owner、状态与时间,再按查询选择检索信号,最后在预算内注入;
- 维护路径:处理纠错、过期、遗忘、删除传播与索引重建。
这四条路径依赖一个基础分层:原始层保存消息、工具返回和业务事件,是核对事实的锚点;派生层保存抽取后的偏好、事实、摘要与状态,允许重算、纠错和失效。 例如 ticket_issued 回执属于原始证据,"3 月 3 日车票已出票"属于可供检索的派生事实。派生记忆应能通过 source_ref 回到原始材料。
"原始"并不等于永久保存。原始层与派生层都应服从数据最小化、保留期、删除权和法律保全;真正要避免的是派生结果在没有来源、没有版本、没有记录的情况下被静默改写。
三、写入:从原始事件变成可信记忆
异步提取可以慢,但不能静默丢失
长期记忆通常不需要阻塞每轮对话。会话结束后异步提取,可以降低主链路延迟;当前任务立即需要的新状态,则应先记录结构化事件,再异步生成长期记忆。例如购票接口成功后,主链路先保存订单号与状态,不能等摘要任务跑完才承认订单存在。
一条实用的处理链是:先从单次会话形成带时间、来源和结果的情景记忆,再定期从多次情景中提炼稳定的语义或程序记忆。但这不是教条:业务已有可靠用户画像时,可以直接维护语义事实;高风险动作则应以业务事件为源,不必让 LLM 重新"理解"一次。
异步并不等于尽力而为。提取任务至少需要幂等键、失败重试、死信或告警,以及按原始事件回放的能力。否则一次队列故障会悄悄变成"Agent 永久忘记",而团队只能从用户投诉中发现。
证据级别和最小审计信息
前三者都可能值得记,但不能被当成同等事实。Agent 的自然语言确认不等于外部动作已经成功。 能拿到工具回执时,应优先记录回执、业务 ID 和状态;只能保存推断时,就明确标注 actor、依据和待确认状态。
写入前的质量门可以组合 schema 校验、规则检查、LLM 复核和人工抽样,但"再让另一个模型审一遍"不是正确性证明。至少要持续检查四类错误:owner 是否错配,时间是否错位,偏好是否被升级为硬约束,工具失败是否被写成成功。发现系统性错误后,还要能按 extractor_version 找到受影响记录并从原始层重放。
四、演化与遗忘:让记忆随事实变化,也能退出
"用户从北京搬到上海"看似只是更新一个字段,实际上要求系统先决定自己要回答哪类问题。

只关心当前状态,可以覆盖快照。 新地址直接替换旧地址,读取简单,但变化轨迹会消失。如果另有可靠事件日志,快照覆盖完全合理;问题在于把快照当作唯一副本。
既要当前值又要普通历史,可以追加事实并显式标记状态。 系统同时保存"2025 年 9 月住北京"和"2026 年 3 月搬到上海",再将旧记录标为被取代。单纯 ADD-only 只完成了追加,并没有自动解决"当前该用哪条"。
需要回答任意时点的状态,才考虑双时态。 有效时间表示事实在现实世界何时成立,记录时间表示系统何时得知它。用户 3 月 1 日搬家、3 月 4 日才告诉 Agent,这两个时间并不相同。双时态模型可以同时回答"3 月 2 日实际住哪里"和"系统在 3 月 2 日以为住哪里",能力更强,建模、查询和维护成本也更高。Zep / Graphiti 的时间知识图谱属于这类路线,但不是所有个性化 Agent 都需要它。
更新解决"变化",维护还要持续处理三类问题:
- 旧:临时行程、一次性地址和短期计划可用 TTL、降权或状态失效退出;稳定偏好不应只因很久没提就机械删除。保留策略要按记忆类型、业务风险和法规要求配置,不存在通用的"90 天最佳值"。
- 重复:ADD-only 系统会持续增长。多条高度相似的出行情景可以压缩成更高层语义记忆,但压缩结果仍需保留来源并允许重算,否则系统最终只剩一句无法核对的概括。
- 错:时间衰减不能修复高置信度错误。用户或运营人员必须能查看、修正、争议和删除记忆,并观测更正何时传播到主存、向量/全文索引与缓存。
删除也不是"删一行数据库"。在适用 GDPR 等规则时,删除可能需要覆盖原始记录、派生记忆、索引、缓存和备份策略。具体义务取决于地区、数据角色与用途,应由法务和工程共同确认;技术上至少要有可追踪的删除任务,而不是让旧向量在主记录消失后继续被召回。
五、读取:找得到还要适用、可信、放得下
存储选型应该从查询开始,而不是从"要不要上向量数据库"开始:
| Agent 要回答的问题 | 更适合优先评估的能力 |
|---|---|
| "用户 X 上周三做了什么" | 按 owner 和时间过滤的 SQL / 事件索引 |
| "和这个故障最相似的历史案例" | 向量语义检索 + 关键词检索 |
"ERR_5021 那次怎么解决的" |
精确关键词 / 全文索引 |
| "支付模块当前生效的 SOP" | 文件或数据库 + 明确版本和状态 |
| "这条事实何时失效" | 双时态表或时间图谱 |
同一个数据库可能同时提供结构化过滤、全文和向量能力,是否拆成多套基础设施,应由数据量、延迟、可靠性和运维成本决定。向量数据库不是记忆系统的默认起点,查询形态才是。

一条稳妥的读取链通常分四步。第一步按 owner_id、状态和有效时间做结构化硬过滤 ,先排除别人的数据、旧北京地址和已失效行程。第二步做查询路由 :订单号 CN123 适合关键词,"那趟回上海的车"可用语义与时间信号,"离现在住处多远"还需要当前地址。第三步将不同检索器的候选做排名融合或 rerank ,而不是直接相加不同量纲的裸分数。第四步才是预算注入:只把有限、带来源与状态的内容放进上下文。
这里的顺序很重要。先做语义召回再过滤,既浪费成本,也可能让不应出现的记录参与排序。每次固定跑四路检索同样不是"更稳",多一路会增加延迟和误召回,应先用真实查询证明增益。
读取链还必须允许"正确地不注入"。如果只找到 Agent 上次说"已经订好",却没有票务回执或订单号,系统应告诉当前 Agent 证据不足,需要重新核验,而不是把一句自然语言承诺注入为"车票已出票"。对高风险动作来说,克制比多召回一条更重要。
六、Mem0 案例:一个实现如何重新分配复杂度
到这里再看 Mem0,才能分清哪些是通用问题,哪些只是一个框架的选择。
Mem0 是跨会话记忆的一种工程实现,不是 Agent Memory 的定义,也不是前文审计字段的来源。
从两遍增删改到单遍 ADD-only:复杂度没有消失,只是后移
旧流程需要两次 LLM 调用:先从当前对话抽取候选事实,再把候选与旧记忆放进 prompt,让模型决定 ADD / UPDATE / DELETE。第二次调用同时承担冲突判断和破坏性写入:一旦模型把"搬到上海"处理成对"住在北京"的原地 UPDATE,当前值虽然干净,历史却无法恢复;DELETE 判断错误时问题更明显。
新版将流程缩成一次 LLM 调用,只输出新增事实。同一个搬家场景会保留两条记录,而不是在写入阶段改掉旧记录。这样既减少了一次模型调用,也降低了误更新、误删除的破坏性。
但 ADD-only 没有免费解决冲突,它只是重新分配了复杂度:数据会持续增长,读取侧必须判断哪个值当前适用,维护侧必须负责去重、压缩、过期与删除。若业务需要明确当前状态或可靠时点查询,显式失效或双时态模型仍然更合适。因此,"不要轻易抹掉变化历史"是通用提醒,ADD-only 不是通用答案。
Agent 信息、多信号检索与 benchmark 都要带边界理解
Mem0 新版开始提取 Agent 生成的信息,修复了只遍历用户消息造成的漏记。例如 Agent 曾确认某次预订,后续会话理应能找到这段交互。但应用层仍要区分自然语言确认、Agent 推断、工具返回和已确认动作:记住"Agent 说已预订"比完全忘记更好,却不能自动证明订单存在。
检索侧加入了语义、关键词和实体信号,并进行排名融合,能改善错误码、专有名词与具体人物等纯语义检索不稳定的查询。这与前文的原则一致:先识别查询需要什么信号,再组合互补检索,而不是把所有问题都变成向量相似度。
Mem0 官方材料报告了 LongMemEval 单会话 assistant 召回从 46.4 提升到 98.2,也披露了 LoCoMo、LongMemEval 和 BEAM 上的质量与 token 数据。这些数字只能说明在其披露的版本、模型和测试配置下,改动针对了旧流程的盲区,不能直接外推为生产收益。本地 source 还记录了两个边界:官方不同页面的部分分数口径并不完全一致;BEAM 10M 中的矛盾消解和时间推理仍明显较弱。真正选型时应在自己的数据上复现,并同时报告摄入成本、注入 token、延迟和正确弃答能力。
七、评测与落地:证明记忆真的改善任务
"召回了几条"不是最终目标。记忆系统应在写入、读取和维护三个阶段形成可回放的指标闭环:
| 指标 | 真正要回答的问题 | 一种可操作测法 |
|---|---|---|
| 抽取准确率 | 内容是否忠于原文,归属、时间和类型是否正确 | 对抽样记录回放原始消息,标注偏好是否被升级、owner 是否错配 |
| 有效召回率 | 完成任务真正需要的记忆,有多少进入候选或上下文 | 为真实任务预先标注必需事实,分别测候选阶段与注入阶段 |
| 错误注入率 | 有多少错误、失效或不相关内容实际误导回答或动作 | 收集错误地址、过期计划、跨用户记录进入 prompt 的案例 |
| 正确不注入率 | 证据不足时,系统能否克制而非硬凑 | 构造只有 Agent 承诺、没有工具回执的订票查询 |
| 过期记忆命中率 | 被召回内容中有多少已失效或被取代 | 搬家后查询当前地址,观测旧北京记录是否仍进入候选和上下文 |
| 纠错生效时延 | 用户修正后,旧值多久停止被使用 | 分别记录主存、全文/向量索引和缓存完成更正的时间 |
指标应按记忆类型、查询形态和风险等级拆分。总体命中率很好,不代表系统没有在支付、订票或身份信息这类高风险查询上稳定犯错;同样,离线召回提升也不等于任务成功率提升。
最后
回到开头的旅行 Agent:购票回执先作为原始事件保存并巩固为情景记忆;多次选择高铁后,偏好被压缩成语义记忆;搬家事实到来时,旧北京地址被明确更新或失效;新会话按 owner、时间和订单号找到适用信息;行程结束后,临时接送计划退出,而可复用偏好与订票核验规则继续留下。到这一步,系统完成的不是一次"向量入库",而是一整条可维护的记忆生命周期。
一套好的跨会话记忆系统,应让过去的信息在未来仍然可用、适用、可核对、可纠错,也能在不再需要时退出。Mem0 的 ADD-only、Graphiti 的双时态、文件式记忆和云厂商的托管策略,只是在这条链路上选择了不同复杂度位置。
参考来源
- Mem0 --- Introducing The Token-Efficient Memory Algorithm --- 单遍 ADD-only、Agent 信息、实体链接与多信号检索
- Anthropic --- Memory tool
- Google Cloud --- Memory Bank overview
- AWS --- AgentCore memory strategies
- Letta --- Memory Blocks
- Letta --- Memory Models: Towards Agents That Learn
- Graphiti 文档 --- 时间知识图谱与事实失效
- arXiv:2501.13956 --- Zep: A Temporal Knowledge Graph Architecture for Agent Memory