前几天把一个用惯了的配置目录连同初始化脚本一起删了紧接着又重装了系统。第二天打开终端准备让 Claude Code 继续昨天没做完的改动它一脸茫然地问我项目结构是什么样的——所有上下文全没了。那一刻我意识到Claude Code 什么都好唯独没有长期记忆这件事让我痛得够呛。会话一关它就把你的项目偏好、技术选型、之前拍板定过的方案全忘干净。后来我找到了 claude-mem 这个开源工具才算是把这个缺口补上了。简单说claude-mem 是 Claude Code 的记忆层它把每次会话中的交互内容自动沉淀到本地 SQLite 数据库里再通过 MCPModel Context Protocol给 Claude Code 提供跨会话检索能力。装好之后AI 助理能想起你之前在别的会话里交代过的约定不用每次都重新解释一遍。这篇文章就把我这几周的部署经历、原理拆解和踩坑记录完整写出来给同样被健忘折磨的人参考。1. claude-mem到底做了什么先理解会话级记忆与持久记忆的差别1.1 Claude Code的无状态困境Claude Code 本质上是一个终端里的 AI 编程助手。你给它一段任务描述它读取你的文件、调用工具、生成代码然后等你反馈。这一套交互在单个会话内部是连续的但一旦你退出会话或者新开一个终端窗口它面对的就是一张白纸。这不是某个客户端没做好而是大语言模型对话接口的天然属性API 调用是无状态的每次请求带的是当前上下文窗口里的内容模型本身不会记得上一次请求之外的东西。你说过的这个项目用 pnpm不要用 npm测试用 Vitest别用 Jest数据库迁移脚本放在 db/migrations 下面——这些信息全都锁在之前那次会话的上下文里新会话一个字都看不到。你可能会说把需求写在项目文档里不就行了行但问题是并不是每个人都坚持写文档而且很多时候这些约定是在对话中随口定下来的根本来不及沉淀到文档里。我就经常在会话里说这个接口保持向后兼容然后下一个会话它就开始大刀阔斧地改签名。1.2 claude-mem的定位——一个外挂长期记忆层claude-mem 的做法很直接它不做模型推理也不改 Claude Code 本身而是做在旁边的一个记录员。它监听会话内容把有人说过什么、做过什么决定、改过哪个文件、用了什么命令这些信息结构化地写进一个本地 SQLite 数据库。等到下次会话开始时Claude Code 通过 MCP 工具主动查询这个数据库把相关的历史记忆拉回上下文窗口。比较关键的机制在于记忆不是盲目全存而是有选择性的。它内置了一个抽取逻辑会判断哪些内容值得保存——比如技术决策、用户偏好、项目背景、任务进度——而不是把整个对话流水账一样灌进数据库。这一点我在后面的原理章节会展开。1.3 用生活类比理解 MCP 的作用想理解 claude-mem 为什么用 MCP 而不是别的方案可以先打个比方。MCP 的定位类似于给 Claude Code 开了一个外挂硬盘接口模型不知道这个硬盘内部怎么存数据的它只需要通过一组固定的工具名去读写就行。claude-mem 就是这块硬盘的驱动。具体到实现上claude-mem 会把自身注册成一个 MCP serverClaude Code 启动时会自动加载这个 server 暴露出来的工具列表。当模型判断需要回忆历史时它会调用类似remember、search_memories这样的工具去做查询再把返回结果当作上下文的一部分继续推理。这个过程对用户是透明的你看到的只是它居然记得上次说过什么。2. 拆开claude-mem的肚子三个组件、一条数据流、一份存储schema2.1 三个核心组件各自扮演的角色claude-mem 不是单个二进制文件它由多个组件组成理解它们的分工有助于你排查问题。我实际使用中最常接触到的有三个CLI 工具、MCP server、记忆抽取模块。CLI 工具是你直接在终端里敲claude-mem命令时用的前端它负责管理数据库、展示记忆列表、搜索历史、打开 SQLite 查看器等。MCP server 是给 Claude Code 的 API 调用入口它负责接收模型发来的查询记忆或保存记忆请求。记忆抽取模块则是一坨核心逻辑负责从原始对话里决定哪些内容进库、哪些内容丢弃。这个拆分带来的好处是如果你不想要自动记忆可以只装 CLI如果你想深度集成就让 MCP server 常驻。有些版本还会为不同的 LLM 后端做适配比如通过环境变量指向不同的 AI 服务地址来驱动抽取模块。如果你只使用 Claude Code 自带的模型这部分基本上不需要额外配置默认值就能跑通。2.2 会话数据是怎么流进SQLite的整个数据链路我可以一步步说清楚。Claude Code 的会话内容会经过一个前置处理claude-mem 监听会话输出在每条 assistant 消息生成完毕后做一次信息抽取。抽取出来的候选记忆会先经过一个去重与合并的逻辑相似度高的旧记忆会被更新而不是新增这样数据库不会无限膨胀。决定入库的内容会以 JSON 序列化后写入 SQLite 的对应表里同时建立索引方便后续全文搜索和相似度检索。我实际观察到的结果是一个高强度开发日大概 300 多轮对话生成的记忆条目大约在 40 到 80 条之间。每条记忆不是完整句子而是提炼后的要点。例如用户要求所有异步函数使用 async/await 风格禁止 .then 链式调用就会作为一条偏好记忆入库而不是好几轮讨论的完整记录。2.3 数据库文件里到底存了些什么默认情况下claude-mem 会把数据存放在用户目录下的一个隐藏文件夹里我这边是~/.claude-mem里面是一个标准的 SQLite 数据库文件。表结构大致包含记忆内容、关联的项目路径、创建时间、更新时间、来源会话 ID、记忆类型这几个核心字段。我常用claude-mem open-db直接看库或者用 SQLite 命令行工具去查表。有一回我需要清理一批关于旧架构的记忆直接跑 SQL 删掉比用命令一个个删快得多。不过要提醒一句直接动库之前一定先备份文件别问我怎么知道的。字段层面的设计还有一个有意思的细节每条记忆会打上项目路径的标签。同一条记忆在另一个项目里不会被读到这在多项目场景下是刚需——否则你在 A 项目里的技术偏好会污染 B 项目的决策。3. 本地部署实录从零开始跑通claude-mem3.1 用pkgx自动装还是npm手工装claude-mem 官方推荐用 pkgx 来跑原理是它会自动下载对应版本的依赖避免污染你的全局 Node 环境。我一开始觉得多此一举直接用了 npm 全局安装。结果后面踩了一个版本不一致的坑这个我在第五节会细说。这里先给结论如果你是新手直接按官方推荐用 pkgx 最省心如果你对 Node 生态比较熟而且能接受自己管理版本npm 全局安装也行。我的安装过程大致是这样先确认 Node.js 版本满足要求我用的是当前 LTS 版本然后执行 npm 全局安装命令。安装完成后终端里敲claude-mem --version能看到版本号就说明 CLI 部分已经没问题了。3.2 把MCP server注册进Claude Code这一步是让 Claude Code认识claude-mem 的关键。Claude Code 的配置文件里有一个 MCP servers 的注册区域你需要在这里加一段指向 claude-mem MCP server 的配置。不同版本的 Claude Code 配置入口略有差别有的是全局配置文件有的是项目级.mcp.json。当时我照着官方 README 里给的配置模板把 command 和 args 填进去启动 Claude Code 后输入/mcp命令检查集成状态。看到 claude-mem 出现在已连接的 server 列表里就算注册成功了。这里有一个新手很容易忽略的点修改配置后必须重启 Claude Code 会话MCP 连接才会重新加载。3.3 用一次带记忆的会话验证是否生效配置完成之后我习惯用一套验证流程来确认记忆真的在起作用。先在一个会话里输入一句明确的偏好比如以后所有新文件头部都加许可证注释然后结束会话。新开一个会话直接问 Claude Code你记得我对文件头有什么要求吗。如果它回答正确说明链路已经通了。我第二次实测时遇到的情况是它说我不确定但用 claude-mem 命令搜索明明能搜到那条记忆。这种库里有、模型不用的情况多半是 MCP server 没有把记忆注入到模型上下文。原因通常是 Claude Code 没有把记忆检索工具暴露给模型或者模型没有主动调用的习惯。解决办法是更新 claude-mem 到最新版本再检查 MCP 连接状态。还有一个更简单的验证方法在同一项目目录下连续开两个会话第一个会话里让 Claude Code记住一个文件路径第二个会话问它这个路径。如果答得上来说明不仅是存储成功了而且检索链路也没问题。4. 实际效果与工作流改变跨会话记忆怎么用出价值4.1 一个多会话开发的完整示例我最近维护一个内部工具项目重构工作分了三个会话才做完。第一个会话里我们确定了新的目录结构并且明确老的 utils 目录逐步废弃新代码统一进 lib。第二个会话开始前我什么都没说只发了一条消息让 Claude Code 继续处理昨天的重构任务。它自动回忆起了目录迁移计划直接在新目录下创建了文件而不是像以前一样继续往 utils 里塞代码。第三个会话里我改需求说某个解析逻辑要支持新格式。Claude Code 回答时提了一句根据之前的约定解析器统一放在 lib/parsers 下。那一刻我是真的觉得这个记忆层把 AI 编程助手的项目成员感拉高了一个档次——它开始像同事一样记得项目约定而不是每次见面都像第一次合作。4.2 记忆命令的两种用法显式询问与自动判断用了一段时间之后我总结出 claude-mem 的两种实用姿势。第一种是显式询问适合你主动想了解历史记忆的场景。比如项目中断了两周回来时直接问我们之前对这个模块的改动计划是什么或者用命令手动搜索记忆库。这种情况下模型会把检索到的记忆作为上下文回答得非常有针对性。第二种是自动判断纯粹靠模型在对话过程中自己决定该不该翻记忆。这个更考验 MCP server 的工具设计是否合理。claude-mem 在会话开始时会把与当前项目相关的核心记忆摘要注入到上下文里相当于给模型一份工作交接笔记。后续对话中如果涉及记忆里的内容模型就能自然地引用。我个人的经验是不要完全依赖自动注入。遇到关键决策节点主动让 Claude Code回顾一下之前关于 XX 的讨论得到的答案会比它自己凭上下文猜要可靠得多。4.3 我的真实使用节奏与取舍我用下来觉得最合理的节奏是重要项目的会话开始时先让 Claude Code 检索一遍项目记忆接着正常干活每天结束时用claude-mem list快速扫一眼今天的记忆条目发现有存歪了的内容就用claude-mem delete或claude-mem edit修正一下。有些记忆我是不希望它存的比如临时的调试信息、一次性测试数据。好在 claude-mem 的命令行工具提供了比较完整的记忆管理能力删起来并不麻烦。需要说明的是记忆抽取本身也是要消耗 token 的如果会话特别长这个开销会反映在 API 账单上。对于预算敏感的场景可以考虑关闭部分自动记忆功能或者定期清理数据库让抽取范围变小。5. 踩坑记录双路径重装、数据库锁与工具边界5.1 双路径重装导致的两个claude-mem互不认账这是我遭遇的第一个坑。当时我同时用了 pkgx 和 npm 两种方式安装 claude-mem本意是想测试哪个版本的抽取效果更好。结果发现两个安装路径各自持有一份独立的资源MCP server 跟 CLI 连的数据库不对。具体表现是CLI 里能看到刚存的记忆但 Claude Code 里的模型怎么都检索不到。排查了一整晚最后发现 npm 安装的 claude-mem 数据落在默认目录而 pkgx 安装的 MCP server 因为环境变量指向了一个自定义目录两边读的是完全不同的库文件。这个问题的教训是同一台机器上不要用两种方式同时装 claude-mem卸载要卸干净。如果你实在需要切换就把环境变量里跟数据目录有关的配置统一指向同一个路径改完记得重启所有相关进程。5.2 SQLite数据库文件被锁或损坏后的恢复第二个坑出在数据库层面。某天我跑了一个长时间会话Claude Code 在反复调用记忆工具然后我突然用命令行工具去操作同一个数据库文件发现 SQLite 返回database is locked。原因是默认的 SQLite 配置在并发读写时容易锁库尤其是在 WAL 模式没开启的情况下。解决办法很简单确保 claude-mem 的版本支持并启用了 WAL 模式或者避免同时用两个进程操作同一个库。我在实践中会遵循一条规矩Claude Code 会话运行期间尽量不手动改库文件如果必须改先暂停会话或者等会话结束再操作。恢复方面SQLite 数据库本身的容错还比较好一般小问题跑一下PRAGMA integrity_check就能看出来。如果真的出现损坏优先从备份文件恢复。我现在会定期把整个~/.claude-mem目录打包备份到自己的备份盘里这个习惯帮我避免了好几次灾难。5.3 claude-mem不能替代什么最后聊一点清醒的认识。claude-mem 解决的是跨会话上下文丢失的问题但它不是 Silver Bullet。它不能替代项目文档。记忆库是碎片化的适合快速检索不适合承载需要系统性组织的架构说明。我见过有人把 claude-mem 当 wiki 用记忆存了几百条真要找某个设计背景时反而搜不出来了。它也不能替代版本管理。代码改了就是改了记忆里存的是我们讨论过要改成什么样而不是实际的提交记录。这两者的错位会在复盘时造成迷惑。它在一些极端情况下也会失效。比如模型上下文窗口太小、或者项目记忆条目过多导致摘要注入被截断。这种情况我遇到过一两次表现为 Claude Code 明明带着记忆却想不起来。解决方案是清理低质量记忆条目给关键记忆留出空间。所以我的最终使用定式是claude-mem 负责快速想起项目文档负责深入理解Git 历史负责忠实记录。三件事各管一摊配合起来才最稳。实际用下来我会把这些命令和配置写进自己的环境初始化脚本重装机器之后几分钟就能把整个记忆系统恢复回来。如果你也在重度使用 Claude Code并且经常因为它又忘了而抓狂花一个晚上把 claude-mem 部署起来是值得的。