你有没有遇到过这种场景:在 Claude Code 里连续干了三四个小时,把接口设计、数据库选型、代码风格约定都聊清楚了,结果第二天开新会话,它问你“这个项目的数据库连接串在哪里配置”。不是模型变笨了,是会话本身就是一次性的。我为了解决这个问题开始用 claude-mem,一个给 Claude Code 做长期记忆的开源工具。它的思路很直接:把每次会话里真正有价值的决策、偏好、约束提炼成结构化记忆,落到本地 SQLite,再通过 MCP 协议让 Claude 在后续会话里按需检索。这篇文章是我接入 claude-mem 之后的完整记录,包含原理、配置步骤、日常用法和踩过的坑,适合所有正在用 Claude Code 做真实项目、却总在重复解释上下文的人。
1. 为什么 Claude Code 需要额外记忆层:会话遗忘的本质
先明确一个事实:上下文窗口再大,它也只是给一次会话用的“工作台”,不是档案柜。模型看到的所有内容都会在会话结束后被清掉,下次新建会话时,它唯一能依赖的只有系统提示、当前目录文件,以及你手动维护的 CLAUDE.md 这类静态输入。换句话说,你昨天在对话里做出的判断,今天默认就不存在了。
这个问题的代价在真实项目里特别明显。我随便举几个例子:
- 你昨天明确说了“这个项目不要用 ORM 自动迁移,改成手写 SQL”,今天新会话里它可能又给你生成迁移工具。
- 你花了二十分钟带它梳理了第三方支付回调的幂等逻辑,第二天让它改相关代码时,它完全不记得那套结论。
- 团队已经确定用 pnpm + workspace,新会话却开始用 npm 初始化。
这些都不是模型能力问题,而是“项目上下文”没有跨会话保存。很多人第一反应是往 CLAUDE.md 里写。这有效,但有两个硬伤:一是手动维护,容易漏、容易旧;二是 CLAUDE.md 本质是静态文本,你能写进去的是“你当时记得要写的东西”,而不是“对话里真实发生过的重要决定”。
也有人想走捷径,把过去所有对话日志直接丢进新会话。我试过,效果很差。几百 KB 的聊天记录混在一起,相关结论被淹没在无关讨论里,模型找不出来不说,token 消耗还高得离谱。而且越是低优先级的无用信息,越会干扰它当前任务的注意力。
到这里就清楚了:需要的是一个介于“静态文档”和“完整日志回放”之间的东西。它应该自动记录,但不存储原始流水账;它应该可检索,但语义上能理解“数据库连接串”和“DB URL”是同一个概念;它应该轻量,在每次会话中只注入少量关键记忆,而不是把所有历史都塞进去。
claude-mem 就是按这个需求设计的。它监听 Claude Code 的会话生命周期,在会话开始时注入记忆提示,在会话中提供语义搜索工具,在会话结束时把长对话压缩成摘要,然后存进本地数据库。下次会话里,Claude 可以通过 MCP 工具主动查历史记忆,而不是靠你重新讲述一遍。
2. claude-mem 的核心机制:SQLite 为底座、语义检索为入口、MCP 为接口
我对工具的第一要求是“能搞清楚它到底在本地做了什么”。claude-mem 没那么复杂,整条链路可以分成三个阶段。
2.1 会话结束时的“提炼”阶段
Claude Code 支持 hook 机制,也就是在某些事件发生后执行外部命令。claude-mem 会在会话结束(Stop 事件)时触发一次记录命令,把当前会话的完整上下文丢给语言模型做一次摘要提取。这一步不是简单截取最后几条消息,而是生成结构化记忆单元,概念上大概是这样的:
{ "id": "f3c8a1e2-...", "project": "order-service", "abstract": "用户要求所有金额计算统一使用 Decimal,禁止浮点数直接比较", "tags": ["订单", "金额", "约束"], "created_at": "2025-06-14T18:30:00Z" }每条记忆并不是原文,而是提炼后的结论。这个设计很关键:原文有大量噪音,比如反复试探、错误路径、语气词,直接存原文既占空间又增加检索干扰。存摘要就不一样,直接把“用户强调过什么、否决过什么、最终定了什么”提取出来,后续检索命中率会高很多。
2.2 SQLite 持久化与语义索引
记忆条目会被写入本地 SQLite 数据库。这里值得展开说一下为什么选 SQLite:它单文件、零运维、不需要额外起服务,备份就是一整份文件,对个人工具来说这是最稳妥的形态。数据库里除了记忆文本和标签之外,还会为每条记忆生成一个向量表示,也就是 embedding。
为什么要做向量?因为关键词搜索解决不了同义表达问题。比如你在新会话里说“帮我看看之前关于回调幂等的结论”,而历史记忆里写的是“支付通知去重策略”。两边字面完全不同,靠 grep 搜不到,但语义向量会判定它们是高度相关的。这就是 claude-mem 检索时的核心逻辑:用本地 embedding 模型把查询转成向量,再在数据库里按相似度取回 top-k 条历史记忆。
我实际体验下来,最直观的差异就是:你不需要记住当时“具体怎么措辞”,只需要知道大概在聊什么,它就能把相关记忆捞出来。
2.3 MCP 服务器:记忆检索的入口
存储只是开始,真正让记忆变得可用的是 MCP(Model Context Protocol)桥接。claude-mem 会启动一个 MCP 服务器,向 Claude 暴露几个工具,常见的有搜索记忆、保存记忆、删除记忆。Claude 在会话过程中如果判断需要历史信息,可以直接调用这些工具。
我的理解是,MCP 的价值在于把记忆从“你手动喂给模型”变成“模型按需自己取”。哪怕你不改任何提示词,只要 Claude 判断当前任务跟历史有关系,它就会去搜。当然,为了让这个行为更稳定,我也会在系统提示里加一句引导,让它遇到不明确的上下文时先查记忆。
还有一个容易被忽略的设计:claude-mem 并不会在每次会话开始时就把整库记忆灌进上下文。它只会注入一段说明,告诉 Claude“你有一个记忆库可用”,最多再注入少量高优先级信息。这样做既能控制 token 消耗,也能避免不相关的历史干扰当前任务。记忆这种东西,只有在你需要的时候出现才是价值,全程挂在眼前反而成了噪音。
3. 从零接入 Claude Code:安装、初始化与三个 hook 位点
接入 claude-mem 不复杂,但有几个环节配置错了会影响实际效果。我按自己的操作流程一步步说。
3.1 环境准备与安装
前提是本地已经装好 Claude Code,且有 Python 3.10 以上的环境。安装只需要一条命令:
pip install claude-mem装好后命令行里会有claude-mem命令,部分版本也提供cm简短别名。你可以先跑一下版本检查:
claude-mem --version claude-mem --help第一次使用建议直接跑初始化:
claude-mem init这个命令会做三件事。第一,创建~/.claude-mem目录,并在里面生成 SQLite 数据库;第二,检查 Claude Code 的 hook 配置,把必要的命令写进去;第三,扫描你已有的历史会话,尝试生成一批初始记忆。扫描这一步比较耗时,如果历史会话很多,可以先挂着让它跑完。我建议首次初始化之后用claude-mem status看一眼结果,确认数据库路径和 hook 状态都正常。
3.2 hook 配置:决定记忆“什么时候触发”
初始化完成后,它会在 Claude Code 的配置里写入 hook。我当前用的配置简化后长这样:
{ "hooks": { "SessionStart": [ { "hooks": [ { "type": "command", "command": "claude-mem inject" } ] } ], "Stop": [ { "hooks": [ { "type": "command", "command": "claude-mem record" } ] } ] } }解释一下这两个 hook 分别干什么。SessionStart的inject负责在新会话开始时往上下文里注入记忆片段和工具说明,让 Claude 知道“你有历史记忆可用”。Stop的record负责在会话结束或中断时把这次对话做摘要归档。一进一出,形成闭环。
这里提一点:Claude Code 的 hook 分为项目级和用户级,前者放在项目的.claude/settings.json,后者放在用户目录。如果只是个人项目,用项目级配置本身就够,不要全局注入,否则所有项目都会共享同一套记忆逻辑,后面会很容易产生跨项目串味。团队协作时更要注意:不要把个人记忆库路径写进仓库级配置,那会让所有成员的记录互相污染。
3.3 验证配置是否生效
写完 hook 不能直接开干,先跑一次检查:
claude-mem check这条命令会告诉你几个关键信息:数据库能不能打开、hook 命令路径找不找得到、embedding 模型是否可用。我遇到过最典型的问题是命令行工具路径。比如用某种 node 版本管理器,claude-mem命令只在某个 shell 里能被找到,但 Claude Code 执行 hook 时用的是另一个环境。解决方法是把 hook 里的 command 改成绝对路径,例如/home/you/.local/bin/claude-mem inject,一劳永逸。
如果你跟我一样还用编辑器里的 Claude Code 插件,还需要检查 MCP 服务是否注册成功。一些版本会在初始化时自动完成,如果没自动注册,可以手动在.mcp.json里加:
{ "mcpServers": { "claude-mem": { "command": "claude-mem", "args": ["mcp"] } } }之后重启 Claude Code,在 MCP 列表里看到 claude-mem 就说明接上了。
4. 高频操作与调优策略:从命令行到 MCP 搜索
配置接入只是起点,日常怎么用才是决定这工具“值不值”的关键。我把自己最常用的几个操作整理成了一张速查表。
| 命令 | 作用 | 典型场景 |
|---|---|---|
claude-mem status | 查看初始化状态、数据库位置 | 排障第一步 |
claude-mem check | 检查 hook 和依赖健康度 | 升级后确认兼容 |
claude-mem search 关键词 | 语义搜索历史记忆 | 查历史结论 |
claude-mem add --text "..." | 手动写入一条记忆 | 主动记录关键决定 |
claude-mem export | 导出全部记忆为 JSON | 备份、迁移 |
claude-mem zap --id | 删除指定记忆 | 清理错误记录 |
claude-mem ui | 启动本地 Web 界面 | 可视化查看和检查 |
我最常用的是search。比如项目做了一半,我想知道之前有没有讨论过“日志脱敏”方案,直接跑:
claude-mem search 日志脱敏它会返回一批相关记忆,每条都有摘要和时间。这比翻旧会话日志快太多了。另一个很值得养成习惯的是add。有些决定发生在对话里的某个瞬间,当时没有形成完整会话,或者你想要把某条规则变成硬约束,就手动补一笔。我通常这么记:
claude-mem add --text "所有对外接口统一走 /api/v1 前缀,鉴权用 JWT,token 有效期 2 小时" --tag api,鉴权这样手动写入的记忆在下一次检索时就有机会被命中。Claude 在 MCP 工具里也能直接调用保存函数,等于你在聊天里说一句“记住这个”,它就能自己落库。
4.1 让 Claude 主动翻旧账
虽然 MCP 工具理论上允许 Claude 自己决定要不要搜索,但实际使用中它的主动性还是不够强。我的做法是在项目提示词里加一句引导,类似:
当用户提到的需求可能在历史对话中有结论时,先搜索记忆库再回答。
加了这句之后,Claude 遇到“之前不是说好……”“这个配置是不是改过”“上次我们讨论过……”这类表述时,就会先触发搜索,再基于结果回答。这个改变很微小,但体感差异巨大,直接避免了很多次“重新发明轮子”的对话。
4.2 记忆的可视化与直接审计
CLI 操作虽方便,但记忆积累多了以后,需要有整体视角。claude-mem 提供一个本地 Web 界面,运行claude-mem ui后浏览器打开页面,可以按项目、按时间浏览所有记忆条目。我每个月会过一遍,把明显过时的、错误的信息直接删掉。
如果你更习惯直接碰数据,也可以打开 SQLite 文件:
sqlite3 ~/.claude-mem/claude_mem.db浏览记忆表、检查摘要内容、确认搜索逻辑是否合理,这些都是允许的。注意不要边跑着 Claude Code 边改数据库,加锁冲突会导致写入失败,先停掉会话再操作。
4.3 本地优先与隐私边界
关于数据安全,claude-mem 的设计天然是本地优先的,记忆默认落在你自己机器的 SQLite 文件里。但有一个点必须提醒:摘要提取和向量生成的具体实现,不同版本可能不同,有些用的是本地模型,有些把数据发给外部模型接口。如果你是处理敏感项目,务必在初始化之后实际看一眼流量和配置,确认是不是本机推理。
我的建议很简单:如果公司代码不能出本地环境,就选完全本地推理的版本,不要因为贪图摘要质量盲目开远程模型。记忆库本身就是极高密度的项目情报,录进去的每一条都是实打实的业务决策,保管等级应该跟你手里的密钥差不多。
5. 我用 claude-mem 三个月后踩到的坑和优化方法
写到这里,讲的都是“正常路径”。但实际用了三个月,我碰到的问题比文档里提到的情况要具体得多。这里分享四个我认为最值得注意的坑。
5.1 记忆膨胀:库越来越大,检索越来越乱
第一个坑是最早遇到的。用了一个半月后,某天我搜“部署流程”时返回的全是无关记忆,有些甚至是两三周前的日常琐碎。原因不复杂:每次会话结束都会自动生成摘要,而我当时的会话里夹杂了大量小任务,比如“把报错贴出来看看”“帮我解释一下这段代码”这类过程性内容也被提炼成了记忆。
解决思路有三步。第一,在记录提示里明确“只记结论、决策和约束,不记过程”。第二,定期用claude-mem ui人工清理,把明显不值得保留的记忆 zap 掉。第三,干脆做一次“重新开始”——用 export 导出全量 JSON,备份后清空数据库重新初始化,只把还有价值的条目通过 add 写回去。这种整体瘦身每季度做一次就够了。
5.2 摘要质量不稳:模型“不知道什么值得记”
第二个坑比膨胀更隐蔽。自动摘要的质量取决于当时的上下文和模型判断,但对“什么值得记”的理解经常不符合我的预期。比如它会仔细记录“用户正在用 Ubuntu 22.04”,却漏掉“用户明确反对引入 RabbitMQ,坚持用 Redis Stream”。后者才是真正影响未来决策的信息。
我后来做了两件事。第一,在对话中主动强调,例如说出“请记住这个决定:我们不用消息队列,用 Redis Stream”,这样 Claude 在生成记忆时就会有强引导。第二,重要的约束我用claude-mem add手动录入,而不是依赖自动摘要。现在我的原则是:自动记录兜底,手动补丁保证关键信息不丢。
5.3 多项目、多分支共用一个记忆库的冲突
这个坑来自我自己的错误配置。我把 claude-mem 装成了用户级全局 hook,于是 A 项目里记的约定,偶尔会串到 B 项目的检索结果里。表面看都是“技术结论”,但背景完全不同,反而干扰了判断。
正确做法是每个项目独立初始化,或者至少在建库时限定项目名,让搜索默认只查当前项目。我现在每个仓库的.claude/settings.json里只挂项目级 hook,数据库也按项目目录区分。团队协作时尤其要强调:个人记忆库不要提交到 git,仓库里只保留 hook 配置,具体记忆文件放进.gitignore。
5.4 被 Claude Code 更新打断的兼容性问题
最后提醒一下版本兼容。Claude Code 本身更新很勤,hook 事件格式、MCP 注册方式都可能变化。遇到过两次跟新后 claude-mem 命令找不到的问题,后面总结出几条经验:
- hook 命令用绝对路径,别依赖 shell 环境变量。
- 升级 claude-mem 后马上跑
claude-mem check,确认 hook 配置依然有效。 - 重大项目里不要一有新版就盲目升,先在测试目录验证一轮。
- 保持记忆库可备份,任何升级前先
claude-mem export一份 JSON。
说实话,claude-mem 不是银弹,它不会自动把每个项目都变成“有记忆的团队协作者”,它只是把记忆的采集、存储、检索这件事做扎实了。真正让它发挥价值的,是你怎么定义“值得记的东西”,以及在对话里怎么引导它记录。我个人现在每天开工前会先跑一次claude-mem search 昨天结论,把前一天的上下文捡回来,再开始新任务,这个习惯本身已经比工具更值钱。