如果你最近也在用 Claude Code 写代码,大概率撞见过同一个场景:昨天晚上还跟它聊得热火朝天,敲定了数据库选型、约定了 API 命名规范,今天早上新开一个终端会话,想让 Claude 接着昨天的进度改代码,它却一脸茫然地看着你,仿佛你们根本不认识。这个"跨会话失忆"问题在社区里被讨论了很久,直到我翻到 GitHub 上的开源项目claude-mem,才算真正找到顺手的解决方案。简单说,claude-mem 就是给 Claude Code 装上一套"自动更新的项目备忘录",它会在每次会话结束后悄悄把值得记住的内容提炼出来,存进本地 SQLite,下次开工时再把相关记忆回灌到 Claude 的上下文里。这篇文章我会把它的原理、部署步骤、实测表现和踩坑经验完整写一遍,适合正在用 Claude Code 做真实项目、且被"重新解释一遍上下文"折磨过的开发者。
1. 一场对话结束,它就把一切忘光了:Claude Code 的记忆空白
1.1 上下文窗口不是记忆,只是一张"临时工作台"
很多人会把上下文窗口误解成"模型记住了我们的项目",其实它更像一张施工队每天早上临时搭起来的工作台:今晚收工,所有图纸、材料、未完成的部分全部清走。Claude Code 的上下文窗口也是这样,无论它昨天跟你讨论了多少个文件、改了多少处逻辑,只要会话结束,那些对话内容在下一场会话里就只剩下"系统提示词 + 项目里的静态文件"可以依赖。
我自己遇到过一个很典型的案例:有一天下午让 Claude Code 把项目的存储层从 JSON 文件改成 SQLite,过程中定下了表结构、迁移策略、ORM 选择,还顺手调整了三个模块的目录结构。第二天上午我新开一个会话,想让它接着完成剩余接口的适配,结果它连"我们已经决定用 SQLite"这个基本前提都毫不知情,直接建议我用原来的 JSON 方案改。那一刻我是真有点崩溃的——不是模型不聪明,而是它真的没有任何"昨天发生过什么"的痕迹。
1.2 "手写记忆文件"和"重贴前情提要"为什么撑不过三个月
社区里其实早就有人意识到这个问题,所以普遍的做法有两类。
第一类是手动维护 CLAUDE.md 文件,把项目约定和重要决策写进去,让 Claude 每次启动时自动读取。这个方案对稳定约定很有效,比如"本项目使用 TypeScript""测试文件放 tests/ 目录",但它要求你自己记得去更新,而且很容易遗漏那些"临时拍板但后来影响深远"的决策。很多人新鲜劲儿一过,就根本想不起来维护了。
第二类是每次开会话时手动粘贴一段前情提要,把昨天的结论、当前进度、下一步计划压缩成文字扔给 Claude。这个方案的缺点是显而易见的:费时、费 token,而且你写出来的描述往往不够全面,甚至会带偏 Claude 的理解。我自己试过几次之后得出的结论是:手工记忆只能支撑一个月的热情,三个月后基本弃用。
1.3 claude-mem 到底补的是哪块空缺
claude-mem 想解决的不是"让 Claude 记住所有对话",而是"让 Claude 记住值得记住的部分,并且不需要你手动做任何事"。它的工作方式可以概括成一句话:监听会话结束→提炼记忆→存进本地数据库→下次会话开始时自动注入。
它本质上是一个围绕 Claude Code 的外挂组件,利用 Claude Code 的日志和 Hook 机制完成记忆的"捕获-提炼-存储-回放"。因为所有记忆都存在本地 SQLite 文件里,不依赖云端服务,也不用担心第三方看到你的代码讨论内容。对长期用 Claude Code 写项目的人来说,它补上的是最痛的那一环:让 AI 协作从"每次都重新开始"变成"有一定连续性"。
2. 从会话日志到长期记忆:claude-mem 的工作链路拆解
2.1 抓取:监听会话日志和 Hook 事件,而不是暴力录屏
理解 claude-mem 的第一步,是先知道它从哪里拿数据。Claude Code 默认会把每次会话的完整对话记录写入本地文件,路径一般在用户目录的~/.claude/projects/下,按项目路径哈希成不同子目录,里面存着一串 JSONL 格式的会话日志。也就是说,你和 Claude 的每一轮问答、每一次工具调用的输入输出,其实都已经以结构化文本的形式躺在你硬盘上了。
claude-mem 做的事情之一,就是等一个会话结束时去读这些 JSONL 文件。更精细的版本会利用 Claude Code 的 Hook 机制,尤其是Stop事件和UserPromptSubmit事件:前者在 Claude 每次回复结束时触发,适合做"记忆提炼";后者在用户输入下一次提示词之前触发,适合做"记忆注入"。通过 Hook 的方式,claude-mem 能在不打断正常对话的前提下,在合适的时间点做该做的事。
早期版本的 claude-mem 还用过"包装器"方案,也就是用一个脚本包住claude命令,在后台进程结束之后统一解析日志。这种方式在实现上更朴素,但遇到长会话或异常退出时不够稳定,后来逐渐被 Hook 方案取代。
2.2 提炼:把对白变成"值得记住的事情"
拿到原始对话记录之后,下一个问题也很关键:到底该记住什么?如果把整个会话全量存下来,下次注入时上下文会被撑爆,而且里面 90% 的内容其实无关紧要。claude-mem 的思路是提炼(Summarization),用一次额外的模型调用对会话内容做压缩,提取出以下几类信息:
- 用户偏好:比如"开发者的 TS 代码风格偏好是 2 空格缩进""用户明确表示不喜欢在组件里写内联样式"。
- 项目决策:比如"数据库选型确定为 SQLite""模块划分按 feature 而不是按 layer""支付模块暂时不做,放到二期"。
- 任务进度:比如"登录接口已完成,正在重构订单状态机""缓存层还有三个 TODO 没处理"。
- 坑和教训:比如"在 docker-compose 里不要用 localhost 访问宿主机,要走 host.docker.internal""不要用
rm -rf dist清理,因为 dist 是符号链接指向共享目录"。
提炼的动作不是简单地截取几段原文,而是让语言模型以"记忆档案"的形式重写这些信息,让它们变成独立可检索的短句。这样做的好处是,下次注入时 Claude 看到的是高度浓缩的结论,而不是一大段原始对白,因此节省 token,也更容易被 Claude 直接利用。
2.3 存储:按项目归类的本地记忆库
提炼出来的记忆条目,最终会落到一个 SQLite 数据库里。公共实现通常会有类似这样的几个核心概念:
- Project(项目):对应一个项目目录路径,是所有记忆的基本归属边界;
- Session(会话):记录每次对话的来源和发生时间,方便追溯;
- Memory(记忆条目):一条条提炼出来的结论,会关联到项目、标签和时间戳;
- Tag(标签):用于对记忆做分类和筛选,比如"决策""偏好""进度""坑"。
这个设计的巧妙之处在于"按项目隔离"。你在 A 项目里积累的记忆不会跑到 B 项目去,因为注入时 claude-mem 会先识别当前 Claude Code 的工作目录,然后只检索该项目的记忆。这样多项目并行开发时,记忆不会互相污染。
所有数据都保存在本地,权限只归属于本机用户。从隐私角度讲,它比把对话内容发给第三方要安全不少,但这不意味着可以往里面写密钥和口令,后面我会专门讲这个边界。
2.4 注入:下一次对话开始时,悄悄把回忆放到桌面上
记忆存的目的是为了让 Claude "想起来"。当你在项目目录里重新启动 Claude Code 并输入第一句话时,claude-mem 会在UserPromptSubmit阶段,根据当前的项目路径和输入内容,从数据库里检索相关度最高的若干条记忆,然后把它们拼成一段文本,插入到 Claude 可见的上下文里。
这段文本通常会被设计成类似"以下是这个项目的历史记忆,请优先参考:……"的结构,让 Claude 一开场就拥有前情提要。它与 CLAUDE.md 的最大区别在于:CLAUDE.md 是静态文件,靠人手动维护;claude-mem 的记忆是动态生成的,每次注入的条目会随着项目的进展不断变化,也会按相关性筛选,不会一股脑全塞进去。
2.5 项目形态的快速进化:从脚本到插件与 MCP
claude-mem 这个项目本身也在快速迭代。最早是偏脚本化的实现,后来社区里出现了 Rust 重写版本(claude-mem-rs),性能更好,安装也更方便。再往后,随着 Claude Code 引入插件(Plugin)和 Agent Skills 机制,claude-mem 也提供了插件形态,可以直接通过插件市场安装,并支持"思维工作流"、"工作流状态文件"和"手写记忆文件"等更丰富的玩法。
在写这篇文章的时候,我建议你去 GitHub 上看一眼当前仓库的 README,因为它的安装方式和命令形态每个版本都可能微调。下面第四章我会给出普遍适用的部署路径,但如果你某一部和你本地的版本对不上,优先以官方 README 的说明为准。
3. 本地部署与首次配置:从一条命令到第一条记忆
3.1 安装前的环境检查
在动手之前,先把基础环境核对一遍,能省掉后面一大半的排错时间:
- Claude Code 已安装并能正常使用。在终端里运行
claude --version能看到版本号才行。如果这一步都过不了,claude-mem 装上也没意义。 - Node.js 20+ 或 Rust 环境,取决于你用的是 Python/Node 版还是 Rust 重写版。大部分发行版通过
npm安装,所以一个可用的 npm 环境是底线。 - 操作系统:macOS 和 Linux 都是首选,Windows 上建议用 WSL,因为在 WSL 里跑终端代理和 Hook 更省心。
- 终端环境变量:确保
HOME或用户目录下~/.claude目录存在,claude-mem 要读写里面的配置和日志。
3.2 安装与初始化步骤
以目前常见的安装方式为例,流程大致如下:
- 全局安装 claude-mem 本体:
npm install -g claude-mem- 运行初始化命令,让它自动检测你的 Claude Code 配置并注册 Hook:
claude-mem setup这个setup命令通常会做两件事:备份原有的 Claude Code 配置文件(比如~/.claude.json或 settings.json),然后把 claude-mem 需要的 Hook 配置合并进去。因为要改配置文件,建议执行前手动再备份一次,防止意外覆盖。
- 验证安装:
claude-mem --version输出版本号就说明安装成功。有些版本还提供claude-mem doctor或类似命令,用来检查环境是否完整,有就顺手跑一遍。
3.3 跑通第一条记忆:二十分钟内的完整演示
安装完成后,最重要的不是去读文档,而是立刻验证"记忆"到底有没有生效。我建议你跟着这个最小流程走一遍:
第一步,进入一个真实项目目录,启动 Claude Code,然后给它一个含有明确决策点的任务,例如:"把当前项目的数据读取逻辑改成基于 SQLite 实现,并且把新增的连接管理策略写进注释里。"
第二步,正常和 Claude 对话几轮直到任务完成,然后直接退出会话。如果 claude-mem 配置正常,它会在会话结束阶段自动解析日志并提炼记忆。这时候你可以跑一条命令看看有没有抓取到内容:
claude-mem list如果列表里有条目,说明捕获成功。
第三步,重新进入同一个项目目录,再启动一个全新的 Claude Code 会话,然后问一句:"我们当前项目是用什么方案做数据存储的?"如果 claude-mem 注入了昨天的记忆,Claude 会直接给出 SQLite 这个答案,并且还能顺带说出连接管理策略的细节。
整个流程其实就是"上一次会话留下结论,下一次会话直接引用"。第一次跑通这个闭环之后,你基本就能理解 claude-mem 的全部价值了。
3.4 常用的管理命令
日常使用中,你不太会频繁操作 claude-mem,但下面这几个命令属于"知道就不慌"的类型。注意:不同版本命令形态可能略有差异,最稳的做法是随时用claude-mem --help查看本机支持的命令。
| 命令 | 作用 | 典型使用场景 |
|---|---|---|
claude-mem list | 列出当前项目或全局的记忆条目 | 看看项目积累了多少记忆,大概评估注入量 |
claude-mem view <id> | 查看单条记忆的完整内容 | 确认某条记忆是否存在偏差 |
claude-mem search <关键词> | 按关键词搜索记忆 | 想确认某条历史决策是否被记录 |
claude-mem stats | 统计记忆条数、最近捕获时间等 | 健康检查,判断记忆体系是否正常运转 |
claude-mem delete <id> | 删除指定记忆条目 | 发现某条记忆错误或过时,手动清理 |
claude-mem setup | 初始化配置,注册 Hook | 首次安装或升级后重新配置 |
另外,有些版本支持通过环境变量指定记忆库位置,比如把数据目录挪到一个统一的空间里,方便多台机器同步或者纳入备份。如果你有这类需求,去 README 里搜环境变量相关段落比在 UI 里瞎翻要快得多。
4. 带着昨天的记忆开工:实测场景与量化观察
4.1 一个跨会话协作的实测脚本
为了验证 claude-mem 的实际效果,我专门搭了一个小型 Node.js 项目做测场景,并把整个流程记录下来。项目内容很简单:一个基于 Express 的 API 服务,带三个路由、两个中间件、一个简单的 JSON 文件存储层。
第一天我让 Claude Code 做以下几件事:
- 把 API 的数据存储从 JSON 文件改为 SQLite;
- 把所有路由文件的命名改成
*.routes.js形式; - 在中间件里统一加了
request-id生成逻辑,并要求日志里带reqId字段; - 明确要求"以后不要用
||处理缺失值,统一用??"。
这个会话大概持续了四十分钟,涉及十几个文件的修改。我特意没有写任何 CLAUDE.md,完全靠 claude-mem 自动捕获。会话结束后,我用claude-mem list查看记忆条目,能看到类似这样的记录:
- "项目存储层已从 JSON 迁移到 SQLite,使用 better-sqlite3。"
- "路由文件采用模块名 + .routes.js 的命名约定。"
- "用户偏好使用空值合并运算符 ??,避免使用 ||。"
- "中间件已统一注入 request-id,日志输出需包含 reqId。"
4.2 第二天新会话里的实际表现
第二天我直接新开一个会话,第一句是:"帮我把订单路由里的存储逻辑也改成 SQLite 的写法,和现有风格保持一致。"
没有 claude-mem 的情况下,Claude 大概率会问"现有风格是什么?数据库现在用的什么?"或者直接提出一套全新方案。但接入了 claude-mem 之后,它的第一轮回答就直接引用了 SQLite 和 better-sqlite3,并且主动按*.routes.js的命名规则去处理新文件,连reqId传递这种细节都延续了。
实际体感上,这已经接近"带人接手上一任开发者的工作"了。唯一值得留意的是,如果我第一天的会话里存在错误结论,第二天注入后 Claude 会照单全收。所以关键记忆需要定期抽查,特别是那些"决策型"的条目。
4.3 token 开销与首包延迟:付出多少,拿回多少
很多人在意 claude-mem 会不会每次对话都拖慢速度、多烧 token。从我实测的结果看,这个成本是可控的,但需要主动管理。
在记忆条数较少的时候(比如 10 条以内),注入内容可能只有 1~2k token。首条消息的延迟会从 1 秒左右增加到 2~3 秒,因为模型要多读一段历史记忆。但在后续长对话里,这个成本往往能赚回来:Claude 不再需要反复追问项目背景,也不会因为缺乏上下文而提出偏离方向的方案,整体往返次数明显减少。
我用一个粗略模型来评估收益:如果原本每次会话要花 5 轮对话来解释背景和方向,现在只需要 2 轮,那么 claude-mem 注入的 token 成本早就被省下的轮次覆盖了。真正需要警惕的是几个月之后,记忆条目堆积到几百上千条,注入量也跟着膨胀,这种情况下就要做治理了。
4.4 多项目并行的记忆隔离表现
我还分别开了两个项目目录做对照测试:一个project-alpha,一个project-beta。每个项目里各跑了一个会话,让它们分别形成不同的记忆。
第二天我同时在两个目录里打开 Claude Code,分别问"我们项目当前的存储方案是什么",两边都能给出自己项目内部的正确答案,没有出现串记忆的问题。这说明按项目路径聚合记忆的方案在单机多项目场景下是可靠的。
但有一个隐藏的坑:项目的绝对路径变了,记忆可能就找不到了。比如你把项目目录从/code/app改名为/code/app-new,或者把仓库 clone 到另一个目录,claude-mem 可能会把它当成一个全新项目。这类情况不算 bug,但确实会让人产生"记忆丢失"的错觉,迁移项目时最好手动检查一下记忆库的归属关系。
5. 进阶配置:自定义注入策略、MCP 集成与记忆治理
5.1 控制注入量:别让记忆撑爆上下文
claude-mem 的默认行为通常是"检索相关度最高的若干条记忆注入",但相关度的算法并不一定完美。项目跑久了,你会发现有些记忆看似相关、其实陈旧过时,注入进去反而会干扰 Claude 的判断。
我的建议是主动做两层控制。第一层,在配置里限制单次注入的记忆条数上限,比如 20 条或 30 条,超过的部分宁可不注入,也不要全扔进去。第二层,定期检查claude-mem list,把那些已经固化到代码里、不再需要提醒的记忆删除。比如"存储层已迁移到 SQLite"这条,一旦代码里的 import 和配置都写清楚了,Claude 读代码就能知道,历史记忆的增量价值就不大了。
5.2 自定义记忆的提取规则和注入模板
claude-mem 的提炼过程本质上是调模型做一次结构化 summarization,所以它允许使用者干预"该记什么"和"怎么表述"。某些版本支持通过配置文件或插件,覆盖默认的提炼提示词,你可以根据自己的使用习惯,让记忆更偏向某个方向。
比如你的团队经常讨论部署流程,可以让提炼提示词强调"记录环境变量变更、部署命令、运维教训";如果你更关心代码风格,可以让它多提取"命名规则、缩进、组件组织方式"。注入模板也可以调整,比如让记忆以"Project Notes:"的格式放在上下文中,甚至可以在记忆前加一行"这些是历史结论,未经验证的部分请谨慎参考",减少对 Claude 的误导。
5.3 把记忆库通过 MCP 开放给其他工具
claude-mem 的一个比较高级的玩法,是把它作为 MCP Server 暴露出来。MCP 是 Claude Code 支持的一种工具接入协议,你可以把 claude-mem 的记忆库变成一个可查询的工具,让 Claude 在对话过程中直接调用检索接口,而不只是在启动时被动注入记忆。
这样做的好处是,Claude 可以根据当前问题临时决定"要不要翻一下历史记录",而不是每次把所有相关记忆都预加载进来。也就是说,启动时光靠少量精选记忆维持连续性,深度检索按需触发,token 成本会更低。如果你的版本支持 MCP 模式,我强烈建议试一试,配置完成后claude-mem就可以作为其他 MCP 客户端的普通工具出现在工具列表里,类似一个本地知识库。
5.4 与 CLAUDE.md 组成"静态约定 + 动态记忆"的双层结构
我现在的项目记忆方案是双层的:
- CLAUDE.md 只放稳定约定:语言栈、目录结构、统一的代码规范、测试命令等。这些东西几个月甚至一年都不会变,手动维护成本低,放在静态文件里最合适。
- claude-mem 放动态信息:项目进度、临时决策、偏好演变、坑和教训。这些信息变化快,不适合手写维护,交给自动提炼最合适。
两层之间可以有个联动习惯:每隔一到两周,把 claude-mem 里的重要决策整理进 CLAUDE.md,形成"静态固化"。这样做既能缓解记忆库膨胀,也能让项目的入门文档始终反映最新共识,对不常使用 claude-mem 的团队成员也更友好。
5.5 记忆治理:清理、去重与导出
长期使用的另一个问题是重复记忆。同一个决策如果被多次会话反复提炼,记忆库里会出现语义几乎一样的条目,注入时会浪费 token。我一般会每个月清理一次,方法很简单:用搜索命令筛出关键词重复的条目,逐条delete掉旧版本保留最新版。
如果项目要交接或者换机器,还要考虑记忆的迁移问题。SQLite 库本身就是一个单文件,直接拷贝或纳入备份即可,比想象中轻量。不过迁移时要注意,如果目标机器没有安装 claude-mem,光拷库文件是不会自动注入的,需要重新安装并 setup 一遍。
6. 经验与边界:使用 claude-mem 必须守住的几条线
6.1 敏感信息:记忆库不是保险柜
这是我的第一条警告。虽然 claude-mem 只保存提炼后的记忆,而不是完整的对话原文,但提炼过程本身可能把关键片段保留下来,比如一个极长且唯一的 API Key、一段私有代码的独特命名,或者一句包含内部架构细节的表述。任何写进记忆库的内容,都等于落盘成永久文本,比对话日志更难清理。
所以在使用 Claude Code 的时候,我就养成了一开始就明确告知的习惯:让 Claude 不要输出和保存密钥、密码、云厂商访问凭证。如果某条记忆已经写入且看起来敏感,用claude-mem search找到它并delete掉。别把 claude-mem 当成保管机密的保险柜,它只是一个便利的记忆层,安全边界还是要靠自己的纪律。
6.2 上下文膨胀是温水煮青蛙
对于持续几个月的大型项目,记忆库里的条目可能是几百上千条。如果注入策略太贪婪,每次新会话都塞进 50 条记忆,很快你的对话体验就会变成"Claude 花了很大力气读历史,却没精力干正事"。更微妙的是,这种劣化是渐进的,你不会立刻意识到是记忆过量,只会觉得模型越来越"啰嗦"。
我的处理方式是定期看claude-mem stats,如果记忆条数膨胀得太快,就提高提炼阈值或缩短保存期限。也可以把旧记忆归档到手工维护的文档里,避免所有记忆都挤在注入路径上。
6.3 并发会话与项目路径的坑
我试过在同一个项目目录下同时开两个 Claude Code 终端窗口,一边让 Claude A 修改路由,一边让 Claude B 重构数据层。理论上它们应该各干各的,但在会话结束时,两个会话的日志可能因为写入时机问题,导致 claude-mem 在提炼时把不完整的上下文当成了结论。
这不是频繁出现的故障,但确实影响记忆的准确性。我现在的做法是:同一个项目,同一时间只开一个主会话做"决策型工作",如果需要并行处理,就明确让 Claude 在关键结论里加上足够的上下文前缀,确保提炼出来的记忆仍然正确。
6.4 升级 Claude Code 之前,先备份记忆库
Claude Code 更新很频繁,Hook 机制、配置格式、会话日志结构都可能变化。claude-mem 的某个版本可能依赖特定 Hook 名称,或者依赖某种日志字段,一旦 Claude Code 升版,记忆捕获可能静默失效——也就是你完全察觉不到"记忆断供",直到某天发现第二天新会话里什么也想不起来。
所以在升级 Claude Code 或者 claude-mem 之前,我都会做两件事:备份配置文件,然后把 SQLite 数据库文件复制一份到安全目录。升级后立刻验证一遍"前一天会话的结论,新会话能不能说出来",确认链路是通的再继续正式开工。这个检查只需要两分钟,却能避免工作到一半发现记忆断层的尴尬。
文章写到这里,claude-mem 的价值和边界应该已经比较完整了。我个人实际用下来的最大感受是:它把 Claude Code 从一件"用完即走的高级交互工具",变成了一个真正能跨天跟进项目的开发搭子——前提是你愿意花一点时间管理它的记忆质量。最后再分享一个小习惯:每天开工前,花 30 秒看一眼claude-mem stats,确认最近几条记忆确实来自昨天的关键决策;收工前顺手删掉那些明显过时的旧条目。这样下来,你的记忆库会始终保持干净,而 Claude 在每一个新早晨,都能清楚地想起你们昨晚聊到的那件事。