claude-mem:为Claude Code打造外置记忆层,告别会话失忆
我在用 Claude Code 干活的时候,最烦的不是模型不够聪明,而是每次新开一个 session,它就像失忆一样把我之前打的样、定的规矩、踩过的坑全忘了。claude-mem 就是为解决这个问题出现的开源工具——它在 Claude Code 旁边挂了一个本地记忆层,自动记录终端里的对话,把零散的会话沉淀成可检索的长期记忆。这篇文章不聊花哨的概念,只讲 claude-mem 到底是什么、怎么接进日常流程、背后的存储和检索原理,以及我实际用下来的注意事项。
1. 为什么 Claude Code 需要一块"外置海马体"
1.1 上下文窗口不等于记忆
很多人分不清"上下文窗口"和"记忆"这两个东西。Claude Code 本身有一个很大的上下文窗口,聊天时它能引用当前对话里的内容,这确实有用。但它的问题在于:一旦会话结束,或者上下文被大段压缩,那些信息就跟着丢了。下一次启动claude命令,它面对的是一个全新的空状态。
你可以在项目里写一份 CLAUDE.md 让它每次读,但 CLAUDE.md 本质上是静态文件,需要你手动维护。真正的工作中,大量有价值的信息是在对话中慢慢浮现的:某个模块为什么这么设计、用户对这种交互方式的反馈、某条命令在这个环境里必须加参数、某个库在版本升级后出现的兼容性问题。这些东西你当时没意识到很重要,回头要用的时候才想起来,但系统早就忘光了。
claude-mem 的思路是把这个环节自动化。它通过挂钩 Claude Code 的事件,把会话内容按一定策略保存下来,再通过摘要和向量化把它变成可检索的长期记忆。简单说,它给 Claude Code 装了一块外置海马体,负责把短期对话转成长期记忆。
1.2 手工复制粘贴方案的问题
在没有 claude-mem 之前,最常见的做法是手动维护笔记:把重要结论复制到一个 MEMORY.md 里,下次开 session 时贴回去。这个方案不是不行,但有几个硬伤。
第一是时机问题。你正沉浸在改代码的状态里,很难判断哪句话值得记录,等回过神再整理,细节已经模糊了。第二是格式问题。不同的人记笔记风格完全不同,有人只记结论,有人记完整上下文,导致笔记越用越乱。第三是检索问题。笔记多了以后,你压根不知道哪条笔记对应哪个场景,搜索只能靠关键字,语义相近但表述不同的话搜不到。
claude-mem 把这些事情接管以后,我开始理解"记忆工具"和"备忘录"的本质区别。备忘录需要你主动去写,记忆工具则在后台持续工作。它自动收集、自动摘要、自动建立索引,你只需要在需要的时候去检索。
1.3 claude-mem 的解决思路
我们用最简单的话概括 claude-mem 的闭环:记录、存储、检索、注入。
- 记录:通过 Claude Code 的 hook 机制,在每个关键事件触发时抓取对话内容。
- 存储:原始会话和生成的记忆分别落在本地 SQLite 数据库里。
- 检索:用语义向量把记忆文本向量化,搜索时按相似度召回。
- 注入:你可以在新会话里通过
/memory之类的命令或直接把搜索结果贴给 Claude,让旧记忆参与新决策。
这个闭环的目标不是取代你的判断,而是减少重复劳动。每次新会话开始时,你不用再把项目背景、技术约束、历史决策重新讲一遍,而是直接搜索相关记忆,让 Claude 在一开始就站在之前的成果上继续干活。
2. 从安装到接入:claude-mem 与 Claude Code 的挂钩方式
2.1 安装与环境要求
claude-mem 的安装方式很直接,我用的是标准安装脚本,在终端里执行一行命令就好。如果你不想走脚本,也可以从 GitHub Releases 下载对应平台的二进制文件,或者用包管理器安装。
安装前要确认几件事:
- 系统里有 Node.js 或对应的运行时(取决于你的发行方式,这一步通常会自动处理)。
- 有可用的 Claude Code 环境,也就是你已经装好
@anthropic-ai/claude-code并且能正常跑claude命令。 - 有一个能访问 Anthropic API 的 key,因为 claude-mem 做摘要时多数情况下会调用 Claude 模型。如果你只用纯本地 embedding,不跑摘要,那至少也要配置好本地模型服务。
我当时的安装过程就踩过一个坑:终端里同时跑了多个 Shell 环境,zsh 和 bash 的 PATH 不一致,导致安装完成后claude-mem命令找不到。解决办法很简单,装完以后重启终端,或者执行hash -r刷新命令缓存。
2.2 install 命令到底改了什么
claude-mem install是接入 Claude Code 的关键命令。它做的事情不是把某个脚本塞进你的项目里,而是修改用户的全局配置文件,默认路径是~/.claude/settings.json。
这些配置的核心是 hooks。Claude Code 本身支持在特定事件发生时执行外部命令,claude-mem 利用了这个机制注册多个钩子:
- SessionStart:会话开始时触发,用来标记新 session 的开始。
- UserPromptSubmit:每次用户提交 prompt 时触发,用来捕获输入。
- PostToolUse:每次工具调用结束后触发,用来捕获代码读取、文件写入等动作。
- Stop:会话停止时触发,用来做收尾和摘要。
配置文件改完大致长这样:
{ "hooks": { "SessionStart": [ { "matcher": "", "hooks": [ { "type": "command", "command": "claude-mem onSessionStart" } ] } ], "UserPromptSubmit": [ { "matcher": "", "hooks": [ { "type": "command", "command": "claude-mem onUserPromptSubmit" } ] } ], "PostToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "claude-mem onPostToolUse" } ] } ], "Stop": [ { "matcher": "", "hooks": [ { "type": "command", "command": "claude-mem onStop" } ] } ] } }字段在不同版本里可能有细微差异,比如 matcher 的匹配规则或者 command 的具体参数,最好以你当前版本实际生成的配置为准。我写这个示例只是为了让你理解它工作的底层机制,而不是让你照着抄。
2.3 Hook 事件的触发链路
把 hook 拆开看,就能理解为什么 claude-mem 能做到"无感记录"。
当你在终端里启动claude时,SessionStart 事件先触发,claude-mem 创建一个新的 session 记录。接下来你输入 prompt,UserPromptSubmit 触发,它会把你的输入保存下来。Claude 开始执行工具调用,比如读文件或者运行命令,PostToolUse 触发,它会把工具名、输入参数、执行结果一并捕获。最后你输入/exit退出,Stop 事件触发,它会整理这一整段会话。
这里有个值得留意的点:hook 的执行是同步的还是异步的,直接影响使用体验。如果 claude-mem 处理得太慢,你的对话会被卡住。实际上它做了很多异步操作,事件触发后先把数据写入本地缓冲,摘要和向量化在后台慢慢跑。所以正常使用中你几乎感觉不到它的存在。
我建议你装好后先跑一个短会话,然后打开~/.claude-mem/logs看看有没有报错。第一次接入时最容易出现的问题就是权限不对,比如配置文件目录不存在,或者 SQLite 数据库文件无法创建。
2.4 为什么选 Hook 而不是改系统 Prompt
其实做一个记忆工具,最简单粗暴的思路是改系统提示词,让它每次会话前把记忆读出来塞进上下文。这做起来方便,但副作用很大。系统提示词越长,模型在对话中需要同时维护的上下文就越多,不仅消耗 token,还容易让模型分心,抓不住当前任务的重点。
Hook 这种路线等于把"记录"和"使用"拆开了。记录阶段完全在本地异步发生,不影响主对话;使用阶段由你决定要不要把记忆注入进去。这种设计更克制,也更符合实际使用习惯。很多人其实不需要每次会话都加载全部记忆,只需要在关键决策点去查一下相关记录。
我自己用下来,最大的感受是:好的工具应该像一个靠谱的同事,而不是一个喋喋不休的助理。它平时不说话,但你问问题的时候,它能给出有依据的回答。
3. 日常操作全解:search、remember、session 与自动摘要
3.1 你用最多的应该是 search
claude-mem 提供了一组 CLI 命令,其中search是我日常使用频率最高的动作。它的作用是做语义搜索,也就是你输入一句自然语言,它返回与之意思相近的记忆片段。
示例:
claude-mem search "上次说的那个登录接口的限流方案是什么?"它会返回一组记忆,每条可能包含记忆 ID、时间、来源 session 和内容摘要。输出通常不会太长,方便你快速判断哪条是你要的。
区别于普通的关键词搜索,语义搜索能处理同义表达。比如你上次说的是"登录接口的频控",这次你搜的是"限流",它依然能召回。背后的机制是向量相似度检索,我后面会详细讲。
如果你觉得返回结果太宽泛,可以加参数限制数量:
claude-mem search --limit 5 "数据库迁移的注意事项"我还发现一个技巧:搜索时尽量描述你当前遇到的场景,而不是直接复述你当时的原话。比如你正在调试一个诡异的内存泄漏,搜索"内存一直涨该怎么排查",会比搜索"memory leak"更容易找到相关的操作经验。
3.2 remember:手动写入长期记忆
自动记录很重要,但有些东西你希望立刻固化下来,不需要等它慢慢摘要。这时候用remember命令手动写入。
claude-mem remember "本项目约定:所有对外 API 的错误码统一使用五位数编码,前两位是服务编号。"这个命令很适合保存那些"团队约定"或"技术决策"。比如你在对话里刚确定了某个方案,与其等摘要生成后再确认,不如当场手动存一条。
也可以记录一些与对话无关,但对以后工作有用的信息。比如:
claude-mem remember "部署服务器上的 /tmp 目录空间有限,超过 2GB 的构建产物要放到 /var/artifacts 下。"手动写入的记忆和自动生成的记忆放在同一个库里,统一参与搜索。这样它们权重一致,不会被当作次要内容处理。
使用中要注意:不要什么都往里写。如果记忆库里堆了几千条琐碎内容,搜索结果的信噪比会下降。我通常只在两种情况下手动记录:一是明确的长期约定,二是跨 session 的关键决策。
3.3 session 与 stats:复盘一把梭
session子命令用来查看历史会话。常见用法有:
claude-mem session list claude-mem session show <sessionId>session list会按时间列出最近的会话,包括开始时间、结束时间和大概的消息数量。session show可以查看某个会话的详细内容,这个功能非常像在看终端回放,适合晚上复盘白天的工作。
stats命令则给你一个全局视角:
claude-mem stats它会显示总共有多少条记忆、多少段会话、存储占用多大等信息。我用它来判断记忆库是否健康。如果发现会话很多但记忆很少,说明摘要提取没生效,需要检查配置;如果记忆数量突然暴增,可能是某些无关内容被过度提取,需要清理。
这里有个真实体会:定期复盘会话记录能帮你发现自己的工作模式。我翻了一个月的 session 之后发现,自己在环境配置上花的时间远多于写业务代码的时间。这个认识比任何效率工具都值钱。
3.4 自动摘要怎么工作
自动摘要算得上是 claude-mem 比较核心的能力。每次会话结束后,它会尝试把会话内容整理成几条"可记忆"的条目。
这个过程的底层逻辑是:用一段专门的 prompt 喂给 Claude 模型,让它从原始对话中抽取那些对未来工作有参考价值的信息。常见的抽取对象包括:
- 项目架构决策和理由
- 某个命令或脚本的实际用法
- 依赖版本的坑和解决办法
- 用户明确表达的偏好或需求
摘要生成之后,会写入记忆库,进入可搜索的状态。
我刚开始用的时候有个误解,以为它会像会议纪要一样把每句话都总结出来。实际上它做的是"去重 + 提炼"。同一次会话里反复出现的细节,会被浓缩成一条核心结论。这样做的好处是记忆库不会无限膨胀,坏处是如果你需要非常细碎的原始信息,摘要可能不够用,这时候还是要靠 session show 去翻原话。
4. 记忆背后的存储与检索原理
4.1 SQLite:一份在本地、可控、可备份的记忆账本
claude-mem 的存储以本地 SQLite 数据库为主,默认目录在~/.claude-mem/下面。用 SQLite 的好处是简单、可靠、不需要额外起服务。数据库文件就放在你自己的机器上,你随时可以用工具打开看里面到底存了什么。
这一点很重要,因为它意味着你对数据有绝对的控制权。不需要上传到第三方云服务,也不依赖某个厂商的存储方案。对于很多开发者来说,"记忆在本地"本身就是一种安全感。
另外,SQLite 单文件的结构让备份变得非常容易。我每周会用 rsync 把~/.claude-mem整个目录同步到备份盘上,基本上不用担心数据丢失。如果你有 NAS 或者云盘,把整个目录放进去就好。
数据库里一般会分成几张表,比如存储会话的表、存储消息的表、存储记忆条目的表。它们之间通过 session ID 关联。实际字段名取决于版本,我不在这里展开,但了解这个结构对排查问题很有帮助。
4.2 向量化与语义搜索:为什么不是 LIKE
如果只做关键词匹配,直接用 SQL 的 LIKE 就够了,但 claude-mem 的搜索体验明显不是这个风格。它能理解语义,核心原因是它给文本做了向量化。
流程大致分三步:
- 把记忆文本切分成合适的段落或句子。
- 通过 embedding 模型把每段文本转换成一个固定维度的向量。
- 搜索时把你输入的问题也转成向量,然后计算它与所有记忆向量的余弦相似度,返回最接近的结果。
向量化模型有很多选择。claude-mem 支持配置不同的 embedding 提供方,比如 API 形式的 OpenAI 兼容接口,或者本地的 Ollama。我目前用的是本地配置,模型选的是nomic-embed-text。本地跑 embedding 的好处是速度快、数据不出机器、不产生额外费用;坏处是首次使用时需要下载模型,机器性能差的会有点慢。
配置示例大致这样:
{ "embeddings": { "provider": "ollama", "model": "nomic-embed-text", "baseUrl": "http://localhost:11434" } }如果你想用 OpenAI 兼容接口,就改成 provider 的对应名称,并配置 API key 和环境变量。
4.3 自动记忆提取的 Prompt 逻辑
除了存储和检索,记忆的质量还取决于"提取"环节。claude-mem 的自动摘要不是简单地截取最后几条消息,而是有一套提取策略。
我理解它的本质是:把"会话数据"转化为"经验条目"。会话数据是流水账,经验条目是结构化知识。中间需要一个转换器,这个转换器就是 Claude 模型本身。
阅读它的记录时我会想,它其实是在执行一个信息筛选任务——哪些信息在未来的会话中可能被再次用到?比如"我这次用了 npm 的--legacy-peer-deps才把依赖装好",这是一条值得记忆的信息;比如"我今天喝了三杯咖啡,下午打了两个小时游戏",这是无聊的流水账,不应该被保留。
所以如果你觉得自动提取出来的记忆质量不高,先看看是不是自己的对话质量不高。一个满是碎片化指令的会话,很难提炼出有长期价值的东西。反过来,如果你在会话里主动说清楚"为什么这么做",系统提取到的记忆质量通常会好很多。
5. 把 claude-mem 用顺手的配置与避坑经验
5.1 先决定 embedding 供应商
刚开始配置时,我面临的第一选择就是 embedding 用谁的。这个决定会影响延迟、成本、隐私和数据质量。
我的建议是分场景:
- 个人日常使用,机器配置还行的,优先用本地 Ollama。零成本,数据不出机器,离线也能用。
- 团队使用,或者要处理超大规模记忆库的,用 API 类服务更省心。省去本地模型管理,检索效果通常也更稳定。
- 隐私敏感项目,比如涉及客户数据或内部业务逻辑的,强制用本地方案,并且开启脱敏配置。
配置项中比较关键的是模型名称和维度。换模型时要注意,新旧模型的输出维度可能不同,原来生成的向量会失效,需要重新索引。我踩过这个坑:换模型后搜索质量骤降,查了半天才发现是向量维度不一致。
5.2 不要忽略隐私与脱敏
claude-mem 默认把所有对话都记录下来,但这不代表你希望所有内容都被记录。终端里经常会出现 API key、密码、临时访问令牌之类的东西。
应对办法有两个层面。第一,claude-mem 本身支持配置脱敏规则,把匹配到的内容替换成占位符再存储。你可以给它一批正则表达式,比如:
{ "redact": [ "sk-[A-Za-z0-9_-]{10,}", "ghp_[A-Za-z0-9]{20,}" ] }这样即使工具调用输出里带了密钥,存到数据库里的也是被 mask 过的内容,搜索时不会把真实密钥捞出来。
第二,你自己要有使用习惯。在终端里处理敏感信息时,尽量别让它们出现在命令行参数里。比如从环境变量读取密钥,而不是直接在命令中写死。这不仅是为了配合 claude-mem,也是终端使用的基本安全常识。
5.3 踩过的坑:Hook 没生效、重复记忆、记忆污染
我实际用下来有三个比较典型的坑,这里说详细一点。
第一个是 Hook 没生效。现象是:装了 claude-mem,也跑过 install,但打开实时统计发现没有任何数据进来。排查思路是先确认配置文件里有没有对应的 hook 条目,再手动执行一下claude-mem onSessionStart这类命令,看是否报错。如果是权限问题,解决方式通常是修复目录权限或重新安装。
第二个是重复记忆。系统把同一个信息存储了多条,导致搜索结果里前几条都是相近内容。原因通常出在摘要和手动记录叠加上:你在会话里手动 remember 了一条,摘要又自动提取了一条。办法是按记忆 ID 查重并手动删除多余条目,或者调整摘要的频率和覆盖范围。
第三个是记忆污染。这个比较隐性,指的是记忆库里很多内容你现在根本用不上,比如某次试验型会话留下的临时结论。搜索时这些内容会挤占相关性排序,干扰你的判断。最有效的办法是定期清理整个库,只保留那些经过验证的经验。我一般每月做一次"记忆审计"。
5.4 与其他工具的联动
claude-mem 的价值不只是单独使用。它可以和你的其他工作流串起来。
比如你在 Claude Code 里已经维护了一份 CLAUDE.md,claude-mem 可以和它配合:CLAUDE.md 记录稳定的、静态的项目约定,claude-mem 记录动态的、从实践中产生的经验。前者像公司制度手册,后者像个人工作日志。
如果你有自动化脚本,也可以把claude-mem search的结果输出到 JSON 文件里,再喂给后续流程。它在某些版本里提供了 serve 模式,可以起一个 HTTP 接口,方便其他工具调用。我个人在团队场景下更建议这么做:一台机器上跑 claude-mem 服务,团队成员共享一个记忆库,搜索结果直接在群里互相引用,比各自记笔记要高效得多。
6. 给重度用户的三条实操建议
6.1 建立"忘记"机制,而不只是"记录"机制
很多人用记忆工具时会陷入一个误区,觉得存得越多越好。实际上记忆库越大,检索噪声越高,相关度排序越不稳定。
我给自己定的规则是:每周花十分钟浏览一下本周自动生成的记忆,把那些已经过时或无关的条目用forget命令删掉。看似麻烦,但后续搜索会舒服很多。
claude-mem forget <memoryId>你也可以直接删除某个 session 下的所有记录,让那些明确不会再用的会话整体消失。保持记忆库的整洁,和保持代码库的整洁同样重要。
6.2 把重要记忆"手动升级"
自动记忆的质量取决于当时的对话。大多数日常会话能生成几条不错的记忆,但真正决定你工作质量的往往是几条核心经验。这些东西值得你用remember把它升级成标准条目。
我通常的做法是:每次项目收尾时,把项目里踩过的三个最大的坑分别用三句话写成一个条目。这句话不需要太多上下文,只要在将来看到时能提醒自己就行。下一次做类似项目时,搜索一个关键词就能把它捞出来。
这种"自动为主、手动为辅"的组合,比纯手动笔记轻松,比纯自动记录更靠谱。
6.3 结合 CLAUDE.md 做上下文的长期管理人
最后建议你不要让 claude-mem 承担所有记忆任务。它适合做"经验检索",但不太适合做"每次必读的上下文"。稳定的项目约束、技术栈说明、代码规范,这些应该放在 CLAUDE.md 里;动态的经验、踩坑、决策过程,放在 claude-mem 里。
我的日常习惯是:项目启动时把 CLAUDE.md 写清楚,工作过程中依赖 claude-mem 记录和检索。每次新会话开始,Claude 读 CLAUDE.md 获得骨架,我遇到具体问题再让 Claude 去搜记忆。这样两边职责明确,互不干扰,加起来才是一个完整的长期记忆系统。
回看我自己的使用过程,claude-mem 真正改变我的不是让我少敲了几行重复指令,而是让我意识到:工具能记住的,是发生过的事;但沉淀下来的,才是能用上的经验。这套记忆层值得每一个重度使用 Claude Code 的人认真配置一次。