MemoryBank - Long Term Memory with Forgetting · essay
02. MemoryBank:长期对话记忆和遗忘曲线
论文:MemoryBank: Enhancing Large Language Models with Long-Term Memory
链接:https://arxiv.org/abs/2305.10250
本地原文:
![[papers/02-MemoryBank-2305.10250.pdf]]
论文定位与阅读路径
核心定位
MemoryBank 关注的是“长期陪伴式对话”:Agent 不只是记住事实,还要随着时间理解用户个性,同时模拟人类遗忘。
原文结构导读
| 原文章节 | 读法 | 你要抓住的工程问题 |
|---|---|---|
| Abstract / Introduction | 看作者为什么把长期记忆放到 LLM 外部 | 对话助手为什么不能只靠上下文窗口 |
| 2 MemoryBank | 精读,论文核心 | 记忆如何存储、检索、更新和遗忘 |
| 2.1 Memory Storage | 看层级记忆对象 | 原始事件、摘要、用户画像怎样分层 |
| 2.2 Memory Retrieval | 看检索特征 | 检索不只看相似度,还要考虑时间和重要性 |
| 2.3 Memory Updating | 看更新与遗忘 | 新记忆怎样合并,旧记忆怎样降权 |
| 3 SiliconFriend | 看系统化封装 | MemoryBank 怎样接到真实聊天产品 |
| 4 Experiments | 看定性和定量证据 | 记忆是否改善长期一致性和用户画像 |
| 5-6 Related / Conclusion | 快读 | 和其他长期对话记忆区分边界 |
这篇读法不要从“遗忘曲线很像心理学”停住。真正该学的是:长期陪伴式 Agent 至少要同时维护三层东西:事件级记忆、摘要级记忆、用户画像级记忆。遗忘曲线只是其中的排序/降权策略,不是完整记忆系统。
证据链阅读
| 证据点 | 读什么 | 工程判断 |
|---|---|---|
| 定性案例 | 记忆是否让聊天更连贯、更像认识用户 | 证明长期画像不是静态资料卡 |
| 定量分析 | 有无记忆/遗忘机制时回答质量变化 | 判断遗忘曲线是否真的有用 |
| 更新机制 | 新事件如何影响旧摘要和画像 | 长期陪伴系统必须能修正自己 |
| SiliconFriend 系统 | 论文如何接成产品原型 | 看 API、存储和对话链路如何合并 |
研究背景与问题定义
它要解决什么
如果你做一个长期聊天助手,用户会期待它记得:
- 我叫什么。
- 我喜欢什么。
- 我之前烦恼过什么。
- 我最近的目标是什么。
- 我说过的重要事件。
普通 LLM 没有跨会话记忆。MemoryBank 就是给聊天机器人加一个长期记忆银行。
方法框架与核心机制
核心流程
flowchart TD
A[多轮对话] --> B[保存详细交互]
B --> C[生成事件摘要]
C --> D[更新用户画像]
D --> E[按时间衰减记忆强度]
E --> F[下次对话检索相关记忆]
F --> G[生成更个性化回答]
三个关键点
1. In-Depth Memory Storage
它会保存较详细的多轮对话,包括时间信息。
时间很重要,因为“用户昨天说身体不舒服”和“三年前说身体不舒服”的意义不同。
2. Hierarchical Event Summary
直接保存所有对话会太乱,所以需要摘要。可以理解为:
代码块收起展开
原始聊天记录 -> 小事件摘要 -> 更高层用户画像这和你复习时做笔记一样:不可能把老师每句话都背下来,要提炼成知识点。
3. Forgetting Mechanism
MemoryBank 借鉴艾宾浩斯遗忘曲线:不常用、不重要的记忆会逐渐变弱。
工程上可以理解为给记忆一个分数:
代码块收起展开
memory_score = importance * time_decay * access_boost- importance:这件事本身重不重要。
- time_decay:越久远越衰减。
- access_boost:最近被用过就增强。
概念校准
你的脑子不会平均记住所有事。昨天吃了什么可能很快忘,但一次重要考试、一个长期目标、一个朋友的偏好会记更久。MemoryBank 就是把这种“重要的留下、不重要的淡掉”的机制放进 Agent。
工程映射与实践启发
工程落地方案
Java 后端可以这样做:
| 表/模块 | 作用 |
|---|---|
conversation_message | 原始对话 |
memory_event | 从对话抽取出的事件 |
user_profile | 用户画像 |
memory_score_job | 定时衰减记忆分数 |
memory_retriever | 当前问题相关记忆检索 |
最小字段:
代码块收起展开
memory_event(
id, -- 事件唯一 ID,用于后续引用和去重。
user_id, -- 归属用户,长期记忆必须先按用户隔离。
content, -- 原始或压缩后的记忆内容。
importance, -- 重要性分数,决定遗忘时是否优先保留。
last_accessed_at, -- 最近一次被检索/使用的时间。
created_at, -- 写入时间,用于计算年龄。
decay_score -- 遗忘分数,通常由时间、重要性、访问频率共同决定。
)相关工作与方法对比
它和 MemGPT 的区别
| 维度 | MemGPT | MemoryBank |
|---|---|---|
| 隐喻 | 操作系统内存管理 | 人类长期记忆银行 |
| 重点 | 上下文和外部记忆调度 | 用户个性化和遗忘 |
| 适用 | 长文档、长任务、长对话 | 陪伴助手、用户画像 |
局限、对比与阅读检查
局限与边界
- 遗忘曲线是启发式,不一定适合所有任务。
- 摘要质量依赖 LLM。
- 用户画像可能误判。
- 隐私问题更明显,因为它保存长期个人信息。
阅读重点
- 它如何从对话中生成记忆。
- 它如何做层次化摘要。
- 它如何给记忆做时间衰减。
- 它如何更新用户个性理解。
- 它适合哪类产品,不适合哪类产品。
实践启发
如果做 Personal Knowledge Agent,不要把所有历史都永久等权保存。至少要有:
- 重要性评分。
- 最近访问时间。
- 过期/衰减机制。
- 用户可查看和删除记忆。
原文精读补充
1. Introduction 要抓什么
MemoryBank 的起点不是“企业知识库”,而是长期陪伴式对话。它关心的是:聊天机器人如何随着时间理解一个人,而不是每次都像新朋友。
这和 MemGPT 的问题不同:
| 论文 | 主要问题 |
|---|---|
| MemGPT | 上下文窗口有限,如何管理长上下文 |
| MemoryBank | 长期互动中,如何记住用户经历和个性 |
所以 MemoryBank 更靠近 personal assistant / companion AI。
2. 记忆结构拆开看
MemoryBank 不是只保存原始聊天记录。它强调三类结构:
| 结构 | 作用 |
|---|---|
| Detailed memory | 保留原始或较细粒度事件 |
| Summary memory | 把对话压缩成层次化摘要 |
| Personality understanding | 逐步形成对用户性格/偏好的理解 |
你可以这样理解:
代码块收起展开
原始聊天 = 日记流水账
层次摘要 = 复习提纲
用户画像 = 对这个人的长期理解3. 遗忘曲线为什么重要
很多初学者会想:既然是长期记忆,那全部永久保存最好。
MemoryBank 的思路相反:人类记忆会遗忘,Agent 记忆也需要衰减。否则系统会出现:
- 太多旧记忆干扰当前问题。
- 过时偏好持续影响回答。
- 检索结果越来越噪声。
- 存储和上下文成本持续上升。
遗忘不是删除一切,而是降低旧记忆优先级。
4. 检索时不只看相似度
长期对话记忆如果只看 embedding 相似度,会漏掉时间和重要性。更合理的分数至少包含:
代码块收起展开
score = relevance + importance + recency/retention这和 Generative Agents 的 recency/importance/relevance 很接近。
5. 实验怎么看
原文里会通过长期对话、用户理解、回答质量等方式验证。你读实验时重点问:
- 它是否比没有长期记忆的模型更了解用户。
- 它是否能在多轮后找回早期信息。
- 遗忘机制是否减少无关旧信息干扰。
- 用户画像更新是否会被个别对话带偏。
6. 工程落地提醒
Personal Knowledge Agent 不应该只保存“事实”。它还应该保存:
| 类型 | 示例 |
|---|---|
| 学习事件 | 今天学了 Agent Memory 论文 |
| 偏好 | 喜欢逐篇拆解、不要浅尝辄止 |
| 能力状态 | Java 后端基础,正在转 Agent |
| 薄弱点 | 需要代码字段/函数注释 |
但这些记忆必须带时间和置信度。比如“最近不喜欢咖啡”不等于“永远不喜欢咖啡”。
深度精读:MemoryBank 到底比“聊天记录存库”强在哪
1. 它的产品假设是长期陪伴
MemoryBank 的目标场景不是企业问答,也不是代码助手,而是长期聊天伙伴。这个场景有几个特殊要求:
- 用户会反复出现。
- 用户会提到生活经历。
- 用户偏好和性格会逐渐显现。
- 回答是否“像认识我”很重要。
- 记忆错误会带来明显冒犯感。
所以 MemoryBank 的记忆不只是事实库,还包含对用户经历、关系、偏好、情绪和画像的建模。
2. 为什么要分详细记忆和摘要记忆
如果只保存详细对话:
代码块收起展开
优点:信息完整。
缺点:检索噪声大、成本高、难形成稳定理解。如果只保存摘要:
代码块收起展开
优点:短、清晰。
缺点:细节丢失,摘要错误难恢复。MemoryBank 的思路是两者都保留:
| 层 | 用途 |
|---|---|
| 详细记忆 | 需要证据和细节时查 |
| 事件摘要 | 快速回忆对话主题 |
| 层次摘要 | 长周期理解用户经历 |
| 用户画像 | 对偏好/性格的高层估计 |
这其实是一个小型数据仓库思想:明细层、汇总层、画像层。
3. 遗忘曲线不是玄学,是排序机制
艾宾浩斯遗忘曲线在这里不要理解成“像人脑一样真实遗忘”。工程上它主要是一个排序/衰减函数:
代码块收起展开
越久没被访问的记忆,默认权重越低;
越重要、越常被回忆的记忆,保留权重越高。你可以把记忆得分理解成:
代码块收起展开
memory_score = semantic_similarity
+ importance_weight
+ retention_weight
+ access_boost其中 retention_weight 随时间下降,access_boost 随访问增强。
4. 用户画像最容易做坏
论文里提到动态理解用户个性,这个方向很诱人,但工程上很危险。
坏例子:
代码块收起展开
用户今天说“我烦死 Java 了”
系统记成“用户讨厌 Java”更合理:
代码块收起展开
用户在某次学习挫折中表达对 Java 的烦躁;
这可能是短期情绪,不应上升为稳定偏好。画像类记忆要比事实类记忆更谨慎:
| 记忆 | 置信度策略 |
|---|---|
| 明确事实 | 用户直接说,可以较高 |
| 偏好 | 多次出现再提高 |
| 性格判断 | 默认低置信度 |
| 情绪状态 | 强时间衰减 |
5. 写入流程可以这样实现
flowchart TD
A[一轮对话结束] --> B[抽取事件]
B --> C[生成短摘要]
C --> D[更新层次摘要]
B --> E[抽取用户事实/偏好]
E --> F{是否稳定}
F -->|是| G[写入长期画像]
F -->|否| H[写入情景记忆]
G --> I[更新访问/遗忘指标]
H --> I
这个流程比“对话 -> embedding -> 存库”靠谱很多。
6. 对大二阶段最重要的理解
MemoryBank 的“遗忘”不等于不重视历史,而是承认长期系统必须治理信息优先级。
就像你复习:
- 高频考点反复看。
- 冷门知识知道在哪查。
- 过时理解要改。
- 错题比普通题重要。
Agent 也是一样。永久保存全部内容不等于智能。
7. 工程表结构示例
代码块收起展开
memory_item(
id, -- 记忆条目 ID。
user_id, -- 用户隔离键。
memory_type, -- profile / event / preference / fact 等类型。
content, -- 可直接放入上下文的记忆正文。
source_message_ids, -- 来源消息 ID 列表,用于审计和回溯。
importance, -- 重要性评分。
confidence, -- 抽取可信度,低可信记忆应谨慎注入。
last_accessed_at, -- 最近使用时间。
access_count, -- 被命中的次数。
retention_score, -- 综合保留分数,遗忘策略读取它。
created_at, -- 创建时间。
updated_at -- 最近更新时间。
);偏好和画像不要只存一句话,至少要有 evidence:
代码块收起展开
memory_evidence(
memory_id,
source_type,
source_id,
observed_at,
quote_summary
);8. 读实验时该看什么
陪伴式 Agent 的评估很难。你要注意:
- 是否只评估“能不能回忆事实”,还是也评估对话自然度。
- 用户画像是否由人类判断,还是 LLM judge 判断。
- 遗忘机制是否真的提高质量,还是只是减少噪声。
- 有没有测试偏好变化后的更新。
这类论文实验往往不如数学 benchmark 硬,所以要把它当系统设计启发,不要当最终证明。
论文精读主线:问题-方法-验证-局限-启发
1. 核心结论
MemoryBank 把长期对话记忆做成事件存储、层级摘要、用户画像和遗忘机制的组合,让长期陪伴型 Agent 能记住用户并降低过期信息的影响。
本篇的阅读重心是:长期陪伴记忆如何从事件形成画像,同时让过期信息衰减。读完后要能说清它改变的是 runtime、存储、检索、更新还是评测层;否则只是记住了论文名。
2. 问题背景
聊天机器人会话结束就失忆;但把所有历史都存起来也会引入噪声、重复和过期事实。长期陪伴系统需要从具体事件中形成稳定画像,同时避免一次性情绪或临时计划永久影响回答。
把问题具体化为失败样例:用户临时说“最近不想学 Java”,系统却永久当成偏好;或旧目标已经结束,仍在回答里反复引用。用这个样例反推论文动机,比泛泛说“上下文不够”或“记忆不准”更有判断力。
3. 核心方法
系统先从对话中抽取值得保存的事件,再把多个事件汇总为层级摘要或用户画像,最后用遗忘曲线控制旧记忆权重。检索时结合语义相关、重要性和记忆强度,而不是只看 embedding 相似度。
flowchart TD
M[对话消息] --> E[事件抽取]
E --> S[详细事件记忆]
S --> P[层级摘要/用户画像]
S --> F[遗忘强度计算]
P --> R[检索候选]
F --> R
R --> C[进入上下文]
方法部分按数据流读:对话事件先被过滤和打分,再进入 event memory;稳定事件聚合成 profile,检索时按相关性、重要性和遗忘强度排序。每一步都要能标出输入、输出、控制点和失败后该记录的日志。
4. 技术细节
关键是把事件和画像分开。事件回答“什么时候发生了什么”,画像回答“用户长期是什么样”。事件可以衰减,画像要有证据和置信度。遗忘不是简单删除,而是在排序时降低旧记忆影响。
代码块收起展开
final class MemoryBankService {
private final EventExtractor eventExtractor; // 从消息中抽取值得长期保存的事件,过滤寒暄和临时噪声
private final ProfileUpdater profileUpdater; // 把多条事件合并为画像字段,并保存证据 ID
private final ForgettingScorer forgettingScorer; // 按时间、访问次数、重要性计算记忆保留强度
private final MemoryRetriever retriever; // 综合语义相似度、重要性和遗忘强度排序
MemoryResult handle(MemoryInput input) {
// 1. 从消息中抽取值得长期保存的事件,过滤寒暄和临时噪声
// 2. 把多条事件合并为画像字段,并保存证据 ID
// 3. 按时间、访问次数、重要性计算记忆保留强度
// 4. 综合语义相似度、重要性和遗忘强度排序
// 返回结果时必须带 evidence、confidence、traceId,方便以后追查记忆为什么生效。
return MemoryResult.withTrace(input.traceId());
}
}字段检查重点是 eventType、importance、decayRate、profileKey、evidenceEventIds 决定记忆是临时事实还是长期画像。这些字段不是装饰,它们决定后续能否检索、审计、回滚、限权和做离线评测。
5. 实验验证
实验要看跨会话连续性是否提升,例如是否记住早期用户事实、是否减少重复询问、是否根据偏好调整回答。遗忘机制的消融很关键:去掉遗忘后如果过期信息干扰增多,说明它不是装饰模块。
实验阅读重点:看跨会话一致性、过期事实干扰率、画像证据链;遗忘消融要证明旧噪声确实被压低。如果论文没有直接给出这层证据,复现时就要自己补机制级指标。
6. 局限与启发
画像生成容易过度推断,隐私风险也更高。启发是个人学习 Agent 要区分长期稳定偏好、当前阶段目标、一次性任务和临时情绪,不要把所有用户话语都升级为画像。
迁移到你的项目时,结论是:你的 Agent 不能把所有对话都升级成长期偏好;学习目标、项目状态、情绪和身份事实要分不同衰减策略。先把边界做对,再追求更复杂的模型或更大的记忆规模。
7. 关键术语表
| 术语 | 在论文里的意思 | 工程落地时要看什么 |
|---|---|---|
| Event memory | 具体发生过的对话事件 | 带时间戳、来源和重要性的记录 |
| Hierarchical summary | 从事件抽象出的高层总结 | 用户画像、阶段目标、项目状态 |
| Forgetting curve | 旧记忆影响随时间衰减 | 排序权重衰减,不一定物理删除 |
| Memory strength | 记忆当前有效强度 | 时间、访问次数、重要性共同决定 |
8. 复现难点
难点是事件抽取和画像更新。抽得太多会污染,抽得太少会失忆;单次事件不能直接生成强画像。衰减参数也要按类型区分:身份信息慢衰减,短期任务快衰减,学习偏好中等衰减。
复现入口应从失败集开始:准备同一用户偏好随时间改变的对话集,验证系统能保留稳定偏好、淡化临时情绪、解释画像来源。只有先证明旧方案会坏,才知道新机制是否真的解决了问题。
9. 代码框架建议
建议三张表:memory_event(id,user_id,text,type,importance,created_at,last_accessed_at)、user_profile(key,value,confidence,updated_at)、profile_evidence(profile_key,event_id)。检索时返回证据事件,不只返回画像结论。
代码验收门槛:写入画像前必须有多条证据或高置信事件;单句表达默认进入 event,不直接覆盖 profile。这条门槛应写进测试或 trace 字段里,避免实现只停留在 demo。
10. 相关论文对比
MemoryBank 和 MemGPT 都解决长期上下文,但前者关注长期陪伴和用户画像,后者关注上下文资源调度。Mem0 后续把写入操作显式化为 add/update/delete/noop,Zep 则用时间图谱处理事实变化。
横向比较时抓这个角度:它和 MemGPT 都处理长期信息,但 MemoryBank 更关心用户模型,MemGPT 更关心上下文调度。比较对象不是谁“更先进”,而是谁负责哪一层失败。
11. 批判性思考
MemoryBank 容易把“记住用户”做成“过度画像用户”。长期记忆的好坏不只看召回率,还要看哪些信息不该记、哪些记忆需要确认、用户能否查看和删除。
批判边界:记忆越像画像越需要用户可见和可删;否则系统会把推断当事实,隐私和偏见风险都更高。这不是否定论文,而是把论文结论放回真实系统的成本、权限和恢复约束里。