claude-mem:解决Claude Code上下文丢失问题的持久记忆工具

发布时间:2026/10/28 3:14:37
claude-mem:解决Claude Code上下文丢失问题的持久记忆工具

如果你重度使用 Claude Code 做开发,大概率经历过这个场景:上午刚让 Claude 搭好项目的目录结构和 API 约定,下午开个新会话让它继续写某个模块,结果它连项目的技术栈都要重新问一遍。你不得不把上午说过的约束、偏好、踩过的坑重新复制粘贴一次。这种"金鱼记忆"在长周期项目里尤其致命——一次重构动辄跨好几个会话,每天花在重复上下文上的时间比写代码还多。

claude-mem 就是冲着这个痛点来的。它是一个开源的命令行工具,做的事情说白了就一件:把 Claude Code 每次会话产生的对话记录吃进去,加工成结构化的长期记忆,存到本地,下次会话需要的时候再自动喂回给 Claude。它不改变 Claude 本身,而是在 Claude Code 外面套了一层"长期记忆层"。这篇文章我会从实际使用者的角度,把它的架构原理、安装配置、日常命令、MCP 集成以及我踩过的坑完整过一遍,适合所有被上下文丢失折磨的 Claude Code 重度用户参考。

1. 先说说我为什么需要 claude-mem

1.1 同一个问题解释第三遍的崩溃

我的项目是一个中型微服务仓库,十几个服务模块,每个模块有自己的技术选型和历史包袱。用 Claude Code 之前,我最痛苦的不是它写代码慢,而是它"记性太差"。

举个例子。项目里有条不成文的规定:所有数据库访问层必须走统一的 Repository 基类,不允许直接写原生 SQL。这个约定我在会话 A 里明确交代过,Claude 也执行得很好。可一旦开新会话 B,它就像失忆一样,又开始在 service 层里写 QueryBuilder。我质问它,它一脸无辜地说"当前会话没有这个上下文"。

你没法怪它——Claude 的上下文窗口是会话级的,窗口一关,记忆归零。这不是模型能力问题,是架构设计如此。会话结束后的所有内容,对下一个会话来说都等于不存在。

更烦的是,这个问题会随项目规模放大。小项目你还能靠复制粘贴上下文凑合,项目一大,光是把"项目背景、技术约束、当前进度、待办事项"完整描述一遍就得好几百行,而且每次描述还可能不一致、有遗漏。我试过用项目文档(CLAUDE.md)来缓解,但文档是静态的,覆盖不了会话中实时产生的决策和踩坑记录。

1.2 从"会话级记忆"到"持久记忆"的跨越

Claude Code 本身其实提供了一些记忆机制,比如 CLAUDE.md 文件、自定义指令等,但这些都是"人工维护"的。你得自己把重要信息摘出来写进文件,Claude 不会自动帮你沉淀。真实的开发过程中,大量有价值的上下文是散落在对话里的:一次调试中发现的根因、一个你明确否绝掉的方案、一段客户对需求的补充描述——这些几乎不可能被同步到文档里。

claude-mem 的思路完全不同:它不要求你主动记录,而是自动监控 Claude Code 的会话文件,把每段对话的原始记录(JSONL 格式的 transcript)读走,经过分析和提炼后变成一条条结构化的记忆存储下来。下次会话需要时,它再把相关记忆作为额外上下文注入给 Claude。

换句话说,它把"记忆"这件事从"用户的责任"变成了"工具的责任"。我不用再费心维护上下文文档,只需要在关键时刻问一下 claude-mem 还记得什么,或者在 MCP 配置开启后,让 Claude 自己想起来。

2. claude-mem 的核心设计:它凭什么能记住

2.1 三层存储:SQLite + ChromaDB + 文件系统

我用 claude-mem 之后第一件事就是扒它的存储目录,想搞清楚它把记忆放哪了。默认情况下,所有数据落在~/.claude-mem/目录下,里面是典型的"三层存储"结构:

存储层技术选型职责
元数据层SQLite记录会话 ID、时间戳、文件路径、处理状态等结构化信息
向量层ChromaDB(矢量数据库)存放对话内容的向量化表示,用于语义相似度检索
原始文件层文件系统JSONL 格式的会话转储文件,作为不可变的事实来源

为什么分三层而不是直接全塞进一个数据库?因为三种数据的访问模式完全不同。SQLite 适合精确查询,比如"昨天处理过哪些会话""哪个会话涉及了 payment 服务",这类操作需要的是关系型查询能力;向量层负责模糊匹配,用来回答"之前有没有讨论过类似问题"这种语义查询;原始文件层则承担审计和回溯的功能——如果加工出来的记忆有偏差,我可以直接翻原始 transcript 核实。

这个分层思路其实很像人的记忆机制:SQLite 是"事实清单",ChromaDB 是"联想网络",原始文件是"潜意识"。三层各司其职,才保证了既查得准、又想得起、还不失真。

2.2 记忆加工的流水线

每次 Claude Code 会话结束,生成的 transcript 文件会落到~/.claude/projects/目录。claude-mem 的加工流水线就是从扫描这个目录开始的,整个过程分四个阶段:

第一,监听与捕获。claude-mem 可以以守护进程(daemon)方式运行,持续监听新旧会话文件;也可以手动触发。它通过 SQLite 里记录的"已处理文件指纹"来避免重复加工,只处理新增或变更的 transcript。

第二,解析与分段。JSONL 文件里每行是一条消息记录,包含角色(user/assistant)、内容、时间戳等字段。claude-mem 会把长对话按照语义边界切成多个记忆块(chunk),而不是整段塞进去。分段的好处是粒度更细,检索时命中精度更高。

第三,提炼与结构化。这是最核心的一步:原始对话是口语化的、充满噪音的,不能直接当记忆用。claude-mem 会调用大模型对每个记忆块做一次"提炼",提取出关键决策、问题结论、用户偏好等有价值的信息,生成简洁的记忆摘要。这个过程会消耗一定的 API 额度,需要提前有心理准备。

第四,向量化与落库。提炼后的记忆会被送入嵌入模型生成向量,存进 ChromaDB,同时把结构化信息写入 SQLite。落库之后,一条记忆就正式"可被召回"了。

2.3 召回机制:从被动翻历史到主动喂上下文

记忆存进去只是第一步,关键是怎么在合适的时候把记忆拿出来。claude-mem 的召回机制分主动和被动两种。

被动召回是我用得最多的场景:在 Claude Code 会话里,我直接输入claude-mem search "支付模块之前定的幂等方案",它会在本地向量库里做语义检索,把所有相关记忆条目和来源会话返回给我。这个命令本质上是一个"给 AI 用的搜索引擎"。

主动召回则发生在 MCP(Model Context Protocol)集成之后。配置好 MCP 服务,Claude 在对话过程中如果判断"这个问题可能和历史记忆相关",会自动调用 claude-mem 暴露的 MCP 工具去查询记忆,把结果作为上下文的一部分。这个过程不需要我干预,Claude 自己就知道"我该回忆一下了"。

这两种机制合在一起,覆盖了两种典型需求:我有明确目标时用被动搜索,我没有明确目标但 Claude 需要背景知识时用主动召回。实际用下来,主动召回对我这种懒人尤其有价值——它把记忆变活了,而不是让我自己去翻。

3. 从零配置:安装与接入 Claude Code

3.1 安装方式对比

claude-mem 是 Python 写的,安装方式很常规,支持 pip、pipx 和 uv。我个人的建议是直接用uv,原因很简单:uv 的依赖解析速度快,而且能自动隔离环境,不会污染系统的 Python。

# 方式一:推荐,uv 管理全局 CLI 工具 uv tool install claude-mem # 方式二:pipx 隔离安装 pipx install claude-mem # 方式三:传统 pip(不推荐,除非你清楚自己在做什么) pip install claude-mem

装完之后验证一下:

claude-mem --version claude-mem --help

如果能正常输出版本号和帮助信息,说明安装成功。需要注意的一点:claude-mem 的版本迭代很快,建议隔一段时间就uv tool upgrade claude-mem一次,新版本经常会优化解析逻辑、增加新的 MCP 工具。

3.2 配置文件要点

首次运行会生成配置文件,默认路径是~/.claude-mem/config.yml。我调整过几次之后,目前的配置长这样:

# claude-mem 配置示例 storage_dir: ~/.claude-mem/ streaming: true mcp_server: enabled: true port: 8090 daemon: enabled: true interval: 300 processing: enabled: true # 会话文件扫描范围,支持通配符 project_patterns: - ~/.claude/projects/**/*.jsonl git_integration: enabled: true

说几个我踩过坑才理解的关键配置项:

mcp_server.enabled决定这个工具是否对外提供 MCP 服务。如果你希望 Claude 能主动调用记忆,这必须设为true。daemon.enabled控制是否以后台进程方式持续监听会话文件变化,如果关掉,就得手动跑命令去触发加工。streaming影响记忆加工时的响应方式,开着的用户体验会更顺滑。

这里提醒一句:配置改完要重启 claude-mem 的 daemon 进程才生效。我第一次改完配置没重启,白等了好几分钟,以为出 bug 了。

3.3 接入 MCP 的完整步骤

接入 MCP 是让 claude-mem 发挥全部价值的关键一环。MCP 是 Anthropic 推出的模型上下文协议,本质上是给 Claude 提供了一套"调用外部工具"的标准接口。claude-mem 实现了一个 MCP server,对外暴露记忆相关的工具函数,Claude 在对话中按需调用。

在 Claude Code 里接入 claude-mem 的 MCP 服务,我用的命令是:

# 基于 stdio 模式注册 claude-mem 为 MCP 服务 claude mcp add claude-mem -- claude-mem mcp

执行完可以验证注册状态:

claude mcp list

如果列表里有claude-mem条目,说明注册成功。之后启动 Claude Code,Claude 的工具列表里就会多出记忆相关的工具。你可以直接问它:"你现在有哪些记忆工具可以用?"它会列出可用的记忆查询和召回函数。

另一种接入方式是通过 Claude Code 的插件系统(Slash Command Plugin),安装后可以用/memory这类斜杠命令手动触发记忆操作。两者不冲突,我目前是 MCP 为主、插件为辅。

4. 日常使用手册:这些命令才是主力

4.1 状态检查与存储目录

接入完成之后,第一件事永远是看它到底干活了没有。我习惯在每个工作日开始先跑一次状态检查:

claude-mem status

这个命令会输出当前数据存储量、已处理会话数、MCP 状态、守护进程状态等信息。看到会话数在增长,就说明 transcript 的加工流水线是通的。

再配合看存储目录:

ls -lh ~/.claude-mem/ du -sh ~/.claude-mem/

正常情况下你会看到chroma(向量库)、sqlite(元数据库)、logs(日志)等子目录。如果日志目录里报错频繁,先检查权限和路径配置——我最开始遇到过一次因为家目录路径里有中文导致扫描失败的怪问题,新版本已经修复了。

4.2 语义搜索实战

search命令是我日常用得最多的,它解决的是"我隐约记得聊过某件事,但忘了具体内容"的问题。

# 基础搜索 claude-mem search "订单超时重试机制的最终方案" # 限定返回条数 claude-mem search "为什么不用 RabbitMQ" --limit 5 # 按时间范围过滤 claude-mem search "数据库索引优化" --timeframe 7d

它搜的是向量相似度,不是关键词匹配。所以哪怕你记不清当时用的措辞,只要语义相近,就能搜出来。比如说你当时聊的是"接口幂等的处理方式",现在用"重复提交怎么防"去搜,一样能命中。

搜索结果会附带来源会话 ID 和时间戳,我一般会顺着会话 ID 去翻原始记录,确认这条记忆没有在提炼阶段丢失关键细节。这个过程建议养成习惯——记忆加工本质上是"压缩",压缩就有信息损耗,关键时刻还是要回到原文核实。

4.3 用户画像与 Git 记忆

claude-mem 有两个让我觉得"这工具懂我"的功能:用户画像(User Profiles)和 Git 记忆。

用户画像是我用过一段时间后自动产生的。它会从对话里提取我的偏好——比如"用户倾向于使用 PostgreSQL 而非 MySQL""用户要求所有代码必须包含类型注解"。这个画像会被持久化,并且在下一次会话的上下文构建中自动参与。说得玄一点,Claude 开始"知道我是谁"了。

Git 记忆则更硬核:它会把项目的 Git 提交历史纳入记忆体系,这样 Claude 就能理解代码库的演进脉络。比如我搜索"支付模块最近改动",它会结合.git历史和会话记忆给出更完整的回答。这一块要求项目本身在 Git 仓库里,且 claude-mem 的git_integration.enabled配置保持开启。

这两个功能让我最大的感受是:记忆不再是零散的"说过的话",而是开始形成"关于这个项目和这个人的知识体系"。当你连续用了一两周之后,新会话的 Claude 几乎不需要你重复背景介绍,它对你和项目的了解程度是"连续积累"的。

5. 进阶玩法:MCP 工具让 Claude 自己管记忆

5.1 MCP 工具清单

接上 MCP 之后,Claude 的工具列表里会多出一批记忆工具。我实际用下来主要就这几个:

工具名作用典型调用时机
recall主动召回相关记忆会话开始,Claude 发现需要项目背景时
query按语义查询记忆库对话中遇到不确定的历史决策
recall_notes召回带笔记属性的记忆需要查看维护记录、审查备注时
get_all_available_actions列出当前可用的记忆操作Claude 判断该用哪个工具时

关键点在于:这些工具是 Claude 自主决定调用的,不需要我手动触发。Claude 在对话中会做"我是否需要回忆历史"的判断——这就是 MCP 集成和命令行搜索的本质区别。

5.2 让 Claude 主动调用记忆

我一开始以为接上 MCP 就万事大吉,结果发现 Claude 并不是每次都主动去查记忆。它偶尔会在信息不完整时直接给出一个"合理猜测"的回答,而没有去调recall。

后来我调整了用法:在会话开头给 Claude 一句明确的提示,比如:

"项目背景和之前的决策请先调用 claude-mem 的相关工具获取,不要假设我知道历史。"

加上这句话之后,Claude 的主动召回频率明显提高。它会先查记忆,再开始作答。对我来说,这相当于白嫖了一个"元记忆指令"——不是把历史内容塞进上下文(那会爆窗口),而是教会它"去哪里找历史"。

如果想做更多定制,MCP 配置里还可以指定允许哪些工具、禁用哪些工具。我目前禁用了所有"写"类操作,只保留了查询和召回,防止 Claude 在对话中意外修改记忆库。

6. 踩坑记录与性能调优

6.1 存储膨胀与清理

第一个坑:存储膨胀。我用了一周左右,~/.claude-mem/目录已经超过 1GB。原因不难理解,向量库本来就占空间,再加上 SQLite 里冗余的会话记录和日志。

处理办法是定期清理。claude-mem 提供了prune相关命令,可以按时间或按条数清理旧记忆:

# 查看当前记忆条目数 claude-mem view --stats # 清理 30 天前的记忆 claude-mem prune --older-than 30d

这里有个拿捏点:prune 删掉的记忆是永久性的,删之前最好想想那些"过时但是偶尔有用"的内容怎么办。我的策略是:删除时保留原始 transcript 文件,这样即使向量层没了,真的需要时还能从原始对话里手动捞。

6.2 隐私边界:哪些内容不该进记忆

第二个坑,也是我认为最重要的:隐私边界。claude-mem 会把所有 Claude Code 会话内容默认都纳入加工范围。也就是说,你让 Claude 帮你写一份包含薪酬结构的提案,这段对话也会被记忆系统持久化。

这不是 claude-mem 独有的问题,但值得每个使用者提前想清楚。我的做法是:

  • 不把包含敏感凭证、密钥的对话放进记忆库,会话结束后手动删除对应 transcript;
  • 利用配置的project_patterns把某些目录排除在扫描范围外;
  • 对长时间不用的记忆库定期做整体清理。

如果你的团队有信息安全规范,建议在引入 claude-mem 之前先和运维确认存储数据的合规要求。工具本身是开源、本地的,数据不离开你的机器,但它毕竟是以明文和向量两种形态长期驻留在磁盘上的。

6.3 与大型代码库配合的性能问题

第三个坑是性能。我最初是在一个 monorepo 上直接启用 Git 记忆功能,结果 claude-mem 的 daemon 在扫描提交历史时长时间占用 CPU,一度让我以为机器卡死了。

排查后发现是首次构建索引的冷启动成本——它要把整个仓库的提交历史过一遍再向量化。解决办法是让 daemon 在非工作时段先跑一次全量构建,之后进入增量模式就基本无感了:

# 手动触发一次全量处理,然后观察 daemon 自动进入增量监听 claude-mem process --full systemctl --user status claude-mem-daemon # 或 mac 上的 brew services

另外,如果你的项目动辄几十万行代码,我不建议把所有模块的提交历史都开进记忆。更合理的方式是按需调整 Git 记忆的扫描范围,只纳入当前迭代相关的模块。记忆不是越多越好——同样的信息如果过量注入,Claude 的新上下文会被稀释,反而影响判断质量。这是我在测试中反复验证过的结论。

最后再分享一个自己的小习惯:每次重要会话收尾前,我会手动执行一次claude-mem process,确保这段对话的原始记录被及时加工进记忆库,而不是等 daemon 的周期任务。别小看这步,它保证了你最关心的上下文不会被后续会话的洪水淹没。claude-mem 看起来只是个"给 Claude 装记忆"的小工具,但用顺了之后,你会发现自己和 AI 协作的方式正在悄悄改变。