Claude记忆系统深度解析:三层架构如何重塑AI对话体验
一、先讲结论
Claude Code 的记忆系统,远不止是“往文件里追加几行笔记”那么简单。它本质上是一套精心设计的三层架构,分别应对三个不同时间尺度的问题。
| 层级 | 名称 | 时间尺度 | 核心机制 | 是否阻塞主对话 |
|---|---|---|---|---|
| 短期 | Session Memory | 当前会话 | 后台 forked agent 维护结构化笔记 | 否 |
| 中期 | Auto Memory Extraction | 每轮对话结束后 | 后台 forked agent 提取持久记忆到磁盘 | 否 |
| 长期 | Auto Dream | 跨 5+ 次会话后 | 后台 forked agent 整合/修剪记忆目录 | 否 |
几个关键的设计要点值得注意:
- 异步是核心:三层机制都尽量不阻塞主对话。它们利用的是逻辑上的“分叉袋里”(forked agent),而非操作系统层面的子进程。这样做的好处是能复用父级的提示词缓存,将额外成本控制在一次旁路LLM调用附近。不过,三者的触发时机不同:Session Memory 注册在每次模型采样后,而提取记忆和自动“梦境”则是在查询循环结束时触发。
- 层级间有协作:它们并非孤立运行。例如,在特定条件下,Session Memory 的笔记可以被上下文压缩功能优先复用;而自动提取写入的文件,又会被 Auto Dream 整合。
- 主次袋里互斥:更准确地说,这是 Auto Memory Extraction 的策略——如果主袋里本轮已经手动写了记忆文件,后台提取就会跳过这一段,避免重复劳动。
- 记忆读取路径多样:基础模式是把
MEMORY.md作为索引加载进上下文;而在实验性分支中,系统会在每轮查询前,动态召回最多5个相关的记忆文件。
如果你正在构建自己的智能体,这套设计最值得借鉴的并非具体的阈值参数,而是其“后台分叉 + 提示词缓存共享 + 权限沙箱”的模式。它让你能在不增加用户感知延迟的前提下,为智能体增添各种“旁路”能力。
二、它在解决什么问题
用过 ChatGPT 或类似对话产品的人,几乎都体会过同一个痛点:昨天的对话,今天全忘了。
对于编程助手这类智能体来说,这个问题尤为严重。想象一下,你花了一小时教会助手理解项目的构建流程、测试命令和代码规范,结果第二天打开新会话,一切又得从头再来。更糟糕的是,即使在同一次会话中,当上下文被压缩后,许多关键细节也可能丢失。
传统的解决方案是让用户手动维护一个 CLAUDE.md 配置文件。但问题显而易见:
- 用户惰性:大多数人不会主动、持续地去更新配置文件。
- 粒度错配:有些信息只在当前会话中有用(比如“我刚运行的测试命令是
npm test -- --grep auth”),并不值得写入永久配置。 - 信息过时:三个月前记录的项目结构笔记,放到今天可能已经完全不对了。
Claude Code 的思路很明确:别让用户自己记,让智能体自己记。并且,针对不同时间尺度的记忆需求,采用不同的策略。
三、三层记忆的完整工作流
下面这张流程图清晰地展示了三层记忆系统如何协同工作:
flowchart TD
subgraph 短期["短期:Session Memory"]
SM_T["触发条件:token增长≥5K
且工具调用≥3次
或对话自然间断"]
SM_A["后台 forked agent
用 Edit 工具更新笔记文件"]
SM_F["输出:结构化 Markdown
10 个固定 section"]
end
subgraph 中期["中期:Auto Memory Extraction"]
AM_T["触发条件:每轮 query loop 收尾
(最终回答、无 tool call)"]
AM_A["后台 forked agent
读对话 → 写记忆文件到 memory/"]
AM_F["输出:topic files
+ MEMORY.md 索引"]
end
subgraph 长期["长期:Auto Dream"]
AD_T["触发条件:≥24小时
且≥5个新会话"]
AD_A["后台 forked agent
读记忆 + 必要时 grep 转录 → 整合"]
AD_F["输出:合并/修剪/更新
记忆目录"]
end
SM_T --> SM_A --> SM_F
AM_T --> AM_A --> AM_F
AD_T --> AD_A --> AD_F
SM_F -->|"被 Auto Compact 复用"| C["上下文压缩"]
AM_F -->|"下次会话作为记忆上下文被加载"| SP["记忆上下文"]
AD_F -->|"下次会话作为记忆上下文被加载"| SP
接下来,我们逐层拆解。
第一层:Session Memory —— 当前会话的自动笔记
简单来说,就是在后台维护一份结构化的 Markdown 笔记文件,专门记录当前会话的关键信息。
其模板包含10个固定部分:
# Session Title
# Current State ← 当前正在做什么
# Task specification ← 用户要求构建什么
# Files and Functions ← 重要文件及其作用
# Workflow ← 常用命令和执行顺序
# Errors & Corrections ← 遇到的错误和修复方式
# Codebase and System Documentation
# Learnings ← 什么有效什么无效
# Key results ← 用户要求的具体输出
# Worklog ← 逐步操作日志
用户可以通过 ~/.claude/session-memory/config/template.md 来自定义这个模板。实际的会话笔记文件并不放在这里,而是每个会话一份,路径格式为 {projectDir}/{sessionId}/session-memory/summary.md。配置目录存放的是模板和更新提示词,后者也可以用 prompt.md 覆盖。
触发条件:核心逻辑是,当对话的token增长足够多,并且工具调用也达到一定次数,或者对话出现自然间断(最后一轮助手没有调用工具)时,就会触发更新。Token增长是必要条件,这防止了因频繁的工具调用而过度提取。
更新方式:Session Memory 并非简单追加,而是让分叉袋里使用 Edit 工具就地编辑笔记文件的每个部分。提示词中有严格约束:每个部分上限约2K token,总文件上限12K token。一旦超标,提示词会加入CRITICAL级别的压缩指令。
与上下文压缩的协作:这是 Session Memory 最巧妙的用法之一。源码中有一条专门的 sessionMemoryCompact 分支:当自动压缩触发后,系统会先等待正在进行的 Session Memory 提取结束,然后尝试直接用已有的 summary.md 来构造压缩摘要。如果成功,就不再额外发起一次压缩请求;如果条件不满足,则回退到传统的压缩方式。所以更准确的说法是“优先走一条零额外压缩调用的快路径”。
第二层:Auto Memory Extraction —— 持久化的长期记忆
简单来说,就是在每轮查询循环收尾后,由后台分叉袋里从对话中提取值得长期保留的信息,并写入 ~/.claude/projects/ 目录。
它与 Session Memory 的关键区别在于持久性。Session Memory 只在当前会话有效,而 Auto Memory Extraction 写入磁盘的文件是跨会话持久的。基础模式下,下次会话会把 MEMORY.md 索引加载进上下文;更激进的实验路径则会在查询时动态召回相关记忆文件。
运行时机:与 Session Memory 不同,它并非在每次采样后触发,而是在查询循环结束时由特定钩子触发。具体触发点是“模型给出最终回答、查询循环不再继续”。
光标追踪与边界处理:系统使用 lastMemoryMessageUuid 来记录上次处理到哪条消息,每次只处理新增消息,避免重复提取。源码中有一个重要的边界情况处理:如果找不到对应的UUID(例如被压缩删除了),系统会回退到统计全部消息,而不是返回0导致提取功能被永久禁用。
硬上限与尾随提取:分叉袋里的对话轮数被限制为最多5轮,这是为了防止提取袋里陷入验证代码、反复搜索源文件的死循环。如果当前提取还在进行中,又来了一个新的合格轮次,系统不会丢弃或阻塞,而是将最新上下文暂存,等当前提取结束后进行一次“尾随”提取,只处理两次调用之间新增的消息。
主袋里互斥:如果主袋里在对话中已经手动写了记忆文件,后台提取就会跳过这一段,只推进游标,避免了写入冲突。
权限沙箱:分叉袋里的权限被严格限制。它被允许进行读取、搜索和全局查找,但编辑和写入操作只能针对 memory/ 目录。Bash命令只能执行只读的。这种设计既保证了功能,又确保了安全。
记忆清单预注入:在提取开始前,系统会先扫描记忆目录,将现有文件列表(最多200个)作为清单注入提示词,让分叉袋里知道已有哪些记忆文件,从而避免创建重复内容。
MEMORY.md 的截断保护:索引文件有明确的容量限制(最多200行,约25KB)。超标时,系统会先在行边界处截断,再按字节截断作为兜底,并在末尾附上警告,明确告知模型只加载了部分索引内容。
动态召回实验:一个容易被忽略的实现是,Claude Code 已经不满足于仅仅加载整个索引文件。在实验性分支中,当相关功能开关打开时,系统会从常驻上下文中过滤掉索引,改为在查询时动态召回:先扫描记忆目录中最多200个.md文件的前言,然后通过一次侧查询让模型挑选出最多5个与当前查询明显相关的记忆文件,再以附件形式注入,而不是把整个索引常驻在上下文里。这标志着系统正朝着“按需召回最相关记忆”的方向演进。
第三层:Auto Dream —— 跨会话的记忆整合
简单来说,当积累了足够多的会话后,系统会自动触发一次“梦境”——回顾所有记忆文件和会话转录,合并重复项、修正过时信息、修剪冗余内容。
这是最高级的一层。称之为“Dream”,是因为它的行为确实类似于人类睡眠中的记忆巩固过程,重点在于整理和优化已有信息,而非新增。
四步检查门:源码的实现遵循了从廉价到昂贵的检查顺序:
- 时间门:距离上次整合至少24小时(一次
stat()调用)。 - 扫描节流门:距离上次扫描至少10分钟(纯内存比较,避免每轮都扫描目录)。
- 会话门:至少有5个新会话(需要扫描转录目录)。
- 锁门:获取文件锁,防止多个进程同时进行整合。
锁机制:使用文件锁来防止并发操作。如果获取锁失败(锁文件较新且持有者进程存活),则静默跳过;如果持有者进程已死亡或锁超过1小时,则直接接管。如果整合过程出错,会回滚修改时间以便下次能重新触发;但如果是用户主动取消,则不会回滚。
整合提示词的四个阶段:
- 定位:列出记忆目录,读取
MEMORY.md,浏览现有主题文件。 - 采集新信号:读取每日日志,寻找过时的记忆,必要时在转录文件中进行针对性搜索。
- 整合:将新信号合并到已有文件中,将相对日期转换为绝对日期,删除已被推翻的旧事实。
- 修剪与更新索引:更新
MEMORY.md,保持其不超过限制,并删除过时的指针。
用户可见性:“梦境”运行时会在任务面板中显示进度,用户可以随时取消。完成后,会在主对话中显示“改进了N个记忆文件”的系统消息。
四、一个完整的记忆生命周期
假设你连续三天使用 Claude Code 进行项目开发,记忆系统的运作可能如下:
| 时间 | 事件 | 触发的记忆操作 |
|---|---|---|
| 第一天 10:00 | 开始新会话,token达到10K | Session Memory 首次初始化 |
| 第一天 10:15 | 完成一轮工具调用 | Session Memory 更新(满足5K增长和3次调用条件) |
| 第一天 10:20 | 模型给出最终回答(无工具调用) | Auto Memory Extraction 触发,写入2个记忆文件 |
| 第一天 10:30 | 上下文压缩触发 | 优先尝试 Session Memory Compact;若命中则直接用现有笔记构造摘要,否则回退普通压缩 |
| 第一天 10:45 | 会话结束 | — |
| 第二天 09:00 | 新会话开始 | 加载持久记忆索引到上下文;必要时按查询动态召回相关主题文件 |
| 第二天 09:10 | 对话进行中 | Session Memory 重新初始化(新会话新文件) |
| 第三天 下午 | 第5次会话,且距离首次超过24小时 | Auto Dream 触发:整合5个会话的记忆 |
注意第二天开始时——新会话已经能获取到第一天提取出来的持久记忆,用户无需任何操作。区别仅在于,有的实现分支是直接带上整个索引,有的则是等查询到来时再动态召回最相关的记忆文件。
五、和其他方案的对比
| 维度 | Claude Code | Cursor | Windsurf | 手动 CLAUDE.md |
|---|---|---|---|---|
| 记忆层数 | 3(短期+中期+长期) | 1(Rules) | 1(Memories) | 1(纯手动) |
| 自动提取 | 后台 forked agent | 无 | 简单追加 | 无 |
| 记忆整合 | Auto Dream(合并+修剪) | 无 | 无 | 手动维护 |
| 会话内复用 | Session Memory → Compact | 无 | 无 | 不适用 |
| 用户干预 | 零(全自动) | 需手动写 Rules | 半自动 | 全手动 |
| 成本 | 每次提取约一次 LLM 调用 | — | 不明 | 零 |
| 过时处理 | Dream 自动修剪 | 手动 | 无 | 手动 |
Claude Code 的优势在于全自动和多层次。其短板在于成本——每次分叉袋里提取都是一次LLM调用,虽然有提示词缓存共享来降低成本,但长时间使用的累计开销不容忽视。
六、局限与潜在问题
1. Session Memory 的模板刚性
10个固定部分不一定适合所有工作流。例如,进行数据分析的用户可能不需要“工作流”部分,但需要“数据集模式”部分。虽然支持自定义模板,但大多数用户不会去配置。
2. 记忆提取质量依赖模型能力
分叉袋里本质上仍然是让LLM进行“阅读理解+笔记整理”。更重要的是,提取提示词明确要求它只依据最近的对话内容来写记忆,不要再去搜索代码或阅读源码验证。这让流程更廉价,但也意味着它写入的是“对话中被提及且模型认为值得记住的事实”,不一定是“经过再次核实的事实”。一旦写错,后续会话中它很容易再次进入上下文或被召回,产生放大效应。
3. Dream 不能跨项目整合
Auto Dream 只在项目级别运行。如果你在多个相关项目间切换,每个项目的记忆是独立的。
4. 截断保护可能导致信息丢失
MEMORY.md 的200行+25KB硬性限制意味着记忆容量存在上限。对于积累了海量记忆的长期项目,截断不可避免。Auto Dream 的修剪设计可以缓解这个问题,但不能从根本上解决。
5. 后台分叉的隐性成本
虽然分叉袋里共享提示词缓存,但每次提取仍然需要生成新的内容(输出token)。在高频对话场景下,Session Memory 的更新频率可能导致显著的token消耗。
七、最后总结
Claude Code 的记忆系统回答了一个根本问题:智能体的记忆应该由谁来维护?
答案是三层分工:
- 短期记忆由 Session Memory 自动维护,解决“上下文压缩后不丢失关键信息”的问题。
- 中期记忆由 Auto Memory Extraction 自动提取,解决“下次会话还记得上次做了什么”的问题。
- 长期记忆由 Auto Dream 自动整合,解决“记忆越来越杂乱、越来越过时”的问题。
这三层的默认实现都复用了同一个架构模式:后台分叉袋里 + 提示词缓存共享 + 权限沙箱。
如果要用一句话总结最核心的设计洞察,那就是:一个好的智能体记忆系统,不是一个孤立的功能,而是一条完整的流水线。采集(Session Memory)→ 持久化(Extraction)→ 整合(Dream),每一层的成本和时间尺度不同,但它们共同构成了从“一次性工具”到“长期搭档”的进化路径。
