资讯详情

资讯详情

给Claude Code加长期记忆:claude-mem安装、原理与避坑指南

如果你跟我一样每天都开着 Claude Code 写代码那你一定经历过这种瞬间昨天刚跟它交代清楚这个仓库用 pnpm、组件样式必须走 design token、后端接口统一走 SWR 封装——今天新建一个会话它一脸茫然地看着你好像先前的一切都没发生过。一次两次还能忍天天重复交代背景人就开始烦躁了。我是在这种烦躁的驱使下找到 claude-mem 的。claude-mem 是一个给 Claude Code 添加“长期记忆”能力的开源项目。它不改变你原本的对话方式只是在你和 Claude 之间多了一层自动记录与主动回顾的机制每次会话结束后它会把值得记的内容摘出来存成结构化记忆下一次会话开始时再把相关记忆“喂”回给 Claude。装完之后Claude 至少能稳定记住三件事项目背景、你的个人偏好、以及之前拍板过哪些关键决策。这篇文章我会把一件事讲透为什么要给 Claude Code 加记忆、claude-mem 是怎么装怎么用的、它的内部工作链路是什么样的以及我自己跑了一个多月之后踩过的那些坑。不管你是刚接触 Claude Code 的新手还是已经靠它扛日常开发的老人下面这些内容应该都能直接用上。1. 最让我受不了的一件事Claude 每次开新会话就“失忆”先说说我是在什么场景下崩溃的。坦白讲Claude Code 刚出来的时候我非常兴奋因为它解决了我日常开发里大量“机械但需要动脑”的活。但用着用着我发现它的协作体验有一个巨大的断裂点会话内的记忆非常强会话之间却完全是零。这个断裂点会让你反复做无用功我至少碰到过三种典型情况。1.1 三个真实场景第一个场景是跨天开发。第一天我让 Claude Code 帮忙搭了一个 Node.js 服务端项目的脚手架目录结构、依赖选型、环境变量、甚至 lint 规则都是聊天聊出来的。下班前我看了一眼非常满意。第二天早上我想让它在这个项目里加一个请求日志中间件于是打开终端开了一个新会话把需求一说。它沉默了一会儿回复我“我没有在项目里找到相关的中间件目录请确认一下项目结构。”我确认什么这个结构就是它自己搭的。它只是忘了。第二个场景是偏好纠正。我习惯用双引号而不是单引号TypeScript 的类型定义喜欢写在接口里而不是 type 别名里组件我倾向用函数声明而不是箭头函数赋值。这些偏好我几乎每天都在向它重复。它不是学不会而是根本没有“学会”这个概念——每一次对话都是全新开始上下文清零我又要重新教育一遍。最让人沮丧的是它每次犯错的方式都一样就像第一天上班的实习生你上周说过的注意事项它一条都不记得。第三个场景是项目约定。比如我们的接口返回统一是{ code, data, message }这种结构错误码 401 必须跳登录页测试文件统一放在__tests__而不是test目录。这些约定我在不同会话里交代过不下十遍但它还是会在某个时刻写出一个{ status, result, msg }的返回结构然后自信地跟我说这是按项目风格写的。每次遇到这种时刻我都觉得我的时间被浪费了。如果你也在这三个场景里撞见过任何一个你应该明白我说的痛。1.2 为什么“上下文窗口变大”解决不了这个问题有人可能会想以后的模型上下文窗口越来越大干脆把所有历史都塞进去不就行了这个思路不能说错但它没抓住本质。大语言模型本质上无状态。每一次请求对模型来说都是独立的你发给它的任何内容都只是临时拼接的文本。Claude Code 之所以能在单个会话里记住前面聊过的话是因为它在会话内部维护了一套状态管理机制把之前的对话、工具调用结果、文件修改记录都重新组织成当前请求的上下文。一旦会话结束这套状态就清零了。上下文窗口再大也只是让“单次会话能装下的东西变多了”跨会话的记忆能力依然为零。也有人会说不是有 CLAUDE.md 吗把项目规范写进去Claude 每次打开项目都会自动读。这个方法我试过有用但它有明显的硬伤。第一它是静态的。你昨天临时拍板的方案、今天刚纠正的偏好CLAUDE.md 不会自己更新得你手动去改。第二它适合放“稳定约定”不适合放“动态记忆”。你不会为了“用户今天说不喜欢某种写法”这种临时偏好去改项目根目录的说明文档吧反正我不会太累了。所以想真正解决这个问题需要的是一个能跟着对话实时更新、并且在下一次对话开始时主动把相关内容翻出来的“记忆层”。当时我翻遍了开源社区最后选定的方案就是 claude-mem。2. claude-mem 到底在做什么一个挂在 Claude Code 边上的记忆夹层第一次看到 claude-mem 这个名字的时候我心里想的是又一个给 AI 加记忆的玩具后来仔细看了它的思路发现它不是简单地把聊天记录存成文本文件而是真的在 Claude Code 旁边搭了一个完整的记忆服务层。2.1 它的定位与核心能力claude-mem 的定位可以概括成一句话把 Claude Code 从“无状态工具”变成“有状态协作者”。它不改变你原本的提问方式也不改变 Claude Code 的代码生成能力只是在背后多了一层“自动记录 主动回顾”。它的核心能力拆开来看是这么几块对话记录通过 Claude Code 的 Hook 机制在每次助手输出结束后自动拿到这一轮对话的内容包括用户消息、助手回复、工具调用结果。内容摘要把原始对话交给模型做提炼沉淀成结构化的记忆条目而不是把几百 KB 的原文一股脑存下来。这一点非常重要直接决定了后面检索的效率。语义存储与检索记忆入库之后会做向量化索引。下一次无论是新会话开始还是对话进行中它都可以按语义相似度召回相关记忆而不是靠关键词死匹配。主动注入召回的记录会通过 MCPModel Context Protocol模型上下文协议暴露给 Claude。Claude 能在需要的时候主动去“回忆”而不是被动接收一堆无关信息。你可以把它想象成给 Claude 配了一个档案管理员。你和 Claude 在桌上讨论问题档案管理员就站在旁边听把有价值的对话内容整理成卡片存进档案柜。第二天你来了还没开口档案管理员已经把和当前项目相关的卡片都摆在了桌面上。2.2 它不是又一个 CLAUDE.md我一开始最大的疑问是这和 CLAUDE.md 有什么区别用了几天之后我得出了结论你可以把 claude-mem 理解成一个“动态的 CLAUDE.md”但它的能力边界比 CLAUDE.md 要宽得多。对比维度CLAUDE.mdclaude-mem内容来源手动编写对话自动提炼更新方式手动维护每次会话后自动更新注入策略每次全量注入按语义相关度按需召回内容类型稳定的项目规范动态的项目状态、偏好、决策记录适用场景技术栈说明、编码规范临时决策、用户偏好、任务进度我对这两个工具的定位是互补关系团队级别的稳定约定放在 CLAUDE.md 里适合“规定动作”而每天都在变化的项目状态、用户偏好、临时决策交给 claude-mem 这种记忆层来处理。前者管“应该怎么做”后者管“之前到底发生了什么”。2.3 一条完整的协作动线为了让后面几章的内容更容易理解我先给出一条完整的动线你看完会对它的工作方式有个整体印象你在终端里向 Claude 提问Claude 开始执行任务。一次完整的助手回复结束后Claude Code 的 Stop Hook 被触发调用 claude-mem。claude-mem 拿到这一步的对话内容发给模型做摘要与分类。摘要结果写入本地 SQLite 数据库并生成向量索引。下次你打开新会话claude-mem 会根据当前项目目录与对话主题在后台检索相关记忆。检索结果通过 MCP 工具暴露给 ClaudeClaude 可以按需调用比如“查一下这个项目之前用的是什么日志库”。Claude 在回复里自然地引用这些记忆你就不需要再重复交代一遍。这套动线看起来简单但每一环都有不少细节值得展开。下面我先讲安装再讲每一步背后的原理。3. 安装和接入三分钟把记忆插件装进 Claude Code安装部分其实比我想象的简单。claude-mem 设计得比较“傻瓜”核心就两步装包、初始化。但我还是要多说几句因为有一些安装后的坑我是在踩过之后才反应过来的。3.1 安装命令与 init 自动配置我当时的操作是全局安装这样可以跨项目复用npm install -g claude-mem claude-mem init这里我建议用全局安装而不是在单个项目里npm install。原因是 claude-mem 需要像一个系统服务一样挂在 Claude Code 的配置层如果装在项目里你切换项目就失效了。init这条命令会自动帮你完成几件事在 Claude Code 的用户配置目录下注册 Hook。Claude Code 的 Hook 机制允许你在特定时机执行外部命令claude-mem 会申明自己需要监听Stop和SubagentStop这两个时机。创建默认的数据库目录~/.claude-mem/初始化 SQLite 数据库。注册一个 MCP Server这样 Claude Code 才能发现 claude-mem 提供的记忆查询工具。如果检测到项目目录可能会顺手生成一份.claude-memignore模板方便你配置忽略规则。如果你用的是非默认的 shell比如 zsh全局安装完 npm 包之后建议确认一下claude-mem这个命令是否在 PATH 里。遇到“command not found”的时候多半是 npm 的全局 bin 目录没被 shell 加载把对应的路径加到 PATH 就好。这个不是 claude-mem 的问题是 npm 全局命令的经典坑。3.2 验证安装是否成功装完之后第一个要做的动作是确认记忆系统真的在运行。我每次在新环境装完都会执行claude-mem status这条命令会显示数据库路径、当前记忆条目数量、Hook 注册状态和 MCP Server 状态。如果你看到 hook 状态是 active数据库路径不是默认的~/.claude-mem/那我建议你留意一下是不是项目级配置覆盖了全局配置。接下来做一次真实验证随便开一个 Claude Code 会话跟 Claude 聊几句业务相关的内容让对方输出一轮完整的回复然后退出会话。再执行一次claude-mem status如果“记忆条目数量”从 0 变成了大于 0说明整个链路已经通了。这里有个小细节很多人会误以为聊天的“每一句话”都会被立刻记录。实际上 claude-mem 是在一轮完整的助手回复结束后才触发记录的所以你在它还在输出的时候切走或者用 CtrlC 中断了回复这一轮内容可能不会入库。这个逻辑后面还会细说。3.3 隐私保护和忽略规则记忆系统最让人担心的就是隐私。我把敏感项目接入之前先认真看了一下它的忽略机制发现它参考了.gitignore的思路整体上还算靠谱。你可以在项目根目录创建一个.claude-memignore文件语法和.gitignore基本一致# 忽略包含密钥的文件路径 .env *.pem # 忽略临时目录 /tmp/* # 忽略某些特定目录的对话 node_modules/除了文件路径claude-mem 还支持关键词级的过滤。比如你可以在配置里设置一些敏感词只要对话内容中出现这些词这一轮就不做摘要、不入库。我在本地配过类似token、password、api_key这样的词虽然粗暴但至少能挡住一部分误记录。还有一个容易忽略的点默认情况下记忆库是全局单库还是按项目隔离这个需要确认。如果你同时维护好几个项目我更建议按项目分开存储避免不同项目的记忆互相污染。这点我在第 6 章讲坑的时候会重点展开。4. 记忆的完整生命周期从截获对话到语义召回这一章我打算把 claude-mem 的工作链路拆开按“截获—摘要—存储—召回”四个环节来讲。理解了这四个环节你才能真正知道哪些场景适合它、哪些场景不适合它、以及出问题的时候该去哪里排查。4.1 截获Hook 在背后干的事Claude Code 本身提供了一个 Hook 机制让你在特定事件发生时执行自定义命令。claude-mem 主要依赖两个时机Stop每轮助手回复结束、轮到用户发言的时候触发。SubagentStopClaude 调用子代理Subagent执行完任务并返回结果时触发。为什么不用PreToolUse或者PostToolUse因为 claude-mem 想记录的是“一段完整对话”的语义而不是单次工具调用的输入输出。工具调用过程可能很碎比如一次搜索、一次读文件、一次写文件如果每次工具调用都入库记忆会变成噪音。我曾好奇过 Hook 是怎么把对话内容传给 claude-mem 的。查了一下它的实现发现 Claude Code 的 Hook 会把会话 ID、消息内容等通过标准输入传给外部命令。claude-mem 拿到这些数据之后会再调用一轮模型来做摘要。也就是说每一次会话结束背后其实还有一次额外的模型调用。这一点直接关系到你的 token 成本我会在第 6 章的坑里继续聊。4.2 摘要与结构化把对话“嚼碎”拿到原始对话之后下一步不是直接存起来而是做摘要。为什么要做摘要不存原文的原因很简单原文又长又杂直接存下来会占空间召回时还会把无关信息一起带出来。claude-mem 在做摘要时会把可记忆的信息尽量分成几类项目事实技术栈、目录结构、依赖版本、接口约定。用户偏好代码风格、命名习惯、喜欢或讨厌的写法。决策记录为什么选这个方案而不选另一个最后拍板的结果是什么。会话摘要这一轮会话做了什么、做到了什么进度、下一步计划是什么。每条记忆最终会带上一组元数据比如会话 ID、创建时间、项目路径、关联的文件路径。这些元数据决定了记忆在后续检索里的可过滤能力。举一个实际效果当你在一个项目里查“日志方案选型”的时候即使另一个项目也讨论过同样的话题因为项目路径不同它不会把两个项目的决策混在一起。4.3 存储SQLite 加向量索引存储层用的是 SQLite这是我很喜欢的一个设计。任何独立的 Python 脚本、Node 脚本都能直接打开这个文件备份就是拷贝一个文件不会有额外的基础设施依赖。核心表结构大致长这样CREATE TABLE memories ( id INTEGER PRIMARY KEY, type TEXT, -- project_fact / user_preference / decision / summary content TEXT, -- 结构化摘要内容 embedding BLOB, -- 向量表示 project_path TEXT, -- 项目路径用于隔离 session_id TEXT, -- 来源会话 ID created_at TEXT -- 创建时间 );向量索引的作用是支持语义检索。你搜索“我们数据库选型最后定的是啥”即使记忆原文里写的是“不用 MySQL改用 PostgreSQL”它也能通过向量相似度把这条记忆捞出来。如果只靠关键词匹配这种跨表达方式的检索基本做不到。4.4 召回新会话里它是怎么想起来的记忆存下去不是目的能被重新想起来才有价值。claude-mem 的召回设计走的是 MCP 路线。MCP Server 启动后会给 Claude Code 暴露一组记忆相关的工具比如search_memories、recall_memories。Claude 在对话过程中可以按需调用这些工具。调用时claude-mem 会拿当前的对话上下文去向量库里做 top_k 检索命中的记忆会返回给 Claude作为它回答问题的参考。这里有一个关键的设计选择记忆是“按需召回”不是“全量注入”。如果每次会话都把上百条历史记忆塞进上下文不仅浪费 token还会干扰 Claude 对当前任务的注意力。按需召回的思路更像人脑——不是把所有记忆都端到眼前而是遇到相关问题时再去翻档案。用过一段时间之后你会发现 Claude 的回复风格会有一个微妙的变化它开始会引用“之前讨论过的内容”而不是每次都用泛泛而谈的口吻回答问题。这种变化就是记忆层真正生效的信号。5. 实战用法怎么把记忆调到“刚刚好”的状态工具装好、原理摸清之后真正的问题是日常开发里怎么用才能让这套记忆系统发挥最大的价值这一章我写三个真实场景附带一些我自己摸索出来的操作技巧。5.1 三种最实用的场景场景 A隔了一周回来继续开发。我有个项目是周末维护的每次间隔一周。以前回来第一件事是翻之前的聊天记录、看代码注释、回忆我到底想做什么。装上 claude-mem 之后我回来直接跟 Claude 说“继续我们上次的工作先把当前进度梳理一下。”它调用了记忆查询工具把上周的会话摘要和决策记录捞了出来然后告诉我这个项目目前处于哪个阶段、下一步计划是什么。那种体验非常舒服就像同事帮你做了交接。场景 B纠正过一次的偏好不再反复踩。我有一段时间特别烦 Claude 在写 React 组件时默认用React.FC后来我连续纠正了它几次。有了记忆之后它在新会话里写组件时会主动规避这个问题甚至会在回复里补一句“按照你之前的偏好这里我没有用 React.FC。”我第一次看到这个补充的时候愣了一下然后意识到它真的把我之前随口说过的话记住了。场景 C跨会话的任务衔接。现在我会刻意在会话结束时跟 Claude 说一句“总结一下目前做了什么下一步打算怎么做。”这句话会让 claude-mem 的摘要质量更高。第二天开新会话我不需要从头讲需求只需要给它一个触发词比如“继续优化昨天的数据同步逻辑”它就能自己把上下文接起来。如果你不把这个钩子抛出来它也能存但摘要会显得更零散。5.2 怎么判断它到底记住了没有有时候你会不确定记忆是否真的进了库我常用的验证方式有三种直接问 Claude“根据你的记忆我们项目当前的技术栈和目录结构是什么”如果它答得上来说明相关记忆已被召回如果它答得模棱两可说明这条记忆可能没存上或者检索时没有被命中。观察 Claude 是否主动调用记忆工具。Claude Code 的界面里能看到工具调用记录。你问了一个只需要历史背景的问题它如果先调用了search_memories再回答说明记忆链路正常。手动查库。终端里执行claude-mem search 数据库选型可以直接看库里有没有相关内容。这个命令在排查问题的时候很有用可以帮助你区分“没存上”和“存了但没召回”。5.3 记忆调优频率、阈值、隔离跑了几天之后我开始觉得默认配置不够“锐利”于是做了一些调优这里几个参数是我实际验证过最有用的调优项我的推荐值说明摘要频率每轮 Stop 后实时性强但 token 成本高也可以改为每天只摘要一次省成本检索数量 top_k5 到 10太少会漏太多会混入无关记忆项目隔离按项目分库强烈建议避免多项目记忆互相污染忽略规则按目录和关键词配置把临时目录、敏感文件排除在外过期清理每周一次删除 30 天前的临时偏好与一次性决策关于检索数量我个人的体会是top_k不是越大越好。默认值如果召回 20 条Claude 的回答里会出现很多风马牛不相及的内容调成 5 到 10 之后回答明显更聚焦。当然这个值跟你的记忆库总量有关记忆库很大时可以适当上调一点。还要提一下 CLAUDE.md 和 claude-mem 的分工。我的做法是稳定的团队规范、编码规范写在 CLAUDE.md 里动态的项目状态、个人偏好、临时决策交给 claude-mem。两者不是替代关系而是互补关系。6. 跑了一个半月之后我想吐槽和提醒的事最后这部分我想聊聊不完美的地方。任何一个工具用久了总会踩到几个文档里没写的坑。claude-mem 也一样。6.1 我踩过的几个坑坑一Claude Code 更新会把 Hook 配置重置。这是我遇到最频繁的问题。Claude Code 升级之后Hook 配置可能被重置或者覆盖结果 claude-mem 悄悄停止工作了但你不仔细观察根本发现不了直到某天你发现 Claude 对历史项目完全不记得。解决办法是每次 Claude Code 更新之后顺手跑一遍claude-mem init让重新注册 hooks。坑二token 成本比想象中高。摘要需要额外调用模型每轮对话都会产生额外的 token 消耗。如果你一天会话非常多月底看账单会发现多了一笔不小的开销。我的对策是高频率对话的日常开发中把摘要频率调低只在开重要会话、或者需要跨天衔接时才让配置保持全量记录。坑三敏感信息被记进库。我有个测试环境不小心在对话里发了一个临时 token结果 claude-mem 把整段对话做了摘要包括那串 token 也在摘要里。后来我清理了库并且在移动端和敏感环境里把关键词过滤打开了。现在我的原则是默认情况下明确属于敏感类的信息坚决不让它进记忆库宁可让 Claude 当场忘掉也好过库里躺着一个随时可能泄露的密钥。坑四记忆库膨胀导致召回质量下降。跑了一个月之后我的全局库里塞了上千条记忆。这时候检索回来的 top_k 结果开始变乱经常返回一些与当前任务毫无关系的历史内容。后来我养成了每周清理一次的习惯把 30 天前的临时偏好和已完成任务的摘要删掉。对于一个持续演进的项目记忆应该保持精简。坑五多项目污染。早期我没有按项目隔离记忆结果在 A 项目里讨论的“不用 axios用 fetch 封装”会跑到 B 项目的回忆里。B 项目的代码环境跟 A 项目完全不一样Claude 却以为 B 项目也是这个约定。这其实是所有通用记忆系统的通病上下文如果不加边界模型就会张冠李戴。现在我把每个项目的库分开之后这个问题基本消失了。6.2 我的日常维护流程我现在的日常维护流程已经固定下来了分享给你参考每天下班前在 Claude Code 里说一句“总结今天的进度和下一步计划”让记忆摘要更有条理。每周执行一次claude-mem status看一眼记忆条目数并用claude-mem search抽查几条最近记忆是否有价值。每两周清理一次过期记忆。重要的项目决策记录和长期偏好留下一次性的进度总结超过 14 天后删掉。每次 Claude Code 更新后跑一遍claude-mem init重新确认 hooks 注册。这个动作几乎是无成本的但能避免“静默失效”。常用命令整理一下claude-mem init # 初始化/修复 hooks 与数据库 claude-mem status # 查看记忆系统状态 claude-mem search 关键词 # 手动搜索记忆库 claude-mem forget id # 删除某条记忆 claude-mem reset # 清空整个记忆库慎用6.3 哪些内容不建议交给它记最后关于“记忆边界”的思考。我见过不少人对记忆系统抱有过于美好的期望觉得什么都能扔给 claude-mem。我的建议是下面这几类内容尽量不要让它记密钥、密码、Token、个人信息。这类内容一旦入库就是一个潜在泄露点。一次性的临时需求比如“帮我把这个 JSON 转成 CSV不用保存”。记这种意义不大还占库容量。情绪化的偏好。你某天心情不好说了一句“再也不要用 xxx 框架了”这种话如果被当成长期偏好存进去几天后你会莫名其妙发现 Claude 对那个框架避之不及。我个人的体会是记忆系统有一个“度”的问题。记少了等于没装记太多、太杂检索质量会下降Claude 反而被噪音干扰。如果你也在天天跟 Claude Code 重复交代同一件事那我建议你先装上 claude-mem 试两天。装完之后当你看到 Claude 主动说出“根据你之前的偏好这里我做了这样的处理”的时候你会觉得之前那些重复的沟通成本都值得再花这一遍。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →