如果你经常用 Claude Code 写代码、搞重构,大概率碰到过这种事:上午刚和它对齐了项目的目录结构、技术栈和代码风格,下午新开一个会话,它又回到“失忆”状态,连你用 React 还是 Vue 都要问两遍。这个问题的根源在于 Claude 的对话是无状态的,每次会话都是一张白纸。claude-mem 就是为解决这个痛点而生的开源 MCP 服务器,它的作用通俗讲就是给 Claude 装上一套长期记忆:让它能自动记住哪些信息值得留,在下一次会话里按需把旧记忆“翻”出来用。这篇文章我会从使用者的角度,拆解 claude-mem 的记忆机制、安装接入、配置项、数据管理,以及我实测过程中踩过的几个坑。内容主要面向已经在用或打算长期用 Claude Code 的开发者,也适合想给自己的 Agent 加记忆层的玩家。我会尽量把“为什么这么做”讲清楚,而不是只给一套命令让你复制。
1. Claude 的“失忆”是设计使然:claude-mem 到底在补什么缺
1.1 无状态不是 bug,是一笔成本账
Claude 的 API 在设计上就是无状态的。每次请求,服务端不会主动保存上一轮对话的状态,你需要把所有历史消息作为上下文传给它。对服务方来说,无状态意味着可以横向扩容,不需要维护海量的会话状态;对应用层来说,无状态也意味着数据更可控,对话结束即是删除,安全和合规上的负担小。这些都是实打实的优点。
但对开发者来说,无状态的代价在长期项目里会越来越明显。第一,上下文窗口再大也是有限的,Token 成本却在持续累积。你手动在 system prompt 里塞历史记录,到了第 20 轮对话基本就不可用了。第二,即使你愿意花 Token 钱,那些散落在对话日志里的关键决策、用户偏好、技术约束,也不会自动收敛成一条干净的记录。新会话开始时,Claude 知道的和你第一次打开它时一样多。
所以在 Claude Code 这类编程工具里,社区通用的做法是“外置记忆”:把项目说明、常见约束写进 CLAUDE.md 或项目文档,手动引导模型每次读取。这个方案我用了挺久,它有效,但有一个致命前提:你得记得去维护,而且 Claude 只能在你明确指示下被动地记,它不知道“什么东西值得记”、什么时候该把旧记忆翻出来。
claude-mem 切入的角度就是从这里开始的。它不是一个帮你写文档的辅助工具,而是一个跑在 MCP 协议上的记忆服务:由 Claude 自己在对话中判断该记什么,再把信息结构化存下来;下次对话,由 Claude 按需检索、注入到上下文。相当于把“外置记忆”这个需要人肉维护的状态,变成了一套自动运转的机制。
1.2 记忆方案对比:为什么我最后选了 claude-mem
在决定用 claude-mem 之前,我也比较过几种方案,这里直接给一张表:
| 方案 | 记忆来源 | 检索方式 | 维护成本 | 与 Claude Code 的集成度 |
|---|---|---|---|---|
| 手写 CLAUDE.md | 人 | 全量载入 | 高,容易过时 | 原生但不聪明 |
| 自建 RAG 管道 | 外部脚本 | 向量检索,需自己写接口 | 高 | 需要自己封装 |
| claude-mem | Claude 自主提取 | 语义+全文检索,通过 MCP 注入 | 低 | 原生 MCP 服务器 |
表格里最值得展开的是最后一行。claude-mem 最吸引我的点有两个:
第一,它不是被动的知识库,而是“调度器”。决定记什么、什么时候记、什么时候取,这些判断都由 Claude 来完成。你不需要维护一个专门的处理脚本,也不需要在每次对话开始时手动指定“请先读取记忆”。记忆的写入和读取都发生在对话流程之中。
第二,它跑在 MCP 协议上。Claude Code、Claude Desktop 以及很多支持 MCP 的客户端都原生兼容,装好 MCP 服务器就能用,不需要改业务代码。你既可以把它当成个人助手的长效记忆,也可以扩展为团队共享上下文。
当然,它也不是万能的。记忆质量高度依赖 Claude 本身的判断力,如果模型在某个领域表现不佳,记忆的准确性也会打折扣。但作为开发者工具,它已经足够好用。
2. 记忆的运转逻辑:Claude 怎么知道该记什么、该翻什么
2.1 两套记忆:显式记忆文件 + 语义数据库
第一次用 claude-mem 的人,容易把它理解成一个“聊天记录存档器”,但它的设计比这精细得多。
据我目前的使用经验,它把记忆分成了两层。第一层是显式记忆文件,通常以 Markdown 形式存放在本地记忆目录里,Claude 在需要的时候可以直接读取。这个文件的定位类似于一份“从历史对话中提炼出的项目速写”,特点是结构化、可读、稳定,适合承载那些需要反复出现的硬信息——比如用户的名字、项目的主要约束、你惯用的包管理器、测试命令、分支策略等。
第二层是语义数据库。claude-mem 默认用 PGLite 把记忆向量化后存起来,并建立全文索引。它的价值在于搜索:当你在新会话里问“之前关于数据库分表我们是怎么定的”,Claude 不是去翻原始聊天记录,而是通过 SearchMemory 工具做语义检索,把相关度最高的片段捞回来。对应到人的记忆模型,这就像“模糊回忆”——你不必给出准确关键词,描述个大概就能把旧账翻出来。
我自己是这样理解这两层关系的:记忆文件是长期贴在桌面上的便签,它一直在视线里,但你不会给便签写长篇小说;语义数据库是身后的一整柜档案,平时锁着,问到了才去查。两条路径互补,既保证核心信息一定能被看到,又避免把所有历史都塞进上下文窗口。
2.2 Memory 工具:让 Claude 学会“记重点”
自动记忆的核心不在数据库,而在 Claude 的判断规则。claude-mem 启动后,会通过 MCP 向 Claude 暴露一组工具,同时往 system prompt 里注入一段记忆指令,里面规定了什么时候该调用工具、该存什么。
这条指令的大意是:当你发现用户透露了可复用的个人信息、项目决策、代码约定时,调用 Memory 工具把这信息存下来。也就是说,记忆动作的发起方从“用户”变成了“模型”。我举个例子,有次我在对话里说了一句“这个项目里我们统一用 pnpm,不用 npm”,下一轮 Claude 就调用了 Memory 工具,把“项目使用 pnpm 作为包管理器”这句话写进了记忆。全程我都没有说“请记住”。
根据我的观察,它判断“值得记”的信息大致有几类:
- 用户身份与偏好:姓名、角色、常用技术栈、沟通风格
- 项目级约束:目录结构约定、依赖管理策略、测试工具选择
- 关键决策:为什么选了某个方案、哪块代码被重构过、结论是什么
- 术语与命名:内部缩写、特殊文件路径、专有名词
这里必须说一句:真正好用的记忆不是“什么都存”,而是“知道该扔什么”。Claude 现在的判断力还远称不上完美,但已经能覆盖大部分高频场景,而且它有用结构化输出规范来限定记忆条目格式的意识,防止记成流水账。
2.3 SearchMemory 与上下文注入:检索结果怎么进入对话
每开一个新会话,claude-mem 并不会把所有记忆一股脑塞给 Claude。如果那样做,无状态问题的解法只是换了种方式把 Token 烧掉。
它的实际工作方式更像“按需取用”。对话开始后,Claude 结合当前任务判断是否需要历史记忆。如果需要,就调用 SearchMemory 工具,把用户的问题或当前上下文作为检索条件,在语义数据库里找相关片段。检索结果会以上下文片段的形式返回,Claude 再把它自然融入当前回复。
这个设计有两个直接好处:第一,Token 开销可控,不会被旧记忆占满上下文;第二,避免信息污染,你问“这周的发布计划”,它不会把三个月前的琐事也给翻出来。
不过,按需取用也有代价:检索质量决定记忆利用率。如果检索召回了一堆弱相关片段,或者漏掉了关键片段,Claude 依然表现得像失忆。claude-mem 在这块的处理是在底层同时做全文检索和向量检索,再对结果做排序,尽量把相关度高的内容送进上下文。实际用下来,“我记得好像有这回事”这类模糊查询的命中率还不错。
除了 SearchMemory,工具集里还有负责拉取上下文前情的工具,名称在不同版本里可能略有差别。我习惯把两者的分工理解为:SearchMemory 回答“我记得好像有这回事,具体是什么”,前者回答“这个项目的前情提要是什么,我接手时的状态如何”。
2.4 对话归档:SaveChat 让每次会话都留底
除了点状记忆,claude-mem 还会把完整的对话保存下来,对应的是 SaveChat 工具。这个功能在项目复盘和问题回溯时特别有用。比如某个 bug 从发现、分析到修复,中间经历了哪些讨论,靠记忆碎片拼不出完整链路;但有完整会话文档就可以查。
对话保存策略可以通过环境变量控制,比如 CLAUDE_MEM_SAVE_CHATS 控制总开关,CLAUDE_MEM_CHAT_STRATEGY 控制保存节奏。归档的格式一般是可读的 Markdown 或 JSON 文件,存放在本地数据目录里,之后可以交给其他脚本做二次分析。
对我来说,这个功能最舒服的用法不是“留档”,而是作为“工作日志自动生成器”。每隔一段时间,我直接翻会话归档,就能还原出某个功能是怎么一步步定下来的,省去了自己写周报时翻聊天记录的时间。
3. 五步上手:安装接入、初始化和自检
3.1 环境准备:Node 版本与 MCP 客户端
在装 claude-mem 之前,先确认环境满足最基本的三点:
- Node.js 18 或更高版本,npm/npx 可用
- 你日常使用的客户端支持 MCP,比如 Claude Code、Claude Desktop,或者其他兼容 MCP 的编辑器插件
- 能正常访问 npm registry,因为首次启动需要拉取依赖包
Node 版本这块多说一句:如果你的 Node 太老,启动 MCP 服务器时可能会报一些莫名其妙的模块错误,但错误信息里通常不会直接提示版本问题。我的习惯是先node -v看一眼,达不到要求就用 nvm 切换。
3.2 命令行安装与 MCP 服务器注册
我推荐用 npx 方式运行,不需要全局安装也能快速体验。先跑一下版本号确认包能正常拉取:
npx -y @hackmd/claude-mem --version确认没问题后,在 Claude Code 里把它注册为 MCP 服务器:
claude mcp add claude-mem -e CLAUDE_MEM_SAVE_CHATS=true -- npx -y @hackmd/claude-mem命令里的-e CLAUDE_MEM_SAVE_CHATS=true是给 MCP 服务器传入环境变量,表示允许保存会话。不同版本的 claude CLI 参数可能略有差异,以你本地的claude mcp add --help输出为准。如果你用的是 Claude Desktop 或其他 MCP 客户端,就需要手动编辑客户端的 MCP 配置文件,写法是这样的:
{ "mcpServers": { "claude-mem": { "command": "npx", "args": ["-y", "@hackmd/claude-mem"] } } }配置完一定要完全退出客户端再重新打开。MCP 的服务器列表是在启动阶段加载的,有些客户端提供了热重载按钮,但据我经验,完全重启最可靠。
3.3 初始化目录与配置
注册成功后,执行初始化命令:
claude-mem init这个命令会创建 claude-mem 的数据目录和默认配置文件。跑完之后,可以执行:
claude-mem config打印当前生效的配置,包括记忆文件路径、数据库路径、是否保存对话等。刚 init 完看到的基本都是默认值,后面想调参再通过环境变量覆盖,不需要改代码。
3.4 健康自检:doctor 一定要跑一次
装好之后我强烈建议先跑一次:
claude-mem doctor它会检查 Node 版本、MCP 连接状态、数据库可写性、记忆文件路径是否存在这几项,发现问题会给出对应的修复提示。这个命令特别适合在你改动过环境变量、切换过 Node 版本后用来排查。
还要提醒一个细节:如果你不希望每次启动都通过 npx 联网拉包,可以改成全局安装:
npm install -g @hackmd/claude-mem然后把 MCP 注册命令里的 command 从npx -y @hackmd/claude-mem换成claude-mem。这样更稳定,响应也更快,算是团队里多人统一环境时的一个小技巧。
4. 配置项与数据管理:让记忆库按你的节奏生长
4.1 关键配置项速查
claude-mem 的配置基本靠环境变量,我列几个最常用的:
| 环境变量 | 作用 | 我常用的取值 |
|---|---|---|
| CLAUDE_MEM_HOME | claude-mem 数据根目录 | ~/.claude-mem |
| CLAUDE_MEM_MEMORY_PATH | 显式记忆文件路径 | $CLAUDE_MEM_HOME/memory.md |
| CLAUDE_MEM_DB_PATH | PGLite 数据库路径 | $CLAUDE_MEM_HOME/pglite |
| CLAUDE_MEM_SAVE_CHATS | 是否保存完整对话 | true |
| CLAUDE_MEM_CHAT_STRATEGY | 保存对话的时机策略 | auto |
| CLAUDE_MEM_SYSTEM_PROMPT | 自定义记忆系统提示词(视版本支持) | 内置即可 |
组合起来大概是这样:
export CLAUDE_MEM_HOME="$HOME/.claude-mem" export CLAUDE_MEM_MEMORY_PATH="$HOME/.claude-mem/memory.md" export CLAUDE_MEM_DB_PATH="$HOME/.claude-mem/pglite" export CLAUDE_MEM_SAVE_CHATS=true如果你在登录 shell 里写了这些变量,记得让客户端继承同样的环境。Claude Code 的 MCP 注册命令里也可以逐个-e传进去,保持一致性。
4.2 存储后端:PGLite 与 Postgres 怎么选
默认情况下,claude-mem 使用 PGLite 作为存储后端。PGLite 是嵌入式 Postgres 的 WASM 实现,不需要单独安装数据库服务,数据落在本地文件夹里。对个人开发者来说这是最省心的方案:零运维、零配置,数据就在自己的磁盘上。
如果你跑团队项目,想让多个人的 Claude 共享一套记忆,或者想把记忆数据放到中心化数据库里统一备份,那可以切换到完整 Postgres。做法是设置 DATABASE_URL:
export DATABASE_URL="postgresql://user:password@localhost:5432/claude_mem"需要提前在数据库里启用 pgvector 扩展,因为 claude-mem 的向量检索依赖它做相似度查询。
两种后端我各用了一段时间。个人项目的结论是:PGLite 够用,不用折腾;团队协作或者想把记忆和现有审计体系串起来时,Postgres 更合适。切换后端之前,记得先把原有记忆文件备份好。
4.3 CLI 实操:手动补记、搜索和清理
虽然自动记忆是主打功能,但 CLI 手动操作在日常维护中也很重要。我常用的几条命令如下:
# 手动补记一条信息 claude-mem remember "用户偏好使用 pnpm 管理依赖" # 搜索记忆库 claude-mem search "项目约定" # 列出保存过的会话 claude-mem chats # 查看某次会话详情 claude-mem chat <会话ID> # 查看当前配置 claude-mem config # 重置数据库(慎用) claude-mem reset手动补记适合在 Claude 没意识到某信息重要时使用。搜索则是我定期检查记忆质量的工具——如果搜索出来的结果和我的记忆有偏差,说明它在自动提取时存歪了,需要及时修正。
4.4 记忆维护:锁定重要条目,清掉过期信息
记忆库和代码库一样,需要维护。我目前的操作习惯是:直接编辑显式记忆文件,把那些必须长期生效的强约束条目放在最前面,并且保持表述简短,让 Claude 每次读到这里都能第一时间看到;语义数据库里的内容则交给检索和数据沉淀自然筛选。
如果发现某条记忆过时了,直接在对话里跟 Claude 说“更新一下:我们已经不用 Jest 了,改成 Vitest”,它会走 Memory 工具更新记忆。如果错误信息已经污染了很多条目,最干净的办法是先claude-mem search看一眼污染范围,再决定是手动清理还是 reset 后重新积累。
5. 实测避坑:我用 claude-mem 踩过的四个坑
5.1 记忆文件越写越长,反而等于没记
我刚开始用的时候,把记忆文件当成“详情页”,恨不得把每个决策的原因、讨论过程都写进去。结果文件越来越长,Claude 每次都要花大量 Token 读取,重点反而不突出了;语义检索的质量也跟着下降,因为相似度计算被一堆弱相关条目干扰。
后来我强迫自己遵循两个原则:第一,记忆文件控制在 200 行以内,只写结论和摘要;第二,每条记忆尽量一句话讲清楚,比如“项目使用 pnpm,禁 npm”而不是“我们讨论了 npm 和 pnpm 的优劣,最后由于团队习惯选择了 pnpm”。细节留到语义数据库里,按需检索,别想着一次性全部塞给模型。
5.2 MCP 注册后工具不生效,大概率是重启不到位
这是我遇到次数最多的问题。明明claude mcp add执行成功了,也看到配置文件里多了 claude-mem 的条目,但进了 Claude Code 之后,工具列表里就是没有 claude-mem。
排查下来,几乎都是同一个原因:配置修改后没有完全退出客户端。MCP 服务器列表在启动阶段加载。一些客户端虽然提供了热重载或刷新按钮,但实测并不可靠。我的建议是:改完配置直接退出进程,重新打开。
另外,如果 npx 方式首次拉包较慢或者网络状况不佳,注册阶段也可能直接失败。遇到这种情况,换成全局安装再注册,把npx -y @hackmd/claude-mem改成claude-mem,几乎所有偶发问题都能绕过去。
5.3 自动记忆会把推测存成事实
这是自动记忆的固有风险:Claude 在对话中如果听到了“我可能想用 Node 写个服务端”这类带推测色彩的话,有可能把它当成客观事实记下来。下次对话它可能煞有介事地引用“用户需要用 Node 写服务端”,实际上你只是随口一提。
我的应对方法是分三层:
- 日常对话中,关键决策尽量用明确句式说出口,比如“最终决定用 Deno”,少用“可能”“或许”
- 定期跑
claude-mem search抽查记忆条目,发现问题当场纠正 - 如果某条记忆的判断价值很高,直接在记忆文件里手动改成强约束句式
5.4 多项目共用一套记忆,串味之后很难受
claude-mem 的记忆可以是全局的,也可以按项目隔离。我在刚开始时就吃过亏:A 项目用 React,B 项目用 Vue,结果两个项目的对话被放进同一套记忆里,Claude 在 B 项目里偶尔会建议我用 React 的生态库,非常难受。
后来我针对不同工作目录分别配置了独立的 CLAUDE_MEM_HOME 和 CLAUDE_MEM_MEMORY_PATH,让每个项目各有一份自己的记忆库。这个操作不复杂,但非常关键。如果你平时会接多个不同类型的项目,我强烈建议从一开始就按项目分目录,而不是等串味了再重构。
6. 从“能用”到“好用”:记忆层的进阶做法
6.1 用记忆模板统一信息粒度
为了让自动记忆的条目更结构化,我试过把记忆模板固定成几段字段:
- Context:这条记忆适用的场景
- Decision:当时定下的结论
- Reason:选的这个方案的原因
- Action:后续要执行的行动
效果很明显。模板化之后,记忆条目不再是散装句子,而是上下文清晰的“决策卡片”。后期我做语义检索时,召回率没有明显变化,但 Claude 引用记忆解释问题时更有条理了,因为 Reason 字段直接给了它推理材料。
如果你用的版本没有暴露自定义提示词的配置,也不用担心。直接在记忆文件里把零散条目整理成统一格式,同样能达到大部分效果。重点是:记忆的存储格式,决定了模型读取时的利用率。
6.2 定期整理记忆:我的维护节奏
我目前给 claude-mem 配了每个工作日结束前的“记忆体检”习惯。具体动作是:
- 用
claude-mem config看一下记忆文件路径 - 打开记忆文件扫一眼,确认核心约束没丢
- 如果发现过时条目,直接在文件里改掉,或让 Claude 更新
每周我再跑一次claude-mem search,挑几个本周高频出现的主题做抽查,看看语义数据库里有没有存歪的内容。这套节奏花不了几分钟,但能让记忆库长期保持健康。
6.3 把 claude-mem 当作 Agent 的记忆层来设计
最后再往远说一步。claude-mem 虽然是为 Claude 设计的,但它的本质是一个 MCP 记忆服务,完全可以作为更通用 Agent 架构里的一个组件。我在写内部工具时,就把它的能力暴露给了自己的编排框架:Agent 接到任务前,先通过 MCP 拉取历史上下文,任务结束后把结果写回记忆库。这样一来,跨会话的状态管理就不散落在各处了,而是统一沉淀在一套记忆服务里。
如果你也打算在项目里引入长期记忆,我的建议是从小的场景开始:先把 claude-mem 挂在 Claude Code 里跑一周,观察哪些信息它记住了、哪些记歪了,再决定要不要继续往 Agent 框架的深处走。记忆这个东西,只有用起来才知道怎么优化。