Claude Code 跨会话记忆实战:用 claude-mem 告别金鱼记忆

📅 发布时间:2026/10/8 17:00:35
Claude Code 跨会话记忆实战:用 claude-mem 告别金鱼记忆
最近我把 Claude Code 用作日常编码的主力之后有个问题一直卡着我代码写一半第二天重新打开终端它对我前一天的项目结构、技术选型、各种约定完全没印象。每次都要重新贴一遍 README、重复解释“这个项目用 pnpm、测试放在tests、数据库表名要带前缀”之类的信息。直到我折腾了 claude-mem 这个开源工具才算是把“跨会话记忆”这件事落到实处。它不是给模型“吃药”让它记住东西而是通过文件系统加 Claude Code 的 hook 机制把每次会话学到的东西沉淀下来在下一轮开始时重新注入上下文。这篇文章我不会只贴一个 README 式的安装步骤而是把我从装到用、从踩坑到调优的整个过程完整记录下来适合所有日常重度使用 Claude Code、尤其是做多天迭代项目的开发者。1. 它解决的痛点Claude Code 的“金鱼记忆”问题1.1 会话隔离带来的信息断层Claude Code 本身的工作模式是“一次会话一个上下文窗口”。你打开终端跑claude它加载当前项目的 CLAUDE.md加上系统提示词然后在窗口内和你对话、调工具、改文件。窗口一关这些对话历史就没了。设计上这是优点——每次会话都是干净的状态不容易被历史垃圾干扰。但做真实项目时这就很痛苦。我举一个自己遇到过的场景一个 API 服务项目我在上一轮里和 Claude 确定了接口路径规则、错误码格式、数据库字段命名规范并且让它把所有路由都按src/modules/业务/routes.ts的文件布局组织。当时聊得清清楚楚代码也照着写了。第二天我打开新会话让它加一个新模块的接口它自己从零开始猜把路由文件放到了src/routes/下面错误码风格也变了。不是它笨是它真的不知道昨天我们约定过什么。CLAUDE.md 可以解决一部分问题但前提是你记得把约定写进去。真实情况是大量约定是在对话中自然产生的你根本不会想着去同步到文件。比如“这个项目错误响应统一用中文”“测试别放 test 目录放tests”“组件命名别用 index.ts用组件名”这些话在对话里就是一句话的事但你不会专门去维护文档。claude-mem 想解决的就是让这一层“隐性约定”自动变成可复用的上下文。1.2 为什么最终选择文件系统记忆而不是对话记忆我最早也用过一些“记录对话历史”的工具效果不太好。它们的问题是对话历史不等于项目知识。一个项目里可能有一百轮对话其中九十五轮都是在改 bug、调样式、试错剩下五轮才真正产生了“以后要一直记得”的信息。如果把所有对话都塞给下一次会话反而会把重要约定淹没在流水账里。claude-mem 的思路不一样。它只做三步会话开始时扫描项目并生成快照对话过程中识别哪些信息值得长期记住把这些信息提炼成结构化文字写进记忆文件。换句话说它记住的不是“我们说了什么”而是“这个项目应该是什么样的”。这个抽象层级更接近人类程序员维护项目文档的方式所以产出的记忆也更容易检查、修改。1.3 和人工维护 CLAUDE.md 的区别有人会说那我每次聊完自己把约定写进 CLAUDE.md 不就行了可以但问题在于“每次都记得”这件事本身就是反人性的。你正在专注写代码的时候不太可能抽身去整理文档连续开几天会之后更不会去回顾哪一轮对话里产生过值得记录的约定。claude-mem 的价值在于把这个动作自动化了而且是在对话自然的停顿点自动触发。它不要求你改变工作习惯你就像平常一样和 Claude 聊天它自己判断哪些话值得记下来。实际用下来我真正动手去改记忆文件的时间反而比之前手动维护 CLAUDE.md 少很多因为大部分整理工作已经被摘要模型做了我只是偶尔做个删减。2. 安装与初始化一条命令背后的三个动作2.1 环境准备和前置条件claude-mem 是一个 Node.js 工具它依赖 Claude Code 的 hook 接口。安装前你至少需要确认三件事Node.js 版本在 18 及以上已经安装并登录了 Claude Code终端里能正常执行claude命令我有一个实际提醒先用node -v确认版本。我有一次在一台老服务器上顺手跑安装结果它直接报错一看 Node 还是 16工具根本没运行起来。先花十秒确认版本比掉进坑里再排查舒服得多。2.2 install 命令到底做了什么安装命令很简单在项目根目录下执行npx claude-memlatest install注意在哪个项目目录跑它就把记忆服务装到哪个项目。这条命令执行完我观察下来主要做了三件事。第一在 Claude Code 的配置文件里注册 hooks。具体来说它会把类似下面这样的 hook 配置合并进~/.claude/settings.json或项目级的.claude/settings.json{ hooks: { SessionStart: [ { matcher: , hooks: [{ type: command, command: claude-mem snapshot }] } ], UserPromptSubmit: [ { matcher: , hooks: [{ type: command, command: claude-mem memory }] } ], Stop: [ { matcher: , hooks: [{ type: command, command: claude-mem digest }] } ] } }这段 JSON 里的命令我是凭实操记忆写的不同版本字段名可能略有出入但事件类型就是这三个SessionStart会话开始、UserPromptSubmit用户提交提示词、Stop会话停止。claude-mem 就是靠这三个时机完成快照、注入和沉淀的。第二在当前项目的.claude-mem/目录里初始化记忆库。快照、历史记录之类的中间产物都放在这里不直接污染项目源码。第三生成或合并 CLAUDE.md 的记忆入口。它会在项目根目录的 CLAUDE.md 里加一个类似“以下内容由 claude-mem 自动维护”的区块之后自动沉淀的记忆就追加在这个区块里。看到这里你应该明白了install不是把工具“装”进 Claude Code 内部而是给 Claude Code 接了三根外部管道。这也是 hook 生态工具的典型思路不动模型、不动主程序只在事件发生的前后调用外部脚本。2.3 验证是否安装成功安装完先别急着开干花半分钟验证一下。claude-mem status如果输出里能看到项目路径、记忆文件位置、hook 状态是 active那就说明管道通了。还有一个更直接的验证方法在当前项目跑一次claude随便问一句“这个项目的记忆里有什么”。如果 Claude 能说出项目语言、构建命令这些快照信息说明 SessionStart 的 snapshot hook 已经生效。提示如果你是用npx claude-mem的方式跑的终端里直接敲claude-mem status可能会提示找不到命令。这时用npx claude-mem status代替即可。2.4 一个容易忽略的细节settings 文件的合并策略Claude Code 的 hooks 配置本身支持全局和项目两级。claude-mem 默认会优先写项目级的.claude/settings.json如果项目级文件不存在它会创建一个新的而不是直接把配置写进全局文件。这个设计的好处是项目删掉之后全局配置不会残留一堆没用的事件回调。但如果你之前已经手动配置过其他 hook就要注意它合并的时候可能不是无损的。我在一个项目里原本有一条 PostToolUse 的自定义 hook安装完发现它不见了。倒不是 claude-mem 故意覆盖而是合并逻辑在读取已有配置时遇到了一些字段冲突。建议装之前先备份一份.claude/settings.json确认无误后再决定要不要恢复。这种小坑文档里一般不会写但实际踩到还挺难受。3. 记忆读写链路从快照到提示词注入3.1 会话开始时的项目快照每次运行claude开始一个新会话SessionStart 事件会触发claude-mem snapshot。这个脚本会扫描当前项目的目录结构、读取 README、package.json、配置文件等生成一份“项目快照”。快照解决的是最基础的那层失忆Claude 至少要知道这个项目长什么样、用什么语言、有哪些模块。快照不会把整个项目的内容塞进去而是提炼出关键信息比如项目名称和一句话简介技术栈从 package.json、requirements.txt、go.mod 等文件识别顶层目录结构主要构建、测试命令关键入口文件这一层信息属于“每次都可以重新计算”的内容所以它存在.claude-mem/目录下不直接往 CLAUDE.md 里写。因为如果每次启动都去刷新 CLAUDE.md会让文件频繁变动反而影响 Claude 读取的稳定性也会污染 git 历史。3.2 交互过程中的记忆提取与沉淀会话过程中最关键的机制是 Stop 事件。当一轮对话结束比如你按了 Esc 或者 Claude 完成了一次回复claude-mem digest会被触发。它做的事是把这一轮对话里的内容交给一个模型调用做摘要提取出“对未来会话有价值的信息”。哪些信息会被提取我根据自己的使用体会总结了这几类项目的关键决策比如“数据库统一走 Prisma不用 raw SQL”用户的代码约定比如“测试文件必须放在tests目录”路径和命名规则比如“组件放在 src/components/ui”用户明说的偏好比如“错误信息用中文返回”它不会把流水账对话记下来只提取有长期价值的部分。提取完成之后模型会生成一段结构化的 markdown追加到记忆文件里。这个机制背后有一个值得说的经验摘要模型的质量基本决定了记忆质量。claude-mem 本质上是“用一次模型调用换未来无数次的上下文节省”。如果摘要得不准后面所有会话都会被带偏。所以我通常建议安装完先别急着堆功能而是用两三天观察一下它总结出来的记忆是不是符合你的预期。3.3 下一轮会话时记忆如何注入下一轮会话开始时claude-mem 除了做快照还会把之前沉淀的记忆从 CLAUDE.md 里读出来经过裁剪、去重之后交给 UserPromptSubmit hook。这个 hook 的 stdout 会被 Claude Code 拼接到当前对话的上下文中相当于每次对话开始Claude 都会“额外看到”一段记忆提示词。注入时机在用户提交提示词之前是为了让 Claude 在第一次回复时就带着记忆而不是等用户提问之后才想起来去翻。这段提示词的格式一般是[Memory] - 项目使用 TypeScript pnpm - 构建命令: pnpm build - 测试目录: __tests__ - 错误响应格式: { code, message } [/Memory]Claude 看到这种结构化标记就会把它当作项目事实来对待。这里有一个坑如果记忆提示词过于冗长会挤占上下文窗口。所以 claude-mem 在注入前会做长度限制超出部分要么截断要么只注入和当前项目最相关的部分。这也是我后面要专门聊记忆膨胀的原因。3.4 记忆分层项目级与全局级还有一个容易忽略的设计记忆分为项目级和全局级两层。项目级记忆存放在当前项目根目录的 CLAUDE.md内容只对该项目生效。全局级记忆存放在用户目录下的 CLAUDE.md内容对所有项目生效。我一般在全局层面放的是跨项目通用的个人偏好比如“代码注释用中文”“不喜欢生成不必要的接口封装层”项目层面的才放具体到这个项目的架构约定。这个分层非常重要。如果所有东西都混在一个全局记忆里几个月后 Claude 会拿着 A 项目的约定去指导 B 项目项目多了之后记忆会互相污染。claude-mem 安装的时候会同时初始化这两层你也可以通过命令分别查看当前项目的记忆和全局记忆。记忆层级存储位置作用范围适合内容项目级项目根目录 CLAUDE.md当前项目技术栈、目录约定、接口规范全局级用户目录 CLAUDE.md所有项目个人编码偏好、通用禁忌、常用命令4. 实测跨两天的真实项目会话4.1 第一天初始化项目 留下约定光讲原理太抽象我拿一个实际项目走了一遍完整流程。我建了一个名为order-service的 Node.js Express Prisma 项目然后在项目目录执行npx claude-memlatest install提示初始化成功后我在 CLAUDE.md 里手工写了几条项目基本信息然后开始和 Claude 一起写代码。第一轮对话里我明确说了三件事“这个项目的所有路由文件都放在 src/modules 下按业务模块分目录”“测试文件统一放到tests用 vitest”“所有接口的错误响应统一用 { code, message } 结构”随后我们花了一个小时创建了用户模块、订单模块写了几个测试文件中途调整过几次目录结构。每次调整 Claude 都会问我“要不要保留之前的命名”我回答“不用以后统一用新的”。这些信息在对话里非常自然但我大概率不会主动去写进 CLAUDE.md。当天结束的时候我特意看了一眼claude-mem status确认 Stop 时的 digest hook 正常触发。第二天要验证的就是那三句约定到底有没有被自动记住。4.2 第二天冷启动会话验证记忆第二天重启终端再次进入项目并运行claude。我没有做任何额外提示直接问“加一个优惠券模块接口风格按项目现有约定来。”然后看它做了什么。它先说了句类似“根据项目记忆路由放在 src/modules 下测试放在tests错误响应用统一结构”这样的话然后开始创建src/modules/coupon/routes.ts测试文件放在了__tests__/coupon.test.ts接口错误返回的 JSON 也是{ code, message }结构。整个过程不需要我重新解释任何一条约定。这一个场景就已经值回安装成本了——以前这种跨会话的一致性要么靠我反复手动维护 CLAUDE.md要么靠新会话里我复制粘贴一堆约束。我又试了一件事故意问它“我们昨天关于目录结构的约定是什么”它能准确地答出来而且表述基本和我当时说的原话一致。这说明 digest 在提取时保留了语义而不是只存了一堆关键词。4.3 还应该关注的东西记忆文件长什么样验证顺了之后我去看了一眼实际写入 CLAUDE.md 的内容。它比我预想的简洁大致是## claude-mem 自动维护 - 技术栈: Node.js, Express, Prisma, TypeScript - 构建命令: pnpm build - 测试工具: vitest - 路由目录规则: src/modules/业务/routes.ts - 测试目录规则: __tests__ - 错误响应格式: { code, message }看到这里我放心了不少。它没有长篇大论地把对话复制进去而是重新组织成了适合后续项目工作的短句。这种格式对于 Claude 来说也容易理解它不需要在一堆叙述性文字里找要点。4.4 token 开销和速度的实测感受天下没有免费的午餐。安装 claude-mem 之后每次会话会有额外开销SessionStart 的快照扫描有少量耗时Stop 时的 digest 会调用一次模型做摘要消耗额外 tokenUserPromptSubmit 注入记忆会增加一点上下文长度我实测下来digest 的次数和 token 消耗跟对话长度有关。一个上午的密集开发大约触发 10 到 20 次 digest额外消耗的 token 大概相当于几次日常对话的量。对于商业订阅用户来说基本可以接受但如果你的场景是海量交互、token 极其敏感最好还是看一眼具体用量再决定开多大的配置。速度方面快照扫描在中小型项目上体感不超过一两秒基本无感大仓库会明显一些我在一个几万文件的 monorepo 里跑过一次首屏会卡一下但还能接受。注意claude-mem 的 digest 本质是额外的模型请求它会产生持续的用量。它不是安装完就一劳永逸的你需要在收益和成本之间做个判断。5. 避坑与调优记忆污染、膨胀与多项目隔离5.1 记忆污染把一次性信息当成长期事实我遇到的最大的坑是记忆污染。有一次我在调试一个临时问题时说“这个环境变量先设成 test等会再改回来”Claude 确实照做了但 claude-mem 的 digest 把“环境变量设置为 test”当作一条项目约定记了下来。之后每次会话Claude 都默认环境变量是 test导致我手动改回 production 之后它还反复试图改回去。这个问题的根因在于摘要模型很难区分“一次性操作”和“长期约定”。我的应对方法是两条对话中尽量把长期约定的表述说得明确比如“记住以后环境变量统一走 .env.production”定期直接打开 CLAUDE.md把记忆区块里明显是垃圾的内容删掉claude-mem 把记忆暴露成可编辑的 markdown在这里就是救命设计。我几乎每周都会花几分钟把记忆文件从头到尾读一遍删掉过期条目保留真正有价值的部分。这个动作本身也是对自己项目管理的一次复盘。5.2 记忆膨胀控制注入体积用了一两周之后项目记忆会越来越大。Claude 每次会话都要读一遍全部记忆如果记了几百行就算上下文装得下也会稀释重点信息——它容易把重要的约定和无关紧要的细节一视同仁。我的调优经验是把记忆文件控制在 30 到 50 行以内比较舒服。超过这个量我就开始做“归档”把已经稳定、不太会变的约定留在 CLAUDE.md把那些只有特定场景才需要的细节移到项目文档里在需要时再让 Claude 去读具体文件。claude-mem 在后续版本里有没有记忆截断或优先级设置建议直接翻 README 的配置项。如果找不到相关配置用“定期手工清理”这种土办法也能达到差不多的效果。重点是不要让记忆文件变成一个只增不减的垃圾场。5.3 多项目工作区隔离和清理如果你像我一样同时在好几个项目里装了 claude-mem要特别注意记忆隔离。有一次我在一个 client 项目开会话却让它去参考另一个 server 项目的接口约定结果 digest 把 server 项目的技术栈信息写进了 client 项目的记忆。幸好我检查了 CLAUDE.md不然它后续会一直拿后端项目的约定来指导前端项目。预防办法很简单确认每个项目装完后CLAUDE.md 里的记忆区块只包含本项目内容。如果真的混了直接删掉对应行即可。.claude-mem目录如果不需要也可以整个删除后重新 install 初始化不会影响 Claude Code 本体。还有一个小细节记得把.claude-mem/加进项目的.gitignore。快照和中间产物没必要提交到仓库多一个人就多一份混乱而且如果团队其他人也跑 claude-mem每个人的快照会互相覆盖造成噪音。5.4 团队协作时的注意事项claude-mem 目前在我看来更偏向个人效率工具团队共用时容易出问题。最典型的是两个人的项目约定可能不一样一个人说“接口用 REST”另一个人说“接口用 GraphQL”双方都会往 CLAUDE.md 写记忆互相打架。如果团队要用我建议把 CLAUDE.md 纳入代码评审范围。因为 Claude Code 本身就会读取项目根的 CLAUDE.md这个文件本来就是项目资产团队内部应该统一维护。claude-mem 的自动写入相当于“AI 也在参与这个文件的编辑”那就更需要人类成员明确边界哪些内容允许自动写哪些必须人工审批。我的做法是保留一个“全局偏好区”由个人维护项目共享区只允许写经过 review 的稳定约定。5.5 卸载和重置的正确姿势用了几天觉得不合适或者某个项目的记忆已经彻底乱了想卸掉也很简单。我记得官方提供的命令是claude-mem uninstall它会移除之前写入的 hook 配置但不会主动删掉 CLAUDE.md 里的记忆区块和.claude-mem/目录。如果你想完全清干净手动删掉这两处即可项目根目录 CLAUDE.md 里由 claude-mem 自动维护的区块.claude-mem/目录这个顺序很重要先 uninstall 再手动清理否则直接删目录的话settings.json 里可能还留着失效的 hook 配置下次启动 Claude Code 会报错。6. 最后分享一点我的实际体会跑完这一整套流程我对 claude-mem 的定位有了更清晰的认识。它不是给 Claude Code 增加什么神秘能力而是把“对话中自然产生的项目知识”转化为“文件系统里可维护的项目资产”。这个思路我觉得比那些只做对话记忆的工具可靠得多——因为文件是可读、可改、可评审的出了问题你不会被蒙在鼓里。我现在已经把它纳入自己的日常工具链新项目开工第一步就是执行安装命令之后每一两天花两三分钟检查记忆文件是否健康。它当然不完美摘要模型的判断会出错记忆膨胀也需要人工介入但在跨会话一致性这个痛点面前这些代价我觉得是值得的。如果你也被 Claude Code 的“金鱼记忆”折腾过可以按这篇文章的路径自己试一次。强烈建议从一个小项目开始用一用然后亲手打开 CLAUDE.md看看它到底记了什么东西。