你有没有这样的经历:每次新开Claude Code会话,都要重复说"我是后端工程师"、“这个项目用Bun构建”、“不要用mock测试数据库”?
没有记忆的AI就像金鱼——每次对话都从零开始。今天咱们聊聊Claude Code的跨会话记忆系统,看AI如何"长记性"。
六层记忆架构
Claude Code的记忆系统有六个层次,从高频增量到低频全局:
| 层级 | 核心文件 | 频率 | 职责 |
|---|---|---|---|
| Memdir | memdir/memdir.ts | 每次会话 | MEMORY.md索引+主题文件,注入系统提示词 |
| Extract Memories | extractMemories.ts | 每轮结束 | Fork agent自动提取记忆 |
| Session Memory | sessionMemory.ts | 定期触发 | 滚动会话摘要,用于压缩 |
| Transcript | sessionStorage.ts | 每消息 | JSONL会话记录存储与恢复 |
| Agent Memory | agentMemory.ts | Agent生命周期 | 子Agent持久化+VCS快照 |
| Auto-Dream | autoDream.ts | 每日 | 夜间记忆整合与修剪 |
这就像人类记忆的层次:
- Memdir:长期记忆库
- Extract Memories:短期记忆编码
- Session Memory:工作记忆摘要
- Transcript:完整记忆备份
- Agent Memory:专业技能记忆
- Auto-Dream:睡眠记忆整理
Memdir:记忆的存储层
记忆目录位置
三级优先链决定记忆存储位置:
CLAUDE_COWORK_MEMORY_PATH_OVERRIDE环境变量autoMemoryDirectory设置(排除projectSettings防恶意重定向)- 默认:
~/.claude/projects/<git-root>/memory/
所有worktree共享同一个记忆目录——记忆是关于项目的,不是关于工作目录的。
MEMORY.md索引
MEMORY.md是记忆系统的入口点,每行指向一个主题文件:
- [编码规范](coding-style.md) - 项目TypeScript编码规范
- [数据库配置](database.md) - PostgreSQL连接信息
- [API文档](api-reference.md) - REST API端点列表
双重截断防止膨胀:
- 最多200行
- 最多25KB
截断时追加WARNING消息,提示模型将详细内容移到主题文件——自修复机制。
主题文件格式
每个记忆是独立Markdown文件,YAML frontmatter标注元数据:
---
name: 编码规范
description: TypeScript项目代码风格指南
type: project
---
- 使用2空格缩进
- prefer `const` over `let`
- ...
四种类型:
- user:用户角色、偏好、知识水平
- feedback:用户对Agent行为的纠正和指导
- project:正在进行的工作、目标、截止日期
- reference:外部系统的指针(Linear、Grafana等)
KAIROS日志模式
KAIROS长期运行模式下,记忆写入策略变为追加到每日日志文件:
memory/logs/2026/04/2026-04-03.md
Append-only策略避免频繁重写,蒸馏交给夜间Auto-Dream处理。
Extract Memories:自动记忆提取
触发机制
每轮查询结束时,fork agent静默分析对话并提取值得持久化的信息。
触发条件:
- 仅主Agent(排除子Agent)
- Fire-and-forget(不阻塞下一轮)
节流与互斥
节流:tengu_bramble_lintel flag控制频率(默认每轮运行)
互斥:当主Agent自己写了记忆文件,fork agent跳过本轮提取。避免两个agent同时写入同一文件的冲突。
权限隔离
fork agent的权限被严格限制:
- 允许:Read/Grep/Glob(只读)
- 允许:Bash(仅
ls、find、grep、cat等只读命令) - 允许:Edit/Write(仅
memoryDir内路径) - 拒绝:所有其他工具(MCP、Agent、写入式Bash等)
高效操作策略
提取agent的提示词明确指示:
第1轮:并行读取所有可能要更新的文件
第2轮:并行执行所有写入/编辑操作
最大轮次限制为5,防止陷入验证循环。
Session Memory:滚动会话摘要
Session Memory解决的是会话内的信息保留。当上下文接近饱和时,为压缩系统提供"什么是重要的"信号。
三重阈值保护
{
minimumMessageTokensToInit: 10000, // 首次触发:10K token
minimumTokensBetweenUpdate: 5000, // 更新间隔:5K token
toolCallsBetweenUpdates: 3 // 最低工具调用数:3
}
触发条件:
- token阈值(5K)必须满足
- 加上:(a) 工具调用数≥3,或(b) 最后一个assistant轮次没有工具调用(自然对话断点)
这样不会在短对话中触发,也不会在密集工具调用中间打断工作流。
与自动压缩的关系
Session Memory注册为post-sampling hook。但初始化门控检查isAutoCompactEnabled()——如果自动压缩被禁用,Session Memory也不运行。
Session Memory的主要消费者就是压缩系统。摘要文件summary.md在压缩时被注入。
与Extract Memories的区别
| 维度 | Session Memory | Extract Memories |
|---|---|---|
| 持久化范围 | 会话内 | 跨会话 |
| 存储位置 | ~/.claude/projects/<root>/<session-id>/session-memory/ | ~/.claude/projects/<root>/memory/ |
| 触发时机 | token阈值+工具调用阈值 | 每轮查询结束 |
| 消费者 | 压缩系统 | 下次会话的系统提示词 |
| 内容结构 | 固定章节模板 | 自由格式主题文件 |
两者并行运行,互不干扰。
Transcript Persistence:完整会话记录
sessionStorage.ts(5105行,最大单文件之一)负责将会话记录持久化为JSONL格式。
JSONL格式
每条消息序列化为一行JSON,追加到会话文件:
{"type":"user","content":"帮我重构这个模块","timestamp":"2026-04-03T10:00:00Z"}
{"type":"assistant","content":"好的,让我先理解代码结构","tool_uses":[{"name":"Read","input":{"file_path":"/src/app.ts"}}]}
JSONL的选择是出于性能——增量追加只需appendFile,不需要解析和重写整个文件。
特殊条目类型
除了标准user/assistant消息,还包含:
file_history_snapshot:文件历史快照,用于压缩后恢复文件状态attribution_snapshot:归因快照,记录文件修改来源context_collapse_snapshot:压缩边界标记content_replacement:内容替换记录,用于REPL模式输出截断
会话恢复
claude --resume时:
- 解析所有JSONL条目
- 根据
uuid/parentUuid重建消息树 - 应用
context_collapse_snapshot,恢复到压缩后的状态 - 重建文件历史快照,确保模型对文件状态的理解与磁盘一致
这使得跨会话"续写"成为可能。
Agent Memory:子Agent持久化
子Agent有自己的记忆需求:
- 代码审查agent需要记住团队代码风格偏好
- 测试agent需要记住项目测试框架配置
三作用域模型
| 作用域 | 路径 | 可提交到VCS | 用途 |
|---|---|---|---|
| user | ~/.claude/agent-memory/<agentType>/ | 否 | 跨项目的用户级偏好 |
| project | <cwd>/.claude/agent-memory/<agentType>/ | 是 | 团队共享的项目知识 |
| local | <cwd>/.claude/agent-memory-local/<agentType>/ | 否 | 本机特定的项目配置 |
每个作用域独立维护MEMORY.md索引和主题文件。
VCS快照同步
project作用域的记忆应该通过Git在团队间共享,但.claude/agent-memory/在.gitignore中。
解决方案是单独的快照目录.claude/agent-memory-snapshot/,通过snapshot.json中的updatedAt时间戳追踪版本。
三种策略:
none:无快照initialize:复制快照到本地prompt-update:提示模型合并(不自动覆盖)
Auto-Dream:夜间记忆整合
Auto-Dream是记忆系统的"睡眠阶段"——后台整合任务,需要同时满足时间门控(默认24小时)和会话门控(默认5个新会话)。
四层门控系统
第一层:Master Gate
if (getKairosActive()) return false // KAIROS模式用自己的dream skill
if (getIsRemoteMode()) return false // 远程模式存储不可靠
if (!isAutoMemoryEnabled()) return false
return isAutoDreamEnabled()
第二层:Time Gate
- 距上次整合至少24小时
- 时间信息通过锁文件的mtime获取
第三层:Session Gate
- 上次整合以来至少有5个新会话被修改
- 扫描有10分钟冷却期
第四层:Lock Gate
- 获取并发锁
- 如果另一进程正在整合,当前进程放弃
PID锁机制
锁文件.consolidate-lock承载双重语义:
- mtime =
lastConsolidatedAt(上次整合时间) - 文件内容 = 持有者PID
获取锁的流程:
stat+readFile获取mtime和PID- 如果mtime在1小时内且PID存活 → 被占用
- 如果PID已死或mtime过期 → 回收锁
- 写入自己的PID
- 重新读取验证(防止竞态条件)
四阶段整合
整合agent收到结构化提示词:
Phase 1 - Orient:浏览记忆目录、读MEMORY.md、浏览主题文件
Phase 2 - Gather:搜索日志和会话记录寻找新信号
Phase 3 - Consolidate:合并到现有文件、消除矛盾、相对日期→绝对日期
Phase 4 - Prune & Index:保持MEMORY.md在200行/25KB内
提示词强调"合并优于创建"、“修正优于保留”,防止记忆文件无限增长。
高频增量+低频全局
Extract Memories和Auto-Dream形成互补架构:
用户对话
↓
Query Loop结束
↓
Extract Memories(每轮)──→ 写入主题文件 / 追加日志(KAIROS模式)
↓
Auto-Dream(定期)────────→ 读取日志+主题文件,整合后写回
↓
下次会话加载 ─────────────→ 系统提示词注入
| 维度 | Extract Memories | Auto-Dream |
|---|---|---|
| 频率 | 每轮(可节流) | 每日(24h+5会话) |
| 输入 | 最近N条消息 | 整个记忆目录+会话记录 |
| 操作 | 创建/更新主题文件 | 合并、修剪、消除矛盾 |
| 类比 | 短期记忆→长期记忆的编码 | 睡眠中的记忆整合 |
实战:管理你的记忆
管理MEMORY.md
理解200行限制是关键。如果索引超过200行,后面条目会被截断。
最佳实践:
- 最重要的条目排前面
- 每个索引条目控制在一行150字符以内
- 将详细内容移到主题文件
理解什么会被记住
四种类型各有最佳用途:
feedback(最有价值):
- “不要用mock测试数据库”
- “prefer early return over nested if”
- 直接改变Agent行为
user:
- “我是后端工程师,不熟悉前端”
- 帮助Agent调整沟通风格
project:
- “目标是在本周五前完成重构”
- 有时效性,需要定期清理
reference:
- “Grafana面板:https://…”
- 外部资源快捷方式,保持简短
控制自动记忆
# 完全禁用所有自动记忆
export CLAUDE_CODE_DISABLE_AUTO_MEMORY=1
settings.json:
{
"autoMemoryEnabled": false, // 按项目禁用
"autoDreamEnabled": false // 只禁用夜间整合,保留即时提取
}
手动触发整合
使用/dream命令即时运行记忆整合:
- 完成大型重构后,更新项目上下文
- 团队成员切换后,整理个人偏好
- 发现记忆文件中有过时或矛盾信息
CLAUDE.md vs 记忆系统
两者互补:
- CLAUDE.md:存储不应被修改的指令(编码规范、架构约束、团队流程)
- 记忆系统:存储可以演化的知识(用户偏好、项目上下文、外部引用)
如果某个信息不应该被Auto-Dream修剪或修改,放在CLAUDE.md中。
这对构建AI Agent的启示
模式1:多层记忆架构
将记忆系统分为三层:
- 原始信号层(日志/会话记录):高频低质
- 结构化知识层(主题文件):中频中质
- 索引层(MEMORY.md):低频高质
模式2:后台提取via Fork Agent
- 在查询循环结束时启动fork agent
- 继承父对话的prompt cache降低成本
- 严格权限隔离(只能写入记忆目录)
- 与主agent通过互斥检查协调
模式3:文件mtime即状态
使用锁文件,其mtime即lastConsolidatedAt,内容即持有者PID。通过stat/utimes/writeFile实现读取、获取、回滚。
模式4:预算约束的记忆注入
多级截断防止记忆无限增长:
- MEMORY.md最多200行/25KB
- 最多200个记忆文件
- Session Memory每节2000 token,总量12000 token
模式5:互补频率设计
双频策略:
- 高频增量提取:捕获所有可能有价值的信号,容忍误报
- 低频全局整合:修剪噪音、消除矛盾、合并重复,修复误报
总结
跨会话记忆是Claude Code从"无状态函数"进化为"有状态助手"的关键:
- 六层架构:从高频增量到低频全局
- 自动提取:每轮fork agent静默分析
- 会话摘要:为压缩系统提供重要信号
- 完整记录:JSONL格式支持会话恢复
- 子Agent记忆:三作用域模型支持专业化
- 夜间整合:Auto-Dream像睡眠一样整理记忆
这就像人类记忆的工作原理:
- 白天:不断接收新信息(Extract Memories)
- 晚上:睡眠中整理巩固(Auto-Dream)
- 长期:形成结构化知识库(Memdir)
理解记忆系统,你就能:
- 更高效地管理项目上下文
- 让AI真正"长记性"
- 在自己的AI Agent中实现持久学习
下篇咱们聊聊驾驭工程原则——从Claude Code学到的架构智慧。
