我一直觉得,Claude 本身的能力足够强,但真正用起来最别扭的一点,是它“记性不好”。每次新开一个会话,我都要重新交代一遍背景:我是谁、我在做什么项目、之前讨论到哪一步了。哪怕我把对话写得再长,只要会话一关,这些内容就像没发生过一样。后来我找到了一个开源项目叫 claude-mem,相当于给 Claude 装上一块可插拔的长期记忆模块,让它能在会话之间记住关键事实、偏好和历史决策。这篇文章想把我在实际折腾 claude-mem 过程中的理解、部署步骤、调参经验还有踩过的坑,原原本本写出来,给同样被“无状态”问题困扰的朋友一个可参考的路线。
我需要先说清楚,claude-mem 不是某个官方插件,而是一个社区开源项目,它的定位是做一个“记忆服务器”,通过 MCP(Model Context Protocol)这类协议和 Claude 客户端对接。也就是说,它并不是去改 Claude 的模型权重,而是给 Claude 增加一个外部工具箱,让它在需要的时候可以主动去“查询记忆”或“写入记忆”。这种设计的好处是,Claude 本身依然是无状态的,但外挂的记忆层替它完成了跨会话的上下文管理。
1. 没有记忆的 Claude,用起来到底有多别扭
先聊聊我为什么会对 claude-mem 产生兴趣。过去半年,我基本把 Claude 当成了日常的“副驾驶”,写周报、改代码、整理采访纪要、做方案分析都在用。但每一次协作都像是从零开始。举个例子,我调试一个 Node.js 项目时,往往要连续好几轮对话,第一轮告诉它项目结构,第二轮贴报错日志,第三轮让它猜可能的原因。到了第四轮,我已经不想再重复项目结构了,可是如果不重复,它就会基于一个残缺的上下文给出离谱建议。
这种“无状态感”带来的不只是效率问题,它还会打断思路。我发现自己在对话中会下意识地说很多“我之前说过”“如上所述”之类的废话,目的就是帮 Claude 把上下文捡回来。时间一长,我甚至开始把重要信息写在一个单独的 markdown 文件里,每次对话开头手动粘贴。这个方法有效,但很蠢,因为文件越来越长,粘贴一次就有几千字,既浪费 token,又让 Claude 在无关细节里迷失。
claude-mem 解决的核心问题,就是把这个“手动粘贴文件”的过程自动化。它让我可以把“事实类信息”长期沉淀下来,比如我的项目环境、常用工具链、团队叫法、代码风格偏好,甚至是“上次我们已经决定用 pnpm 而不是 npm”这种决策记录。等到下次会话,Claude 通过工具调用主动检索这些记忆,再结合当前对话内容,就能表现得好像它一直都在跟进同一个项目。
它适合哪类人?我觉得主要适合下面几类:
- 每天和 Claude 高频多轮协作,但不想反复交代背景的重度用户。
- 在用 Claude Desktop、Claude Code 或类似支持 MCP 的客户端,希望给助手建立个人知识库的玩家。
- 想研究 Agent Memory 机制,想通过一个具体项目看看“长期记忆”在工程上是怎么落地的人。
如果你只是偶尔用 Claude 问几个一次性问题,那 claude-mem 带来的收益不明显,毕竟多一个服务就要多一分维护成本。可一旦你的工作流变得连续,它带来的体验提升是质变级的,这就是为什么我愿意在这上面花时间。
2. claude-mem 的原理拆解:记忆到底存在哪里、怎么被想起来
很多第一次看到 claude-mem 的人会有一个误解,以为它就是把所有对话历史原封不动存下来,然后在每次对话时整包塞给 Claude。如果真是这样,这工具没有任何价值,因为上下文窗口早就爆了,而且也没有哪个模型能从几千条闲聊里自动提炼重点。claude-mem 的聪明之处在于,它按照“记忆的存储”和“记忆的提取”两个环节分别做了处理,下面我拆开讲。
2.1 记忆的存储:事实优先,不是流水账
claude-mem 并不会盲目记录所有对话。它更像一个“记忆管家”,在对话过程中由 Claude 自己决定哪些内容值得记住。这套机制是通过一组 MCP 工具实现的。Claude 在推理过程中识别到“这个信息以后可能还会用到”,就会调用相应的工具,把这条事实写入持久化存储。
常见到的工具定义大概是这样的:
store_memory:存入一条结构化记忆,比如{ "key": "project_language", "value": "TypeScript" }。read_memory:根据关键词或语义检索历史记忆,并把匹配结果返回给 Claude 作为上下文。search_memories:更灵活的检索接口,支持过滤、排序、取 top N。delete_memory:删除指定记忆,用于处理过期或错误的信息。
关键在于,这些工具不是由用户手动触发的,而是由 Claude 根据当前对话内容自主决策。这听起来有点玄学,但实际跑起来就会发现,模型在越来越强的工具调用能力加持下,确实能判断哪些是无意义寒暄、哪些是需要沉淀的重要结论。比如我们在对话里说“这个项目以后都用 pnpm 安装依赖”,Claude 就很可能会调用存储工具把这条写进去;而如果是“今天天气不错”这种话,它一般不会收。
底层存储方面,claude-mem 通常使用 SQLite 这种单文件数据库。SQLite 的好处是部署简单,备份也简单,一个.db文件拷走就完事。为了支持语义检索,它还会为每条记忆生成向量嵌入(Embedding),并存储在一个单独的向量表里。嵌入模型可以在本地跑,也可以调用外部 API,这个我后面单独说。
2.2 记忆的提取:相似度检索 + 上下文注入
既然记忆是碎片化的,那关键问题就变成了“如何找到最相关的记忆”。claude-mem 的默认做法是向量相似度检索。给当前对话内容也生成一个向量,然后和记忆库里的向量做余弦相似度比较,返回得分最高的几条。
这个过程非常像搜索引擎的召回阶段。它不会尝试读懂整段对话,而是从对话中提取一个查询向量,再做近邻搜索。比如你在新会话里问“我们之前关于构建工具的结论是什么”,那这个句子的向量会和“项目里使用 pnpm”那条记忆的向量非常接近,于是被召回。
召回的条数很关键。claude-mem 一般允许你设置top_k,也就是最多注入几条记忆。默认值通常在 3 到 5 条左右。我一开始想,既然记忆库里可能有几百条,为什么不多召回几条?但其实每条记忆都以文本片段形式被拼到系统提示词里,召回太多会稀释真正重要的信息,还会占用输出预算。所以这里需要在“覆盖面”和“精确度”之间做平衡。
Claude 拿到这些记忆片段后,会基于它们和当前用户消息生成最终回答。等于说,claude-mem 的记忆是“软性”的,它不保证每条信息都绝对准确,只是给 Claude 一个很好的先验。Claude 如果发现记忆和当前对话矛盾,通常会用当前更明确的信息覆盖旧记忆,这其实挺合理。
3. 本地部署实录:一条命令装好、却卡在配置上的三个细节
有了原理打底,我们直接进入实操。claude-mem 这类 MCP 服务,安装本身通常很简单,真正费时间的反而在“连接客户端”这一步。下面是我在一台 macOS 机器上的部署过程,Linux 上差别不大,Windows 的话注意路径写法就行。
3.1 安装阶段
claude-mem 一般通过 npm 发布,所以先确保本机有 Node.js 18 或更高版本。我用的是npm install -g claude-mem做的全局安装,这样后续在任意目录都能直接调用claude-mem命令。安装完可以跑一下:
claude-mem --version如果能输出版本号,说明核心已经装好了。这里注意,如果你用的是 nvm 这类 Node 版本管理器,全局 npm 包安装到的路径可能不会自动加到当前 shell 的PATH里。我当时就遇到过命令找不到的情况,重启终端或者重新 source nvm 脚本就能解决。
3.2 配置 MCP 客户端
接下来要做的是让 Claude 客户端知道“有一个 MCP 服务可以使用”。不同的客户端配置方式不同,但原理都是要提供一个 JSON 配置,里面写上命令名和参数。
以 Claude Desktop 为例,配置文件一般在这个路径:
{ "mcpServers": { "claude-mem": { "command": "claude-mem", "args": ["serve"] } } }把这段配置合并到现有的 MCP servers 配置里,然后完全退出并重启Claude Desktop。只关窗口再打开往往不够,因为它可能不会重新扫描配置。这一步是我第一次踩的坑,改完配置后卡了十分钟,一直看不到记忆工具出现,后来才发现是没完全退出进程。
如果你是命令行用户,用 Claude Code 的话,还需要在项目或用户级别的.mcp.json里加同样的配置。相对麻烦的一点是,某些版本要求命令使用绝对路径,否则会找不到可执行文件。稳妥起见,我在配置里写的是:
{ "mcpServers": { "claude-mem": { "command": "/usr/local/bin/claude-mem", "args": ["serve"] } } }这里/usr/local/bin换成你自己which claude-mem输出的路径就行。
3.3 三个容易卡的细节
部署过程中我最想提醒的总共有三个细节,都不是文档里特别强调的:
第一个是MCP 服务缺省端口冲突。claude-mem 默认会在本地某个端口上起服务,如果你之前跑过其他 MCP 服务,占用同一个端口,新服务就会莫名失败。日志会让你摸不着头脑,因为不是权限问题,也不是依赖问题,就是端口被人占了。用lsof -i :端口号查一下就能发现,改用新的端口就好。
第二个问题是首次运行要初始化数据库。我原本以为装完包,直接serve就行,结果发现运行时会在用户目录下自动创建数据库,但是有些版本不给你提示,只会在日志里跳过初始化。我那次因为目录权限不对,导致数据库一直没建成功,整个服务处于“看似正常但没有任何记忆”的状态。后来我手动创建了数据目录,并且给足读写权限,再重启就正常了。
第三个细节是环境变量注入。如果你需要对 claude-mem 做一些内部配置,比如修改数据目录路径、换嵌入模型、调整 top_k,很多参数是通过环境变量输入的,而不是命令行参数。刚开始我死活找不到设置项,后来翻了项目源码才发现所有可配置项都集中在.env文件或 shell 环境变量里。这个属于典型的不看源码根本没想到的坑。
4. 调出“像老友一样懂你”的效果:检索参数、记忆沉淀与冷启动
部署完成只是开始,真正决定体验的是后续的调优。claude-mem 默认配置能跑,但距离“哇,它居然记得”这种效果,还需要我做一些针对性调整。
4.1 调整检索参数:top_k 与相似度阈值
先聊top_k。它决定了每次对话前最多会翻出多少条记忆。数字太小,比如 1,那它只能记住最像的一条,信息可能不完整;太大,比如 10,那系统提示词里会塞进好多历史片段,反而让 Claude 变得啰嗦,甚至把无关记忆当成背景信息引入回答。
我个人的经验是:日常闲聊场景可以用top_k=3,因为这时候对历史信息的依赖不高;在项目开发这种需要连续上下文的场景,调到top_k=5比较合适。如果你做的是需要大量背景资料的写作类任务,可以试到 7,但超过 7 之后收益会明显递减。
除了数量,还有相似度阈值。这个参数决定了“不够像”的记忆会不会被过滤掉。默认阈值如果是 0.0,那意味着任何记忆都会被考虑进来,只是按得分排序。这其实不太好,因为有些记忆相似度极低,纯粹是噪声。我把阈值调到 0.2 左右,低于这个得分的记忆就不注入上下文。这样 Claude 不会被冷门记忆打扰,检索质量会纯粹很多。
4.2 嵌入模型选型:本地优先还是 API?
向量嵌入是整个记忆系统的心脏。嵌入模型决定了记忆之间“相似”到底怎么定义。claude-mem 可以配置不同的嵌入模型,主要分两种路径。
第一种是本地运行的小模型,比如all-MiniLM-L6-v2这类 sentence-transformers 模型。它的特点是私密性好、无网络依赖,但维度比较低,对中文和多语言的支持一般。如果你日常主要是英文内容,它够用;一旦涉及大量中文表达,相似度检索效果会打折扣,因为中文语义距离在小模型上通常不如大模型那么准确。
第二种是调用云端嵌入 API,比如通过 OpenAI 的text-embedding-3-small或其他兼容接口。这能大幅提升中文和多语言的检索效果,缺点是需要联网、额外计费,而且把文本发到第三方。我是先在本地模型上跑通的,后来感觉中文检索总是差一点,换成云端嵌入模型之后明显更准。这里分享一个经验:如果你的对话本身就可能包含敏感信息,最好还是用本地模型;如果追求检索效果且对隐私不敏感,再考虑云端 API。
4.3 冷启动:让记忆库从零开始变活跃
刚装完 claude-mem 时,记忆库是空的,Claude 就算有工具也不知道该写什么,因为你说的每句话它都无法判断“是否有保留价值”。为了让它尽快进入状态,我会主动做一次“记忆播种”。方法很简单:开一个新会话,明确告诉 Claude 我的偏好、项目管理方式、技术栈,然后用指令让它把这些内容逐个写入记忆。
比如我会说:
请记住以下事实:我的项目目录是
~/work/blog-engine;前端框架用 React 18;后端用 Node.js + TypeScript;包管理器统一用 pnpm;代码风格是 2 格缩进;我每周五下午做版本发布。
随后 claude-mem 会收到若干次存储调用,记忆库瞬间就有了十几条基础事实。之后我再开正式会话时,它再也不会问我项目用的是什么框架了。这一步很重要,因为它跳过了最尴尬的“记忆空窗期”。
4.4 记忆沉淀的节奏控制
还有一个容易忽略的点:记忆库不是越大越好。如果 Claude 记住太多低价值信息,比如“用户某天说过某个包安装失败”,这类过期信息不仅没用,还会在检索时占据top_k的名额,把真正的重要结论挤出上下文。
我建议每隔一段时间清理记忆库,我自己的节奏是每周看一次。重点检查三类内容:
- 过期的决策记录,比如已经换掉的技术选型。
- 临时性的事件,比如某次报错、某个待办。
- 重复项,如果同一条事实被存了两次,保留新的即可。
claude-mem 提供了删除记忆的工具,但直接让它删可能不精确。我在清理时会用 SQLite 工具直接打开数据库,按照created_at字段筛选一条条看。虽然原始一点,但可控性最好。
5. 真实使用中踩过的坑:并发写入、中文分词与记忆膨胀
再好的设计,实际用起来也难免有坑。这个部分我把我遇到过的、以及根据项目讨论区看到的典型问题整理一下,希望你能绕过。
5.1 并发写入导致的 SQLite 锁冲突
MCP 服务可能会同时处理多个 Claude 请求,如果你同时开多个对话窗口,就可能有多个 Claude 实例并行写入记忆库。SQLite 对并发写支持一般,同一时间只能有一个连接写库,其他写操作会拿到一个“database is locked”的错误。
我当时是并行打开一个“日常问答窗口”和一个“代码开发窗口”,两边都触发了记忆写入,结果 claude-mem 的日志里连续出现锁冲突。解决方式很简单:给 SQLite 开启 WAL 模式,可以让读写并发性能好很多。我手动对数据库执行过:
sqlite3 memory.db "PRAGMA journal_mode=WAL;"开启之后,并发写入冲突的频率大幅降低。更彻底的做法是给 claude-mem 加一层写入队列,但那是项目级别的改动,普通用户只靠 WAL 基本够了。
5.2 中文内容的检索差距
前面提到嵌入模型对中文检索效果影响很大,这里展开说说。本地小模型在中文上出现的问题主要有两类:一是同义词召回不稳定,比如我说“包管理器”它能找到“pnpm”,但我说“装依赖的方式”它可能找不到;二是对中文短句的向量表达不够稳定,明明字面很像,语义却差很远。
我的解决方式是两层:第一,尽量让记忆里的文本自己包含更丰富的信息,不要存“使用 pnpm”,而是存“项目使用 pnpm 作为包管理器来安装依赖”。这样检索时,哪怕查询说法不同,向量空间里依然有足够多的关键词重叠。第二,如果条件允许,配一个中文效果更好的嵌入模型,比如 BGE-M3 或云端大模型嵌入接口。我在换到更适合中文的模型之后,“搜不到”的情况几乎没有了。
5.3 记忆膨胀如何把上下文“污染”
top_k 是拉取上限,但如果记忆库里本身就有大段大段的文本片段,每条都几百字,那么 top_k=5 就可能产生近两千字的注入内容。这些内容混在系统提示词里,可能会和当前用户消息争抢注意力,甚至让 Claude 偶尔从旧记忆里“脑补”出一些不存在的细节。
我遇到过一次特别典型的:我在对话里问它某个功能怎么实现,它居然把一条旧记忆中“之前我们用过 Redis 做一个缓存”的信息当作前提,然后开始长篇大论解释 Redis 缓存方案。但那次的提问其实是和 Redis 无关的。这就是记忆膨胀导致的检索误判。后来我给自己定了个规矩:存到记忆库里的每条内容尽量短,控制在 50 字以内,只保留结论性信息,少留过程性描述。50 字的限制看起来太死,但确实让最终检索精度高了很多。
5.4 数据备份和迁移
claude-mem 的数据就是一个 SQLite 文件,备份很简单。我会定期把这个文件复制到备份目录,或者打一个 tar 包。迁移到新机器时,除了把包装好,还要把这个数据库放到新机器对应的路径,再启动服务就行。唯一要注意的是数据库路径问题。如果你在新机器上没提前建好目录,服务可能不会自动创建,所以最好先手动mkdir -p相关目录。
6. 隐私与安全边界:本地优先的方案和可以继续折腾的方向
最后我想从隐私角度聊几句,因为“长期记忆”这个东西天然就牵扯到安全问题。记忆库一旦建立起来,里面可能包含你的真实姓名、工作单位、项目细节甚至代码片段。如果这些数据被上传到某个不可控的云端,风险是非常明显的。
claude-mem 的默认设计是本地优先。数据库文件存在你机器上,MCP 服务也跑在本地,Claude 和它之间的通信走的是本机协议。这个模式下,记忆数据理论上不会离开你的电脑。但要注意,如果你配置了云端嵌入 API,那么每条记忆在写入时会把文本发送到第三方接口做向量化。这等于说,有些本来只存在于本地的内容,其实已经经过了外部服务。我在用云端嵌入时,是把“敏感信息不进记忆库”作为底线,会在对话里告诉 Claude 哪些信息不要写入记忆,比如账号、密钥、个人身份证号等。
不过坦白说,靠 Claude 自己识别敏感信息并不可靠。更稳妥的办法是,在嵌入这一层做自定义转换,比如把敏感字段先替换成占位符再入库。这属于进阶用法,普通用户可能用不上,但对隐私敏感的开发者是值得考虑的。
关于“遗忘机制”,claude-mem 提供了删除接口,但它是显式删除,不会自动判断哪些记忆已经过期。我希望能看到更自动化的遗忘策略,比如按时间衰减记忆权重,或者定期把低访问频率的记忆归档。这些目前还没在主项目里看到,不过社区讨论中已经有人提了,未来的版本可能会有改进。
我也在想,如果再往下深入,claude-mem 很值得和知识图谱结合。现在的向量检索本质上是基于语义相似度的,它能回答“我之前提到过哪个包管理器”,但很难回答“我过去的项目里,哪些项目都用过 Redis,并且后来都换成了别的方案”。这种跨记忆的推理,需要把记忆结构化,而不只是文本片段。如果哪一天 claude-mem 支持把记忆抽成实体和关系,那它的价值会再上一个台阶。
回到实际体验,我自己现在已经把 claude-mem 集成进了日常开发工作流。最开始只是为了少重复几段背景说明,后来它慢慢变成了我的第二大脑。它不会主动告诉我它记得什么,但每次它准确地说出“你之前在另一个项目里用的是 pnpm,这次要不要也统一一下”的时候,我都会觉得这项目折腾得值。最后再分享一个小技巧:如果你也打算用,建议一开始就把“每个会话结束前让 Claude 总结本次对话要点并写入记忆”作为固定习惯。这个做法能极大提升记忆的沉淀效率,比你事后手动补录要省事得多。希望这篇记录能帮你少走一些弯路,尽快用上一个真正“懂你”的 Claude。