☰
给 Claude Code 装外挂记忆:claude-mem 接入与配置实战
2026/10/7 6:52:35 网站建设 项目流程

我第一次意识到 Claude Code 需要记忆,是在一个连续调了两天 API 对接的晚上。第一天下午我让它帮我厘清了鉴权流程、敲定了重试策略、还约定好错误码统一用业务码而非 HTTP 码;第二天早上打开新会话,它一脸茫然地重新问我"你们的鉴权方案是什么"。那一刻我明白了:这类工具再聪明,没有记忆就是"金鱼"。

后来我在 GitHub 上翻到 claude-mem 这个开源项目(npm 包名也叫 claude-mem),一句话概括就是:给 Claude Code 装一个本地优先的长期记忆系统。它能自动扫描对话里值得记住的信息,存进 SQLite 和 Markdown 文件,下次开新会话时把最相关的几条记忆自动注入上下文。这篇文章就是我折腾 claude-mem 三个月的完整记录,包含接入方式、配置调优和踩坑心得,适合所有用 Claude Code 又嫌它"记性差"的开发者。

1. 为什么 Claude 需要外挂记忆:会话隔离的痛点

1.1 每次对话都是"失忆状态"

CLI 形态的 AI 编码助手和网页聊天有一个本质区别:网页端你还能滚动历史记录找回上下文,CLI 端每次启动 claude 都是一个全新的进程,它只读得到当前会话窗口里的内容。上下文窗口是有限的,哪怕模型支持超大上下文,实际对话超过一定长度之后,早期的细节也会被挤掉或者被系统截断。更关键的是,会话之间的信息隔离是结构性的:上一次会话的结论、偏好、约定,默认不会带到下一次。

这不是某个模型的缺陷,而是产品形态决定的。如果每次 claude 都自动继承全部历史,多用户之间会串记忆,成本也会爆炸,所以各家都选择了"会话即边界"。问题就出在这:项目开发不是一次会话能完成的。你今天让 Claude Code 搭好了项目脚手架、确定了 pnpm + monorepo、把 eslint 配置改成了 strict,明天它不记得;你花两小时帮它"讲清楚"某个业务模块的来龙去脉,后天它又得重新听一遍。时间就这么被白白浪费了。

1.2 手动方案:CLAUDE.md 的局限

有朋友会说:"那我在项目里维护一个 CLAUDE.md 不就行了?"没错,CLAUDE.md 是官方推荐的记忆方案,我至今也在用。但它的核心问题是:它是写给人看的,也是人手动维护的。你写完初始版本之后,很少会记得在每次决策变化时同步更新它。于是它慢慢变成一个"过期的静态文件",甚至更糟——它记录了已经废弃的决策,反而误导后续会话。

而且 CLAUDE.md 是项目级的,颗粒度很粗。它适合写"稳定事实"(技术栈、目录结构、命令规范),但不适合记录"动态上下文"(这周我们在迁移数据库、当前有 3 个待办的接口、上次联调发现的缓存坑)。动态上下文变化快、数量多、时效性强,手动维护根本不现实。claude-mem 的切入点正是这里:它让工具自己从对话里提炼、按项目隔离存储、在新会话开始时按相关性注入。它和 CLAUDE.md 是互补的,不是替代。

维度CLAUDE.mdclaude-mem
维护方式手动自动
更新时效滞后,容易过期会话结束即时提取
粒度项目级稳定事实对话级细颗粒动态记忆
查询能力无SQLite 搜索 + Web UI
适合场景技术栈和命令规范决策、偏好、进行中的事务

1.3 我理想中的记忆系统应该长什么样

想明白痛点之后,我在接触 claude-mem 之前先给自己列了一个"理想记忆系统"的清单,后来发现这个工具几乎每一条都踩中了。这个清单也分享给你,方便你判断自己是否需要它:

  • 自动沉淀:不需要我手动写笔记,工具自己从对话里提炼。
  • 可解释:它记住了什么,我能直接看到、能手动改,不是黑盒。
  • 按需注入:不是把所有历史都灌进上下文,而是按当前项目和任务挑最相关的。
  • 本地优先:记忆数据存在我自己的机器上,不是必须传到某个云端。
  • 低成本接入:不改动我原有的 Claude Code 工作流,或者改动很小。

这套标准后来成了我判断所有"AI 记忆工具"值不值得用的框架,也是我推荐 claude-mem 时最常跟朋友讲的五条理由。接下来我拆解一下它到底是怎么做到的。

2. claude-mem 的记忆引擎:从对话里捞出值得记住的东西

2.1 扫描、提取、评分、存储的四步流水线

先给结论:claude-mem 的工作方式不是把聊天记录压缩一下存起来,而是一条完整的信息处理流水线。我读了源码和文档之后,把它概括成四步。

第一步,扫描。它会在合适的时机——通常是会话结束(Stop 钩子触发),或者你在 standalone 模式下结束对话后——把整个会话的用户消息和助手消息读出来。这一步不是傻存原始日志,而是为下一步的信息抽取准备原料。

第二步,提取。它借助语言模型能力从消息流里抽出"候选记忆"。什么样的话算值得记?我观察下来主要是三类,下一小节详细展开。这一步产出的是"可能有价值"的信息,还没经过筛选。

第三步,评分过滤。这一步很关键——不是所有提取出来的候选都值得进长期记忆。claude-mem 会对候选记忆做相关性和持久性打分,临时性的内容(比如"帮我看看这个报错")分数低,会被丢掉;长期约束和决策分数高,会被留下。这也是它没把上下文塞爆的原因。

第四步,存储。通过筛选的记忆写入本地存储,同时渲染成人类可读的笔记。你不需要去 parse 数据库,直接用 Markdown 文件就能看到模型记住了什么。

我有一个印象很深的例子。某次对话里我跟 claude 说"这个接口暂时不要缓存,后面会重构",它没有当成一句普通指令,而是提取成一条"项目状态"类的记忆,标注了关联文件。过了四天我再开新会话让它动那个接口,它主动提醒我"这个接口之前决定暂不缓存,如果现在改动涉及缓存策略,建议先确认重构计划"。那一刻你真的会觉得:它不是在翻聊天记录,而是在用记忆。

2.2 什么样的信息会被记住:三类典型记忆

我用了三个月,发现 claude-mem 实际能识别并记住的信息大致可以归为三类。这不是官方文档的原话,是我的总结,你可以拿这个框架去对照它提取出来的笔记,基本能对上。

第一类是显式偏好和约束。比如"这个项目一律不用 lombok"、"我习惯函数名用动词开头"、"commit message 要用 conventional commits"。这类信息的特点是:用户主动说出来,带有强烈的主观倾向,而且影响后续所有相关任务。

第二类是项目层面的决策。比如"我们选 PostgreSQL 是因为团队熟悉且预算有限,暂时不上 ClickHouse"、"前端组件库统一用 MUI 不用 Ant Design"。这些决策本身可能只出现在某一段对话里,但它决定了后续很多技术选型的方向。没有记忆的情况下,你两天后可能就得重新跟 AI 解释一遍,很烦。

第三类是跨会话的状态跟踪。比如"当前生产环境跑的是 v2.3.1,下周要升级 v2.4"、"订单模块还有两个已知 bug 没修,不要在联调环境动那块逻辑"。这类状态时效性最强,也最容易在会话切换后丢失。claude-mem 能把它们提取出来,在新会话里继续作为背景信息存在,这对多会话协作开发帮助非常大。

记忆条目在存储层大概是这样的结构(具体字段随版本变化,但核心字段一致):

{ "id": "mem_8f3a...", "type": "decision", "content": "使用 PostgreSQL 作为主数据库,原因是团队经验丰富且预算有限", "source": "session_2025-01-15T10:30:00Z", "relatedFiles": ["backend/db/schema.sql"], "createdAt": "2025-01-15T10:30:00Z", "score": 0.87 }

有了 type 和 score 字段,它后面做相关性匹配和注入排序就有了依据,不是纯靠关键词搜索。

2.3 本地存储:为什么用 SQLite 还要保留 Markdown

存储这块我一开始觉得多此一举:"有 SQLite 了还要 Markdown 干嘛?"但用了一个月才明白,这是它设计里很聪明的一点。

SQLite(通常放在~/.claude-mem/或项目目录的_mem/下)负责结构化存储和快速检索。每条记忆有类型、内容、来源会话、关联文件、时间戳等字段,搜索和相关性匹配都在库上完成,查询效率比翻聊天记录高好几个数量级。而 Markdown 笔记是给人看的"审计日志"——你可以直接打开_mem/notes/里的文件,看到 AI 记住了什么、记录得对不对。这解决了记忆工具最要命的一个问题:可解释性。如果记忆是黑盒,它给你注入了一个错误记忆,你根本不知道去哪改;有了 Markdown 文件,你随手就能编辑、删改、打标记。

我目前项目里的结构大致是这样:

. ├── CLAUDE.md └── _mem/ ├── memory.db ├── notes/ │ ├── 决策_数据库选型.md │ ├── 偏好_接口命名规范.md │ └── 状态_生产环境版本.md └── sessions/

memory.db是检索核心,notes/是人工可读的记忆索引,sessions/是会话摘要。这个结构直接决定了它后面注入上下文的策略:注入的是按"记忆文件中提取的结构化条目"来的,不是把整个 Markdown 文件丢进上下文。

3. 安装与三种接入方式:从试用到深度绑定

3.1 安装与环境要求

claude-mem 是一个 npm 包,安装非常直接。要求 Node.js 18 LTS 或更高版本,macOS、Linux、Windows 都能跑(Windows 建议用 WSL,因为和 Claude Code 的 shell 集成更顺畅,我自己不是 Windows 重度用户,但看 issue 区讨论大概是这样)。

npm install -g claude-mem

如果你还不想全局安装,临时体验可以直接走 npx:

npx claude-mem@latest

这里有个细节:这个工具更新挺勤快的,版本迭代经常会加新配置项和修复 bug。你要是发现某个命令行为和你搜到的教程对不上,先看看是不是版本问题,npx claude-mem@latest能保证你跑在当前最新版。

3.2 方式一:standalone 模式,一条命令感受记忆

最简单的接入方式是完全脱离 Claude Code 的原有启动流程,直接把 claude-mem 当入口:

npx claude-mem@latest

这句命令会做三件事:初始化当前目录的_mem/存储、按已存的记忆生成启动上下文、然后拉起一个带记忆的交互式会话。你在这个会话里正常和 Claude 对话,结束之后 claude-mem 自动扫描并提取记忆。

这个模式的优点是零配置、开箱即试,适合先体验一下"有记忆"是什么感觉。缺点也很明显:它绕过了 Claude Code 原生的很多配置和管理方式,如果你已经有一套复杂的 Claude Code 工作流(比如自定义 slash command、MCP 服务、复杂的 settings.json),就会觉得 standalone 模式有点"平行世界"。

我的建议是把 standalone 当成"试用模式",跑一两个项目感受记忆效果,真正要长久用还是接下来说的 hook 模式。

3.3 方式二:hook 模式,和 Claude Code 深度绑定

如果你已经习惯claude命令直接干活,那 hook 模式是更平滑的接入方式。它的思路是:不动你的启动流程,只在 Claude Code 的钩子事件里挂 claude-mem 的脚本。

在项目根目录的.claude/settings.json里配置:

{ "hooks": { "SessionStart": [ { "hooks": [ { "type": "command", "command": "claude-mem hook sessionStart", "timeout": 10 } ] } ], "Stop": [ { "hooks": [ { "type": "command", "command": "claude-mem hook stop", "timeout": 10 } ] } ] } }

配置之后,每次你正常输入claude启动会话,SessionStart 钩子就会触发,claude-mem 会从存储里挑出与当前工作目录最相关的记忆,注入到会话上下文中。对话结束(Stop 钩子)时,它再扫描这轮对话,把新的记忆提取入库。整个过程不需要你切换命令,感知上就是"原来的工作流没变,但 Claude 突然记得你了"。

我第一次配完跑了一个会话,第二天重新打开 claude 问它"我们昨天说的那个缓存方案你还记得吗",它居然能完整复述出来。那一瞬间你会觉得这套配置值了。如果你不想手写 JSON,也可以试一下claude-mem setup,部分版本支持自动往 settings.json 里写钩子配置。

3.4 方式三:search / notes / web,把记忆当外脑用

记忆不只是用来注入上下文,它本身也是资产。claude-mem 提供了一套检索和管理界面。

claude-mem search "数据库选型"

这个命令会走 SQLite 检索,返回匹配的记忆条目和来源。比翻聊天记录高效太多,特别是项目大了之后,很多决策你自己都忘了当时怎么定的,一搜就有。

claude-mem notes

查看当前项目或全局的笔记列表。如果想可视化地看记忆之间的关联(比如哪些记忆来自同一个会话、哪些文件被反复提及),可以启动 Web UI:

claude-mem web

跑起来后会本地起一个服务,浏览器里能看到记忆的图谱化视图。我最初觉得这个功能是花架子,后来调试注入效果时发现很有用:它能让你一眼看出某条记忆是不是污染了多个会话,方便清理。

4. 配置项实战:context 注入、过滤与噪音控制

4.1 上下文注入不是越多越好:maxFiles / maxResults / minScore

记忆注入最大的风险是"好心办坏事"——注入太多记忆,把宝贵的上下文窗口占满,Claude 反而抓不住重点。所以 claude-mem 的默认策略是保守的:不是把库里所有记忆都塞进去,而是按相关性挑一小批。

核心配置项是这几组:

context: enable: true mode: "auto" maxFiles: 5 maxResults: 5 minScore: 0.5

maxFiles控制注入的记忆来源文件数上限,maxResults控制最后实际注入的记忆条目数上限。我实测下来,maxResults: 5在大多数场景是够用的——项目级的稳定事实都在 CLAUDE.md 里,动态记忆 3~5 条正好。如果调到 8 以上,你会发现 Claude 在回答时明显变得更"啰嗦",因为它试图把那些不相关的记忆也圆进对话里,回答焦点反而散了。

minScore是相关性阈值,低于这个分数的记忆不会注入。调它的时候要注意:设太低(0.2 以下)会把一些边角料带进来,Claude 容易被无关信息带偏;设太高(0.8 以上)又会漏掉真正有用的内容。建议从默认值开始,用一段时间再根据实际效果微调。

提示:如果你在调试"为什么某个记忆没被注入"这类问题,先别急着调参,把日志级别开到 DEBUG 看一眼检索结果,往往比猜配置高效得多。

4.2 中文对话的记忆识别:mapping 与 mute 配置

claude-mem 最初的设计更贴合英文场景,但中文对话同样能用,前提是把身份映射配好。它需要知道对话里哪些内容属于用户、哪些属于助手,但中文里人称代词经常省略,工具容易搞混"我"到底是用户还是 AI。这就是extract.mapping配置的作用:

extract: mute: false mapping: user: ["我", "用户", "user"] assistant: ["你", "assistant", "AI"]

把中文语境里指代用户的词映射上去之后,提取准确率会明显提升。另外,如果你不希望每次会话结束都弹一堆"已提取 N 条记忆"的日志干扰视线,把extract.mute: true打开就行,它仍然在后台提取,只是不打扰你。

我的项目比较特殊,会有多个协作者通过同一台开发机跑 Claude Code。这时候 mapping 配置要更小心,最好把配置放在项目级而不是全局,避免不同用户的偏好被混进同一个记忆库。这个细节我一开始没注意,后来发现记忆库里多了不少陌生人的偏好,手动清理了一轮才恢复正常。

4.3 日志级别与存储位置:调试的两个抓手

配置里还有一组容易被忽略的项,但它们决定你能不能快速定位问题:

logLevel: "INFO" verbose: false

遇到"明明有记忆却不注入"这种诡异情况时,先把logLevel调到DEBUG,然后开一个会话看输出。你通常能在日志里看到它到底检索到了哪些记忆、为什么某些记忆被过滤掉了。我遇到过一次纯粹是minScore阈值设太高,导致所有记忆分数都够不着注入门槛,日志里全是被过滤的条目,一眼就看出问题了。

存储位置方面,全局配置默认在~/.claude-mem/,项目级记忆在项目_mem/目录。如果你在公司电脑上不想用默认路径,可以通过环境变量改存放目录。这个细节在团队协作时很实用——把存储目录指到项目内并纳入.gitignore管理,团队成员各自维护本地记忆,互不污染。

5. 用了三个月后:我的配置、踩过的坑和清理节奏

5.1 多项目隔离:记忆最怕"串台"

claude-mem 记忆按项目隔离,是我用过之后体会最深的一条原则。如果你所有项目共用一套记忆库,A 项目的技术选型和 B 项目的约定会混在一起注入,Claude 会进入一种"精神分裂"状态——刚才还在用 A 项目的框架回答问题,转眼又把 B 项目的术语塞进来。

我的做法是:每个项目都用 hook 模式绑定自己目录下的配置和记忆,全局只放公共偏好(比如我不喜欢冗余注释、提交信息用 conventional commits)。项目内_mem/加入.gitignore,避免把本地记忆提交到仓库。如果你实在要全局共享,至少要在配置里把注入的mode设为按当前目录过滤,别让记忆跨项目乱跳。

还有一个容易被忽略的点:如果你把同一个项目 clone 到不同目录开发(比如一个目录是~/work/project,另一个是~/tmp/project-backup),它们默认会被当成两个"项目",记忆不互通。这时候要么接受隔离,要么手动让两个目录的配置指向同一个存储位置,看你的工作流需要哪种。

5.2 误记忆和过时记忆:定期清理比你想的更重要

记忆工具的另一大坑是"记错了还一本正经"。有时候模型的提取会出错,把某次对话里的临时讨论当成项目决策存了下来;有时候决策变了,旧的记忆还躺在库里。如果不清理,这些错误记忆会在每次会话注入时反复误导 Claude,而且你会很困惑——它为什么老是在提一个你早就不当回事的方案?

我的清理节奏是:每周末抽五分钟claude-mem notes扫一遍新生成的笔记,发现明显错误的直接删对应 Markdown 文件(数据库会重新索引);过时的记忆我一般不是删掉,而是在笔记里标注"已废弃",这样未来如果需要回溯历史,还能查得到。claude-mem web在这里也帮了大忙,图视图里能看出哪些记忆长期没有被注入使用,那些就是优先清理的对象。

提示:删除 Markdown 笔记文件之后,如果 SQLite 里还残留旧条目,可以重新跑一次 scan 或按界面提示同步索引。不同版本的处理方式略有差异,我自己的习惯是只通过 claude-mem 自己的界面和命令做删除,避免直接改数据库文件导致索引不一致。

5.3 和 CLAUDE.md 的分工:稳定事实进文件,动态上下文进记忆

用到现在,我对 claude-mem 在整个"记忆体系"里的定位越来越清楚。我现在是这样分工的:CLAUDE.md 只写长期稳定的事实(技术栈、目录结构、构建部署命令),claude-mem 负责动态上下文和过程性决策(这个版本改了什么、下周要做什么、为什么选这个方案),两者重叠的部分很少。

这个分工有一个额外好处:CLAUDE.md 因为只放稳定内容,改动频率大幅下降,它反而更不容易过期了。而动态记忆虽然变化快,但 claude-mem 会自动更新,不需要我花精力维同步。以前我每两天就要改一次 CLAUDE.md,现在可能一周才动一次,而且每次改都是因为真的有稳定的约定变更。

5.4 团队协作与隐私边界

最后聊一个很多人容易忽略的话题:团队协作和隐私。claude-mem 默认是本地优先的,记忆数据存在你自己的机器上,这是一个很好的默认。但如果你的项目有保密要求,还是要注意确认记忆提取动作是否调用了云端模型。有些配置下,信息抽取能力可能走模型 API,落地前仔细看一下官方文档的隐私相关说明,别把敏感代码决策记到不放心的地方去。

我现在的做法是:公开的开源项目随便用默认配置,内部商业项目把记忆提取相关的网络行为都确认过一遍,确认数据不出本地之后才会放开用。这点多花十分钟检查,后面能避免很多麻烦。

最后再说两句

说实话,我最初只是把 claude-mem 当个"自动记笔记的小工具",用到现在,它已经成了我工作流里和 CLAUDE.md 并列的一层基础设施。我还是会手动维护 CLAUDE.md,但"事无巨细都得我管"的日子已经过去了——记忆这种事,交给工具自动沉淀,省下来的时间可以用来思考真正的问题。

如果你也被 Claude Code 的"金鱼记忆"折磨过,我建议你从 standalone 模式试起,跑一两个项目感受碰撞;觉得靠谱再上 hook 模式。记住一点:工具只是记忆的外壳,定期整理和清理,才能让它真正替你记住该记住的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询