如果你用过Claude Code,八成经历过这种场景:昨天刚教它把项目里的缩进从四个空格改成两个,今天新开一个会话,它又老老实实地按四个空格写给你看。你跟它确认过的“这个项目统一用pnpm,别碰npm”,隔一个晚上就忘得干干净净。我在这种反复拉扯里消耗了很长时间,直到在GitHub上翻到claude-mem这个开源项目,才算是给Claude Code装上了真正意义上的“长期记忆”。
claude-mem是一个第三方开源工具,它的定位非常明确:给Claude Code提供跨会话的持久化记忆。它通过Claude Code的插件扩展点接入,把对话中值得沉淀的信息自动写入本地SQLite数据库,并在下一次会话启动时把相关记忆重新注入上下文。简单说,它让Claude从“每次都要重新认识的实习生”变成了“慢慢了解你习惯的同事”。这篇文章不是官方文档的复读,而是我实际拆解、部署、使用了claude-mem之后,对整个项目运作机制、接入步骤、实测效果和踩坑过程的一次完整复盘,给准备上手或者正在纠结要不要用的朋友一个参考。
1. 为什么我给Claude Code装了个“第二大脑”:会话失忆是最痛点
1.1 每个全新会话都在重复解释同样的事
Claude Code本身是Anthropic推出的命令行AI编程工具,能在终端里直接读代码、改文件、跑测试、提PR。但它的默认设计是“会话隔离”的:每次新开的会话都是独立上下文,上一次对话既不会自动延续,也不会被主动召回。这其实是很合理的工程决策,毕竟无状态的服务才好横向扩展,也才能控制每次调用的token成本。
可问题在于,人类和AI协作一段时间后,真正有价值的东西往往是“渐进的共识”:你偏好什么代码风格、这个项目的目录结构为什么这么设计、哪个接口有隐藏的坑、哪条命令在CI里跑不过去。这些东西不会写进需求文档,却会严重影响协作效率。于是在Claude Code上出现了经典一幕:昨天你花了二十分钟让它理解“这个仓库里所有新组件必须用函数式写法”,今天它又兴致勃勃地给你生成一个class组件。
我自己最崩溃的一次,是帮一个老项目做技术升级。项目的构建链路特别脆弱,必须在打包前先执行某个脚本,否则产物会缺文件。我第一天反复叮嘱,它确实记得。第二天新开会话,它直接跳过了那步,打包出来的东西果然少了资源。这种问题根本不是模型能力不够,而是上下文根本没带过来。
1.2 CLAUDE.md不够用,我需要的是自动记忆
可能有人会说,Claude Code不是支持CLAUDE.md吗?确实,Claude Code支持在项目根目录放一个CLAUDE.md文件,里面写项目说明和编码规范,会话启动时会自动读取。这个机制我一直在用,但它有几个绕不开的短板:
- 它是静态的。你改了代码风格、换了依赖管理工具、发现了新坑,得手动去更新文件,很容易忘记。
- 它高度依赖人的表达能力。你得把经验提炼成文字,而很多“经验”是在对话中自然流露的,当时没记录,事后根本想不起来。
- 它是按项目为粒度的。跨项目的全局偏好(比如“我写TypeScript永远用双引号”),每个项目都要写一遍。
所以我真正想要的,是一个能自动从对话里提取关键信息、自动沉淀、下次自动带回来的系统。一开始我觉得这想法有点天方夜谭,因为大模型对话本质上是无状态的,想让它自己记忆,除非会话之间能共享某种外部存储。直到我看到了claude-mem,它做的事情恰好就是这一套。
1.3 claude-mem的定位:本地优先的第三方记忆插件
claude-mem的项目作者是Jake Dahn,代码仓库在GitHub上,主线用Rust写成。它本身不是一个独立的AI应用,而是寄生在Claude Code插件体系里的“记忆服务器”。核心特点可以归纳成这么几条:
- 本地存储:所有记忆落在本地SQLite数据库,不强制上传云端,隐私可控。
- 自动记忆:在对话过程中,Claude会调用它暴露的工具,把值得记的内容主动写入数据库。
- 语义检索:不是简单按关键词匹配,而是通过embedding向量相似度,捞出于当前话题最相关的历史记忆。
- 项目级隔离:同一个全局偏好全局生效,不同项目的特定上下文互不串台。
- 可视化:它附带一个Web界面,能直接查看、搜索、删除记忆,不用黑盒操作。
我把它称为“第二大脑”,因为它改变的不仅仅是记住什么,而是让AI开始具备“跨会话的连续性”。下面两章,我先拆开它的工作机制,再讲实际部署步骤。
2. 记忆从写入到注入的完整链路:MCP、SQLite与语义检索是怎么配合的
2.1 先搞清楚MCP是什么
要理解claude-mem,绕不开MCP(Model Context Protocol,模型上下文协议)。这是Anthropic推动的一个开放协议,目的很简单:让AI应用可以通过统一的标准接口去调用外部工具和数据源。你可以把它理解成AI世界的“USB-C接口”,不管插的是鼠标还是硬盘,接口规范是一致的。
Claude Code本身就是一个MCP客户端,它可以加载任意实现了MCP协议的服务器。MCP服务器负责暴露工具,比如create_memory、search_memories,Claude在对话中判断需要时可以主动调用这些工具,拿到结果后再作为上下文的一部分继续推理。
claude-mem本质上就是一个MCP服务器。它在本地启动一个进程,监听Claude Code发来的工具调用请求,读写背后的SQLite数据库。这个架构非常干净:Claude负责“决定什么时候记忆、记忆什么”,claude-mem负责“把记忆存好、搜出来”。两边通过MCP这个标准协议交谈,谁都不需要知道对方的内部实现。
2.2 扩展点claude_code_mentor:一次对话前的自动“提词”
Claude Code的插件系统里有一个扩展点叫claude_code_mentor,这个“mentor”的职责是在对话开始前向Claude提供额外的背景信息。你可以把它想象成一个老员工在实习生开始干活前先交代几句:“这个项目注意啥,老板喜欢啥风格,上次哪块儿出了问题。”
claude-mem正是挂在这个扩展点上。当你配置好插件后,每次启动Claude Code,插件系统就会拉起claude-mem的MCP服务器,并在系统提示里注入一条指令:让Claude去检索与该会话最相关的记忆,把它们当作背景知识参与后续对话。
这个过程发生在用户正式提问之前,所以Claude不是“失忆状态下硬猜”,而是先被“提词”过一次。提词的内容来自两个维度:一是全局记忆(所有项目通用的偏好),二是项目级记忆(当前工作目录对应的记忆)。两者都会经过语义检索,而不是全量灌入,避免上下文被无关历史占用。
2.3 SQLite里到底存了什么
claude-mem的存储选型是SQLite,这个选择很务实。个人使用规模下,记忆条目大概在几千到几万条,SQLite单文件存储、零运维成本、读写性能绰绰有余。数据表的设计思路大致可以分成三块:
- 会话表:记录每一次对话的基本信息,比如会话ID、工作目录、开始时间、模型版本。
- 消息表:存对话中的关键消息原文或摘要,作为记忆的原始依据。
- 记忆表:这是核心,存提炼出来的“有价值记忆”。每条记忆通常包含文本内容、所属会话、所属项目目录、创建时间,以及对应的embedding向量。
值得一说的是“所属项目目录”这个字段。claude-mem按当前工作目录来划分记忆的归属,这样你在~/work/project-a里形成的记忆不会跑到~/work/project-b的上下文里去。同时它又保留了全局记忆区,专门存放那些与具体项目无关的偏好。
2.4 语义检索:几十条记忆里捞出最相关的那一条
记忆存进去不算本事,关键是能捞回来。claude-mem的检索方式不是简单的SQL LIKE查询,而是走语义检索。
当一条记忆被写进去时,claude-mem会为它计算一个embedding向量,也就是把这段文本映射成一个高维数组,语义相近的文本在向量空间里的距离也更近。查询时,把当前对话的关键信息也转成向量,然后计算它和库里所有记忆向量的余弦相似度,取top-k作为候选记忆返回。
可能你会担心性能:如果是几千条记忆,每次查询都要做全量计算,会不会很慢?实测下来,在个人电脑上,几千条级别完全是无感的。就算是上万条,耗时也就是几十毫秒到百毫秒级别,因为每条向量本身很短,SIMD加速下计算余弦相似度非常快。这个方案虽然“暴力”,但对单机个人使用来说足够优雅。
2.5 记忆转移的完整闭环
把所有环节拼起来,一次完整的记忆流转是这样的:
- 你启动Claude Code,插件系统拉起claude-mem的MCP服务器。
- 会话开始,claude-mem把当前目录和全局记忆里最相关的若干条注入上下文。
- 对话过程中,Claude识别到“这个信息以后可能还有用”——比如你告诉它某个测试命令很慢、某个模块是历史遗留、你更喜欢箭头函数——它会调用MCP工具创建一条记忆。
- 这条记忆被写入SQLite,并计算好embedding向量。
- 若干小时后,你新开一个会话,步骤1和2重复,检索系统把这几天积累的相关记忆带回前台。
整个过程完全自动,不需要你手动敲任何“记住这句话”的指令。这也是claude-mem区别于简单备忘录的地方:它让“记忆”变成了一种可以由模型自身判断和执行的持续动作。
3. 安装与接入实操:从cargo安装到Claude Code插件配置
3.1 安装前检查:Rust工具链与Claude Code版本
动手之前,先确认环境。claude-mem主体是Rust编写的,所以如果你打算从源码编译安装,需要本机有Rust工具链。检查方法很简单:
rustc --version cargo --version如果没装,可以用官方推荐的rustup方式安装,这一步会花几分钟下载工具链,耐心等就好。另外Claude Code本身需要启用插件机制,建议先把Claude Code升级到比较新的版本,因为插件系统的接口在早期版本里并不稳定,版本太旧可能加载不了claude_code_mentor扩展点。升级命令通常是:
claude update如果你不想自己编译,也可以直接去GitHub Releases页面下载对应平台的预编译二进制,解压后把路径放进PATH就行。我个人建议先用预编译版本跑通流程,之后想改源码再自己编译,省去第一道门槛。
3.2 从cargo安装的完整流程
我这边是用cargo装的,命令如下:
cargo install --git https://github.com/jakedahn/claude-mem编译过程会拉一批依赖,包括tokio、sqlx、serde这些Rust生态常见库,耗时大概几分钟到十几分钟,取决于机器性能。装完之后确认一下:
claude-mem --version能输出版本号就算安装成功。这个二进制同时承担两个角色:一个是你手动操作的CLI工具,另一个是供Claude Code调用的MCP服务器进程,入口都是同一个命令。
3.3 配置插件目录与MCP服务器参数
Claude Code的插件配置位于两个层级:用户级目录(~/.claude/plugins/)和项目级目录(.claude/plugins/)。用户级配置对当前用户的所有项目生效,项目级只对当前仓库生效。claude-mem建议装在用户级,这样任何目录下启动Claude Code都能加载。
插件目录下需要一个manifest文件,用来声明插件信息和MCP服务器。我当时的配置文件大致长这样:
{ "name": "claude-mem", "description": "Persistent memory for Claude Code via MCP", "mcp_servers": { "claude-mem": { "command": "claude-mem", "args": ["run"], "env": { "CLAUDE_MEM_CONFIG": "~/.claude-mem/config.toml" } } }, "claude_code_mentor": { "memory_tools": ["tool:claude-mem", "create_memory", "semantic_search"] } }写完后,还需要在Claude Code的配置文件里声明启用这个插件。具体路径和字段以你当前版本的官方文档为准,因为Claude Code的配置项迭代得比较快。我这里想提醒的是,command字段务必指向claude-mem二进制在PATH里的绝对路径,有时候shell环境变量在插件加载时没有正确传递,写成绝对路径最稳妥。
3.4 初始化与自检:跑通第一条命令
配置文件写好之后,先别急着启动Claude Code,我们先手动初始化一下:
claude-mem init这个命令会创建默认配置目录和SQLite数据库文件,通常位于~/.claude-mem/。初始化完成后,可以用status命令检查整体状态:
claude-mem status正常情况下会看到数据库路径、记忆条数、embedding后端等信息。接着验证MCP服务器能否独立运行:
claude-mem run如果进程能保持在前台运行不报错,说明MCP服务器本身没问题。此时再启动Claude Code,在对话里随便问一句“你有哪些可用的记忆工具”,如果模型能列出create_memory、semantic_search之类的工具名,说明接入成功。
3.5 embedding后端的选择:本地模型还是API
安装过程中最容易踩坑的是embedding服务的配置。claude-mem本身不管embedding计算,它需要连接一个embedding服务来生成向量。主流选择有两条路线:
- 本地模型:比如通过Ollama跑
nomic-embed-text,或者用llama.cpp拉起一个小型embedding模型。优点是隐私最好、零API费用、断网也能用;缺点是需要本机有可用内存或CPU算力,首次下载模型也要时间。 - 云端API:比如OpenAI的
text-embedding-3-small,或者Anthropic的embedding接口。优点是效果稳定、实现简单;缺点是每次检索和写入都会产生网络请求和费用,敏感代码路径会被发送到第三方。
我个人选了本地Ollama方案,配置里大体是这么写的:
[embeddings] provider = "ollama" model = "nomic-embed-text" base_url = "http://localhost:11434"选本地方案主要是隐私考量。代码仓库里的命名、注释、commit信息往往隐藏着业务逻辑,我不太愿意把这些东西的语义表示发到外部API。本地模型的效果对于“记忆检索”这个场景完全够用,没必要为了多几个百分点的准确率牺牲数据边界。
4. 三组实测:看看它到底记住了什么
4.1 测试A:跨会话记住编码风格偏好
接好之后,我先做了一个最简单的实验。在会话里告诉Claude:“以后在这个项目里,React组件一律用函数式声明,缩进统一为两个空格,不加分号。”然后关闭会话。
隔了一会儿,重新打开Claude Code,起了个新会话,直接让它“写一个UserCard组件”。它生成的代码里,组件用的是function声明,缩进是两个空格,语句末尾没有分号。这就是最基础的跨会话记忆生效了。
随后我又加测了一条全局记忆。在另一个完全不同的目录里,告诉它“我写TypeScript永远用单引号”。回到之前的项目再让它写代码,它依然能记住这个全局偏好。说明全局记忆和项目记忆是分层生效的。
4.2 测试B:项目级“坑位”记忆,换项目就隔离
第二个测试更贴近真实场景。我在project-alpha目录下和它协作时,明确说了一句:“这个项目的build脚本必须在打包前手动执行node scripts/prebuild.mjs,否则产物会缺文件。”它回应说已经记住了。
我在同一个会话里切换到project-beta目录,问它“这个项目打包前有没有需要注意的地方”。它表示没有检索到相关记忆。这说明project-alpha里的记忆没有污染到project-beta,项目级隔离是真正生效的。
这个功能我个人非常看重。因为大多数开发者同时维护多个仓库,如果记忆全部混在一起,A项目的架构决策被带到B项目,反而会制造噪音。claude-mem按工作目录做命名空间切分,本质上就是在模仿人类“不同项目脑子里装不同事儿”的状态。
4.3 测试C:语义检索——用新话题撬动旧记忆
第三组实验,我验证了一下它到底是不是真的“语义”检索。我在之前的会话里记录过一句话:“老版本axios存在响应拦截器重复执行的问题,当时通过给拦截器添加标记位解决的。”
几天之后,我新开会话,故意没有提axios、拦截器这些词,而是换了个角度问:“之前我们处理网络请求的重复回调问题,最后方案是啥?”它不但理解了我在问什么,还把那条记忆完整带了出来。
这就是embedding检索的价值。如果只靠关键词匹配,这段对话根本联系不上;但向量检索把“网络请求”“重复回调”“响应拦截器”这些词映射到了相近的语义空间,才能做到跨表述召回。
4.4 webui查记忆:看到系统里到底长了什么
跑完三组测试后,我用claude-mem web --port 8787打开了它的Web界面。页面很干净,左侧是记忆列表,每一条都标注了来源会话、所属项目目录和创建时间;右侧是记忆详情,能看到原始文本和关联的会话内容。
这个界面最实用的地方是“清理”。AI自动记忆并不总是精准的,偶尔会存下一些噪音,比如某次调试中的临时结论、已经失效的过时信息。在界面里直接删除比改数据库方便得多。我养成了每周扫一眼记忆库的习惯,顺手把过期和错误条目清掉,保证注入上下文的质量。
4.5 一个让我真正信服的场景
真正让我决定长期用它的一次经历,是帮朋友接手一个半死不活的老项目。项目结构混乱,构建脚本有三套,测试环境还依赖一个本地mock服务。我把这些信息在对话中一条条交代清楚,claude-mem自动记录了下来。
第二天朋友在自己的电脑上打开同一份代码,用了同一个配置好的claude-mem,新会话里直接问“这个项目怎么跑测试”,Claude准确地说出了要先用mock服务、再跑特定脚本的流程。那一刻我感觉这东西已经不只是“个人备忘录”,而是可以充当团队知识沉淀的载体。
5. 踩坑记录:MCP失联、记忆串台与上下文膨胀的排查过程
5.1 坑一:升级后MCP服务器起不来,先看日志还是先回滚?
事情发生在一次Claude Code自动升级之后。那天一开会话,我发现它对我的项目一无所知,新写的代码又回到了默认风格。我立刻用claude-mem status检查,数据库正常,记忆条数还在,说明问题出在连接上。
我先试着单独运行claude-mem run,MCP服务器本身能起来,说明不是二进制损坏。接着去翻Claude Code的日志,发现插件系统在加载时直接忽略了那个老manifest文件,原因是新版改了插件配置的字段格式,旧的claude_code_mentor声明不再被识别。
排查到这儿就清楚了:不是记忆丢了,是插件没被加载。解决办法是把manifest迁移到新格式,重新执行claude-mem init再写一遍配置文件。这里想提醒大家,Claude Code最近迭代很快,升级后如果发现记忆失效,优先检查插件配置兼容性,别急着怀疑数据坏了。
5.2 坑二:跨项目记忆串台,语义相似度惹的祸
有一段时间我同时维护两个代码风格完全不同的项目:一个是大型Java后端,一个是Node工具库。某天我在Node项目里要求它写一个异步任务调度器,结果它参考了Java项目里关于线程池的设计记忆,给了我一套明显水土不服的方案。
原因也不难理解。项目级隔离是按工作目录走的,但如果两个项目里用了极其相似的关键词和描述——比如都涉及任务队列、都涉及“并行处理”——向量检索时会捞出对方项目的记忆,因为它们在这个过程中根本无法感知“这句话属于哪个项目”。
这个坑的排查比修复更值得说。我没有急着关掉隔离机制,而是先查了被注入的记忆来自哪个会话。发现确实是跨项目的。最终我采取的方案是:在项目记忆的检索条件里加上强制的工作目录过滤,同时在全局记忆搜索时降低权重。说白了就是让“当前项目”成为检索的硬约束,而不是一个软偏好。
5.3 坑三:上下文窗口被记忆挤占,写一会儿就触顶
第三个困扰出现的比较晚。用了两周之后,记忆库渐渐壮大,某个会话里我明显感觉Claude“变笨了”,经常答非所问,甚至出现上下文溢出警告。一查,原来是注入的记忆条目太多,再加上会话本身的代码内容,把上下文窗口快撑满了。
个中道理很简单:记忆工具是把双刃剑,注入的上下文越丰富,留给当前任务的token就越少。claude-mem本身有配置项控制注入条数和单条长度,但默认值未必适合你的使用习惯。
我的调整思路是三步走。先降低注入条数,从默认的一口气注入十条改成只注入最相关的三条;再限制单条记忆的长度,超过两百字的记忆自动截断;最后定期用webui清理旧记忆。经过这几轮优化,上下文溢出问题再没出现过。
5.4 排查链路总结:日志、配置、版本三步定位法
踩过这几个坑之后,我总结出一套快速定位思路,分享给各位参考:
| 现象 | 优先检查 | 常见根因 |
|---|---|---|
| 完全没记忆注入 | Claude Code日志、插件manifest | 升级导致插件配置格式失效 |
| 记忆错乱/串项目 | 注入记忆的会话来源 | 语义检索跨项目命中,过滤条件不足 |
| 上下文溢出/变笨 | 记忆条数、单条长度配置 | 注入量过大,记忆库未定期清理 |
| MCP服务器启动失败 | claude-mem run单独运行 | 环境变量丢失、路径错误 |
核心思路就一句话:先确定是服务器没起来,还是服务器起来了东西没找对,还是东西对了但太多了。这三个问题对应三条完全不同的修复路线,千万别混着排查。
6. 我现在的用法与后续建议:让记忆工具真正成为团队资产
6.1 把claude-mem当“交接文档生成器”
用了一段时间后,我对它的定位发生了一点变化。一开始我只把它当成“AI的便利贴”,后来发现它更该被当成“自动生成的交接文档”。每次结束任务前,我会主动说一句:“把这次改动里值得记录的关键点保存下来。”然后claude-mem会把架构决策、踩坑结论、命令注意事项全部沉淀下来。
过几天不管是我自己还是同事接手,新会话里都能直接继承这些上下文。尤其是接手历史包袱很重的老项目,这个能力比任何wiki都好用——因为wiki需要人写,而claude-mem是AI在协作过程中顺手套出来的。
6.2 几条实操建议
基于这几个月的使用体验,我整理了几条操作层面的建议:
- 记忆要小而准。大段项目背景、完整架构设计放到
CLAUDE.md里,经验结论、易错点、偏好风格交给claude-mem。两者分工,不要互相替代。 - 定期清理记忆库。每周花两分钟在webui里过一眼,删掉过时条目。保质比保量重要,错误记忆比没有记忆更有害。
- 慎用云端embedding。如果项目代码涉敏感信息,优先本地模型。多花几十毫秒延迟,换来的是数据不出本机。
- 升级Claude Code后先验证记忆。升级完别急着干活,先问一句“你还记得我上次提到的编码规范吗”,确认插件链路没断。
6.3 这类工具的发展方向
站在更高视角看,claude-mem这类工具的出现其实是MCP生态成熟后的必然结果。AI的能力已经从“会思考”扩展到“会调用工具”,下一步自然就是“会积累经验”。单个智能体的记忆库,再往前发展就是团队的共享记忆服务器:多人共用一套知识库,AI在不同开发者之间传递项目上下文。
我甚至觉得,未来“AI的长期记忆”会像数据库服务一样成为基础设施,有专门的存储引擎、权限控制、版本管理。claude-mem虽然当前只是个人工具,但它验证了一个很重要的产品方向:让AI具备跨会话的连续性,是真实存在的巨大需求。
最后再分享一点个人体会吧。用这工具两个月,最直接的感受是Claude Code从一个“每次都要重新介绍的陌生人”,慢慢变成了一个“知道你喜欢单引号、知道你项目有哪些坑”的老同事。如果你也被反复解释同一件事折磨过,不妨给它一次机会。第三方工具嘛,装之前建议先翻一遍源码,确认它只在本地写数据、只调用你配置的embedding服务,再决定要不要接入。毕竟,让AI记住你的事情之前,你自己得先搞清楚它到底把记忆写在了哪里。