前言
大模型本身并不会自动记住很久以前发生的事情。上下文窗口再大,也只能看到当前请求携带的内容;会话结束、窗口被截断或者换了一个Agent,之前的信息就可能消失。
最直接的办法是把所有历史对话重新塞进Prompt,但随着聊天越来越多,这个办法很快就会遇到三个问题:
- 历史记录越来越长,Token成本和响应时间持续增加。
- 原始对话里有大量寒暄、重复信息和已经失效的内容。
- 真正重要的信息被埋在大量文本中,模型未必能准确注意到。
因此,AI长期记忆不能只是“保存聊天记录”,还需要对信息进行提炼和组织。L0到L3就是一种分层记忆方法:底层保留原始证据,上层逐渐压缩成更容易使用的知识。
L0 原始对话
↓ 提取事实、偏好、约束和事件
L1 原子记忆
↓ 按项目或主题组织
L2 场景记忆
↓ 跨场景归纳长期稳定特征
L3 核心画像先记住一句话:
L0回答“当时说了什么”,L1回答“哪些点值得记”,L2回答“这个场景完整发生了什么”,L3回答“这个人长期是谁、应该怎样与他协作”。
四层记忆快速对比
| 层级 | 保存内容 | 典型粒度 | 更新频率 | 主要用途 |
|---|---|---|---|---|
| L0 | 用户和Agent的原始消息 | 一条消息或一轮对话 | 每轮写入 | 原文追溯、重新提取、历史搜索 |
| L1 | 事实、偏好、约束、决策、事件 | 一个独立知识点 | 较频繁 | 关键词/向量检索,精确召回 |
| L2 | 围绕项目或主题组织的场景档案 | 一个场景或一个项目上下文 | 中等 | 快速恢复完整工作背景 |
| L3 | 长期稳定的画像、习惯和协作原则 | 用户或Agent的全局认知 | 最低 | 新会话冷启动、稳定行为指导 |
它们不是四份重复数据,而是同一批信息在不同抽象层次上的表达。
用一个例子贯穿L0到L3
假设用户在一次开发任务中说:
用户:旧的鉴权模块先不要重构,移动端还在使用它。
助手:明白,本次只新增v3接口,不修改旧鉴权流程。这段内容进入记忆系统后,会经历下面的变化。
L0:保留原始对话
L0基本不做语义压缩,保存用户和助手实际说过的话,同时记录会话、角色、时间和消息ID等信息。
{
"session_id": "session-001",
"role": "user",
"content": "旧的鉴权模块先不要重构,移动端还在使用它。",
"timestamp": "2026-08-03T10:00:00+08:00"
}L0最像录音或聊天原稿。它的价值不是方便每轮全部读取,而是提供可信的事实来源:
- 想确认用户原话时,可以回到L0。
- L1提取错误时,可以根据L0重新提取。
- 上层记忆发生冲突时,可以用L0核对时间和上下文。
- 需要寻找某段历史对话时,可以直接搜索L0。
L0的问题也很明显:数据量大、重复多、噪声多,不适合每轮全部注入模型。
L1:提取原子记忆
系统通过规则或LLM分析L0,提取出可以独立成立的知识点:
{
"type": "constraint",
"content": "旧鉴权模块暂时不能重构,因为移动端仍然依赖它。",
"priority": "high",
"source_message_ids": ["message-001"]
}这就是L1原子记忆。“原子”表示一条记忆尽量只描述一个事实:
- 偏好:用户希望使用简体中文回答。
- 事实:项目后端使用TypeScript。
- 约束:旧鉴权模块不能修改。
- 决策:新接口统一使用v3协议。
- 事件:2026年8月3日完成了MemoryCore部署。
- 经验:修改Pipeline后需要检查空闲定时器是否仍能触发。
L1通常是检索的主力。当前问题到来时,系统可以同时使用BM25关键词检索和Embedding向量检索,再把两边结果融合,找出最相关的几条记忆。
例如用户问“这次能不能顺便重构登录逻辑”,系统就可能召回“旧鉴权模块暂时不能重构”这条L1,而不需要重新阅读几个月的对话。
L1比L0更短、更准,但它也有缺点:大量原子记忆彼此独立,缺少完整项目背景。
L2:组织成场景记忆
当鉴权相关的L1越来越多,系统会把它们组织成一个场景:
# 移动端鉴权兼容
## 背景
旧移动端仍然使用legacy-auth,新版本服务正在迁移到v3认证体系。
## 当前约束
- 暂时不能删除或重构旧鉴权模块。
- 新开发不能继续扩大对legacy-auth的依赖。
## 已做决策
- 新接口统一使用v3认证。
- 新旧鉴权暂时并行。
- 等移动端完成升级后,再清理legacy-auth。
## 相关进展
- 已完成v3接口的基础实现。
- 尚未确认旧移动端的下线时间。L2不是单个事实,而是一份围绕具体项目、主题或生活场景的专题档案。它把分散的L1整理成模型容易理解的叙事结构。
常见场景可能包括:
- 某个项目的技术架构和历史决策;
- 某次线上故障的原因和处理过程;
- 用户的健身、旅行或学习计划;
- 一套持续演进的发布流程;
- 一个长期客户的合作背景。
系统通常不会把所有L2全文塞进Prompt,而是先提供一个场景目录:
可用场景:
- 移动端鉴权兼容
- MemoryCore部署
- v2到v3数据迁移模型发现当前问题与某个场景相关时,再通过工具读取完整内容。这是一种渐进式披露:先让模型知道“有什么”,需要时再读取“具体是什么”。
L3:形成长期核心画像
如果类似的信息在多个场景中反复出现,系统才可能把它归纳到L3:
# 核心画像
## 工作方式
- 修改代码前倾向于先理解完整调用链。
- 重视兼容性、数据安全和可回滚性。
- 更偏好增量改造,而不是一次性大规模重写。
## 协作偏好
- 希望先看到结论,再了解原因和实现细节。
- 对高风险操作需要明确说明影响范围。L3描述的不是某一次任务,而是跨会话、跨项目仍然相对稳定的特征。它可以是用户画像,也可以是团队的工作原则、Agent角色认知或长期协作方式。
需要特别注意:不能因为用户只说过一次“不要重构旧模块”,就马上断定用户永远反对重构。L3的生成应该比L1和L2更加保守,只有长期重复出现、证据充分的模式才适合进入核心画像。
一轮对话中,四层记忆如何工作
一次完整的Agent交互通常分成“召回”和“写入”两个方向。
对话开始前:召回
用户提出问题
├─ 搜索与问题相关的L1
├─ 读取稳定的L3核心画像
└─ 获取L2场景目录
↓
组合成受控的上下文
↓
交给LLM处理比较合理的Prompt组织方式是:
- L1每轮都可能变化,作为动态上下文放在用户问题附近。
- L3和L2场景目录变化较慢,作为稳定上下文放在System Prompt区域。
- L2全文和L0原文不默认注入,需要时通过工具读取。
这样既能保证模型拿到足够的信息,又不会让记忆挤占整个上下文窗口。
对话结束后:写入和提炼
Agent完成一轮任务
↓
清洗本轮新增消息
↓
立即写入L0
↓ 异步处理
提取、去重并写入L1
↓ 延迟聚合
创建或更新L2场景
↓ 更低频、更保守地归纳
更新L3核心画像L0通常立即写入,因为它是原始事实。L1、L2和L3可以异步生成,这样记忆系统变慢或LLM提炼失败,也不应该阻塞用户正在进行的对话。
为什么不能只使用向量数据库
向量数据库解决的是“怎样找到语义相近的文本”,但它不等于完整的记忆系统。
假设把所有历史对话切块后直接做Embedding:
- 可以找到语义相似的内容,但不一定知道哪条已经失效。
- 搜到的是原始片段,模型仍然需要现场归纳。
- 多个片段可能互相矛盾,缺少版本和时间关系。
- 无法自然表达某个项目的完整背景。
- 很难形成稳定、可控的长期用户画像。
所以更完整的做法是:
向量检索/BM25:负责“找到候选信息”
L0-L3分层:负责“把信息组织成可长期使用的记忆”
权限与隔离:负责“谁可以使用这些记忆”
版本和来源:负责“这条记忆是否可信、能否追溯”向量库是记忆系统的重要组件,但不是记忆系统本身。
为什么四层缺一不可
如果只有L0
保存最完整,但上下文会快速膨胀。每次都让模型重新阅读历史,也会重复支付理解成本。
如果只有L1
精确检索很方便,但知识会变成大量散落的卡片。模型知道很多局部事实,却不一定理解整个项目为什么会变成现在这样。
如果只有L2
能够恢复项目背景,但查找一个具体日期、原话或约束时不够精确,也不便验证来源。
如果只有L3
上下文最短,但过度抽象容易产生刻板印象。它无法回答某次任务具体做过什么,更不能代替原始证据。
四层组合起来,才同时具备精确性、上下文、压缩率和可追溯性。
实现时最容易踩的坑
1. 把召回内容再次写进L0
系统可能先把相关记忆添加到用户消息前面,再交给模型。如果捕获阶段直接保存这个被修改后的消息,召回结果就会被重新写入L0,下一轮又可能再次召回,形成反馈污染。
正确做法是在注入前缓存用户原始文本,写入L0时还原原文。
2. 每轮重复保存整段历史
很多Agent框架在一轮结束时给出的是完整消息数组,而不是本轮新增消息。必须通过消息位置或时间游标切出增量,否则L0会产生大量重复数据。
3. L1没有保留来源
L1经过LLM提炼后可能出现误解。如果不记录来源消息ID,就无法回到L0核验,也很难纠错。
4. 把偶发行为过早写进L3
L3应该稳定、保守。一次临时决定不等于长期偏好,一次情绪表达也不等于人格特征。L3需要跨时间、跨场景的多条证据。
5. 只增加记忆,不处理过期和冲突
用户偏好、项目状态和技术决策都会变化。记忆系统不仅要会“记住”,还要支持更新、版本、失效、归档和冲突处理。
6. 记忆服务故障拖垮主对话
召回可以并行并设置严格超时;某一路失败时使用其他可用结果。捕获或异步提炼失败时记录日志并稍后重试,不应该让Agent因此无法回答用户。
L0-L3与Adapter的关系
L0-L3负责“记忆怎样保存和组织”,Adapter负责“Agent框架怎样接入记忆系统”,两者不是一回事。
OpenClaw / Hermes / 自定义Agent
↓ 生命周期事件
Adapter
↓ 标准API或SDK
L0-L3记忆系统Adapter通常只需要做好三件事:
- 在构造Prompt前召回L1、L2和L3。
- 在一轮结束后把新增对话写入L0。
- 给模型暴露搜索L1、搜索L0和读取L2等工具。
这样记忆系统就不必绑定某一个Agent框架,同一套记忆可以被多个Agent或不同运行时使用。
最后总结
以后忘记L0到L3时,只需要回忆下面四句话:
L0:原始记录——当时到底说了什么?
L1:原子知识——哪些事实、偏好、约束和事件值得记?
L2:场景档案——某个项目或主题的完整上下文是什么?
L3:核心画像——这个人或团队长期是谁,应该怎样与其协作?再记住它们的读取顺序:
默认使用:L3 + L2目录 + 少量相关L1
信息不足:读取L2全文 → 搜索更多L1 → 最后追溯L0原文真正有价值的AI记忆,不是永远保存所有内容,而是让下一次任务可以准确继承上一次已经付出的理解成本。