对话模型拥有上下文窗口,但上下文并不等于长期记忆。窗口解决“本轮能看到什么”,长期记忆解决“跨越多次交互以后,系统应该保留什么、何时想起,以及何时忘记”。
如果只是把历史对话全部写入向量库,系统很快会遇到噪声累积、事实冲突和召回失控。长期记忆更像一条持续运行的数据治理链路,而不是一次 embedding 调用。
记忆不是原始对话
原始对话是证据,记忆是从证据中提炼出的可复用信息。两者应该分层保存。
一段对话可能包含多个候选记忆:稳定偏好、明确事实、阶段性计划,以及只在当前任务有效的临时状态。提取阶段需要回答三个问题:
- 这条信息以后是否还可能有用?
- 它描述的是事实、偏好、经历还是任务状态?
- 它的有效范围和可信度是什么?
一个简化的记忆对象可以包含:
{
"subject": "user",
"type": "preference",
"content": "更偏好简洁的中文技术说明",
"confidence": 0.88,
"valid_from": "2026-07-01",
"source": "conversation"
}
结构化不是为了追求字段数量,而是让后续的过滤、冲突处理和审计有落点。
提取:先判断,再压缩
提取链路可以分成候选识别、规范化和去重三个阶段。
候选识别
模型从本轮交互中判断是否出现值得长期保留的信息。此时应倾向保守:没有明确证据就不写入,避免把模型推断当成用户事实。
规范化
同一个含义可能有多种表达。规范化需要统一主体、时间、类别和简洁表述,同时保留原始证据的引用,以便将来解释记忆从何而来。
去重与合并
新候选不能直接追加。系统需要先检索相似记忆,再决定创建、增强、替换或忽略。这个过程本质上是一次小型的实体解析与版本管理。
召回:相关并不等于有用
向量相似度只能回答“语义上像不像”,不能独立回答“当前该不该使用”。可靠的召回通常需要多路信号:
| 信号 | 解决的问题 |
|---|---|
| 语义相似度 | 与当前请求是否相关 |
| 时间新鲜度 | 信息是否仍可能有效 |
| 记忆类型 | 当前任务需要事实还是偏好 |
| 可信度 | 信息来源是否足够可靠 |
| 使用反馈 | 过去被召回后是否真正有帮助 |
一种常见做法是先宽召回,再重排。第一阶段追求不漏掉候选,第二阶段结合任务类型、时间与可信度缩小结果。最终注入模型的记忆应当很少,并带有明确边界。
召回还需要负向约束。例如,用户要求“不要使用过往偏好”时,系统必须能够在生成前阻断相关记忆,而不是依赖模型看到后自行忽略。
冲突:记忆需要版本语义
长期运行的系统一定会遇到冲突:用户更换了城市、技术栈偏好发生变化,或者早期提取本身就是错误的。
简单覆盖会丢失历史,永不覆盖又会让召回结果互相矛盾。更可控的方案是保留版本关系:
- 新事实可以使旧事实失效,而不是物理删除;
- 偏好允许并存,但标注作用范围和更新时间;
- 低可信度记忆可以被更强证据纠正;
- 高风险信息需要用户确认后再更新。
这样,系统既能使用当前有效版本,也能解释“为什么发生变化”。
遗忘是系统能力
只写不删的记忆库不会越来越聪明,只会越来越难以控制。遗忘至少包含三种机制:
- 到期:临时计划在时间窗口结束后自动失效。
- 衰减:长期未使用、低价值的记忆逐步降低召回权重。
- 删除:用户可以查看并删除与自己相关的记忆,删除需要贯穿索引、缓存和备份策略。
“被删除”也不应只是一条数据库标记。系统要定义传播路径和完成状态,确保后续生成不会继续使用已撤回的信息。
评估:从命中率走向帮助度
记忆系统不能只看检索命中率。真正需要评估的是端到端效果:
- 该记住的信息是否被正确提取;
- 不该记住的信息是否被拒绝;
- 需要时是否召回;
- 召回内容是否改善了最终回答;
- 过时或错误记忆是否造成负面影响。
离线评测可以构造跨轮次任务,检查记忆写入与使用;线上则更适合观察用户纠正、记忆删除、召回后放弃等信号。对隐私敏感的内容,评估样本也必须经过脱敏和访问控制。
一条可治理的闭环
长期记忆系统可以概括为一个循环:
交互证据 → 候选提取 → 规范化与合并 → 存储
↑ ↓
反馈与纠正 ← 生成使用 ← 重排与过滤 ← 召回
每个箭头都应该有可观测状态,每次写入和使用都应该能够追溯。只有这样,记忆才不再是“模型好像记得”,而是一个能够解释、纠正和治理的工程系统。
小结
长期记忆的核心并不是保存更多,而是在正确的时刻使用少量、可靠、仍然有效的信息。提取决定记什么,召回决定想起什么,生命周期治理决定系统能否在长期运行中保持可信。
模型负责理解语义,工程系统负责边界。两者结合,记忆才会从演示效果变成稳定能力。