Claude Code 的记忆进化:Auto Memory 与 PreCompact Hook 完全解析

问题的起源

用 Claude Code 写代码的人都遇到过一个痛点:Context Window 满了怎么办?

每个 session 的上下文是有限的。当对话太长,Claude Code 会自动压缩(compaction)旧的对话内容,只保留摘要。问题是——压缩意味着丢失细节。你花了半小时调试的那个诡异 bug,压缩后可能就剩一句"修复了 XX 问题"。

下次开新 session?更惨,Claude 完全不记得之前发生了什么。

这就引出了两个核心问题:

  1. 跨 session 记忆:Claude 怎么记住上次学到的东西?
  2. Compaction 保护:压缩前怎么保存完整上下文?

Claude Code 最近给出了自己的答案。

Auto Memory:Claude 自己写笔记

机制

Auto Memory 是 Claude Code 新增的自动记忆系统。跟用户手动维护的 CLAUDE.md 不同,Auto Memory 是 Claude 自己写给自己的笔记。

在工作过程中,Claude 会自动记录:

  • 项目模式:构建命令、测试约定、代码风格
  • 调试心得:棘手问题的解决方案、常见错误原因
  • 架构笔记:关键文件、模块关系、重要抽象
  • 用户偏好:沟通风格、工作流习惯、工具选择

存储结构

每个项目有独立的记忆目录:

~/.claude/projects/<project>/memory/
├── MEMORY.md          # 索引文件,每次 session 自动加载前 200 行
├── debugging.md       # 调试模式详细笔记
├── api-conventions.md # API 设计决策
└── ...                # 其他主题文件

<project> 路径基于 Git 仓库根目录,同一 repo 的所有子目录共享一个记忆目录。

加载策略

这是设计上比较聪明的地方:

  • MEMORY.md:前 200 行自动注入系统 prompt,每次 session 都能看到
  • 主题文件(如 debugging.md):不自动加载,Claude 按需读取

这样既保证了核心记忆的连续性,又不会浪费宝贵的 Context Window。

优点

🟢 零维护成本——用户不需要手动记录项目细节 🟢 Per-project 隔离——不同项目互不污染 🟢 分层设计——索引轻量加载,详细内容按需读取 🟢 越用越聪明——调试过的坑不会再踩第二次

潜在问题

🔴 200 行硬限制——超过的部分不会自动加载,可能丢失重要信息 🔴 质量不可控——Claude 自己决定记什么,可能记了无用的、漏掉关键的 🔴 错误记忆——如果写入了错误信息,后续 session 会一直被误导 🔴 膨胀问题——长期使用后文件越来越多,需要人工清理 🔴 不透明——用户可能不知道 Claude 记了什么,除非主动去翻目录 🔴 Context 成本——每次启动都加载 200 行,占用 Context Window

管理方式

可以通过以下方式管理 Auto Memory:

  • /memory 命令打开文件选择器,直接编辑
  • 直接告诉 Claude:“记住我们用 pnpm 不用 npm”
  • 手动编辑 ~/.claude/projects/<project>/memory/ 下的文件

也可以通过环境变量控制开关:

export CLAUDE_CODE_DISABLE_AUTO_MEMORY=1  # 强制关闭
export CLAUDE_CODE_DISABLE_AUTO_MEMORY=0  # 强制开启

PreCompact Hook:在压缩前抢救上下文

Auto Memory 解决了"记什么"的问题,但还有一个场景它管不到——Compaction 瞬间的完整上下文保存

这个问题的解决方案来自社区。Twitter 用户 @zarazhangrui 分享了一个巧妙的做法。

原始方案:/handover 命令

Zara 最初创建了一个自定义 slash command /handover

  • 用户在 session 结束前手动执行
  • Claude 回顾整个对话,生成一份"交班报告"(HANDOVER.md
  • 内容包括:做了什么、成功/失败的部分、关键决策、踩过的坑、下一步计划

这本质上是医院护士换班时的 handover notes——确保下一个人知道所有重要信息。

进化方案:PreCompact Hook 自动化

社区用户 @pauloportella_ 提出了关键改进:“turn this into a pre auto compact hook and it will do it automatically”。

这个方案利用了 Claude Code 的 Hooks 系统——在特定生命周期事件触发时自动执行用户定义的脚本。

配置方式

.claude/settings.local.json 中注册 Hook:

{
  "hooks": {
    "PreCompact": [
      {
        "matcher": "auto",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/pre-compact-handover.py"
          }
        ]
      }
    ]
  }
}

执行流程

当 Claude Code 检测到 Context Window 即将满载,自动触发 compaction 时:

  1. PreCompact Hook 触发——在压缩执行之前
  2. 脚本从 stdin 接收 JSON,包含 session_idtranscript_path(完整对话记录路径)等
  3. 读取 transcript_path 获取完整的、未压缩的对话内容
  4. 调用 claude -p 启动一个新的 Claude 实例,专门生成 handover 摘要
  5. 保存为 HANDOVER-YYYY-MM-DD.md
  6. Compaction 正常执行,压缩旧内容

关键细节

matcher 的作用

PreCompact 事件的 matcher 支持两个值:

  • "auto":只在系统自动 compaction 时触发(Context Window 快满了)
  • "manual":只在用户手动执行 /compact 命令时触发
  • "*" 或省略:两种都匹配

Zara 选择了 "auto"——只有系统自动压缩时才生成 handover,手动压缩时不触发(因为手动压缩说明用户有意为之,不需要抢救上下文)。

独立实例的设计

claude -p 启动新实例来生成摘要,而不是在当前 session 里做,原因是:

  • 当前 session 的 Context Window 已经快满了,没有空间再做摘要
  • 独立实例有完整的 Context 空间来处理对话记录

Hooks 系统全貌

PreCompact 只是 Claude Code Hooks 系统的一个事件。完整的生命周期事件包括:

事件触发时机
SessionStartSession 开始或恢复
UserPromptSubmit用户提交 prompt
PreToolUse工具调用执行前(可拦截)
PostToolUse工具调用成功后
PreCompactContext 压缩前
StopClaude 完成回复
SessionEndSession 结束

Hook 支持三种处理器类型:

  • Command:执行 shell 脚本
  • Prompt:发送 prompt 给模型做单轮评估
  • Agent:启动子代理,可使用工具验证条件

详细文档:Hooks 完整参考 | Hooks 入门指南

两种方案的关系

Auto Memory 和 PreCompact Hook 解决的是不同层面的问题:

🔵 Auto Memory日常积累——Claude 在工作过程中持续记录有价值的知识,跨 session 可用 🟢 PreCompact Hook紧急抢救——在 Context 被压缩的那一刻,保存完整的工作状态

它们不是竞争关系,而是互补的:

  • Auto Memory 是长期记忆,记录的是"知识"
  • PreCompact Handover 是工作快照,记录的是"状态"

最佳实践是两者结合使用——Auto Memory 让 Claude 越来越了解你的项目,PreCompact Hook 确保你永远不会因为 Context 压缩而丢失工作进度。

参考链接

如果这篇文章对你有帮助,欢迎请我喝杯咖啡,支持我继续创作更多内容。

Buy me a coffee