
用 Claude Code 干活久了你多半碰到过这个场景上一个会话里刚把项目的数据库结构、技术栈、部署流程聊明白结果新开一个会话它又一脸懵地反问“请问这个项目用的什么框架”。别笑这不是模型变笨了而是 Claude Code 的每个会话上下文天然隔离——关掉终端记忆就归零。claude-mem 这个开源工具就是来解决这件事的它把会话中的对话、结论、项目约定沉淀到本地数据库里下次新会话里让 Claude 自己检索历史记忆实现跨会话的长期记忆效果。这篇东西适合两类人一是被 Claude Code 重复解释问题折磨的日常用户二是想搞清楚“如何给大模型对话系统接外挂记忆”的实现派。我会从机制到配置到踩坑一条条讲清楚。1. 先搞明白 claude-mem 到底解决了什么问题1.1 Claude Code 的“失忆”根源很多人第一次用 Claude Code 时都会产生一个错觉它跟网页版 Claude 一样记得我之前说过的话。但实际上不是。网页版聊天窗之所以看起来有记忆是因为 Anthropic 把整段历史都留在同一个会话里用上下文窗口硬撑而 Claude Code 在终端里每跑一次claude就是开启一个全新的、干净的一次性会话老的对话记录不会跟着进到新的对话窗口。哪怕你昨天刚让它改完支付模块的 API 签名今天新开会话它连这个项目叫什么都得重新问。这种设计本身是合理的。上下文窗口有长度上限而且每次会话开始时如果系统把之前所有历史都塞进去一方面浪费 token另一方面大量无关信息反而会干扰模型对当前任务的理解。所以 Claude Code 官方提供的会话恢复机制是“手动指定恢复某个历史会话”比如claude --resume让你选择上次的会话或者用--continue接着最近一次会话继续聊。但问题在于没人会天天带着上次的尾巴干活更多时候你是今天想解决一个新的小需求却要重新解释一遍项目的背景约定。这种“重启即失忆”的痛点就是 claude-mem 存在的理由。1.2 claude-mem 的核心价值给会话装一个外置记忆硬盘打个比方Claude Code 本身是个脑容量有限、且每次工作都清空脑子的临时工。你说一遍项目规范他当场是明白的但第二天你就得再说一遍。claude-mem 做的事情很简单——给他配了一个记事本和一套检索系统。这个记事本不在模型脑子里而是在你本地磁盘上是一条独立的、可以跨会话读取的记忆通路。具体到使用效果你在一个会话里和 Claude 讨论清楚了“订单号统一用 order_no不要用 orderId”claude-mem 会把这条信息作为一条记忆向量化存入本地库。等你下次开新会话Claude 会通过 claude-mem 提供的工具查到这条记忆然后在回答新问题之前自动带入“订单号字段叫 order_no”这个背景。你不用重新解释它也能在正确的轨道上干活。这就是“外置记忆硬盘”的感觉——模型本身没记性没关系硬盘有记性就行。核心价值再浓缩一下就三点第一跨会话叙事连贯省去大量重复沟通第二记忆可检索不是全量塞给模型而是按当前任务语义筛选最相关的历史信息第三存储走本地数据归属清晰隐私边界自己掌控。这三点是后面所有技术细节展开的出发点。1.3 和 RAG、MEM0 这类方案有什么不同提到“给大模型加记忆”你肯定听说过 RAG检索增强生成和 MEM0 这类方案。很多人问我说 claude-mem 是不是就是给 Claude Code 套了一层 RAG。答案是也不全是。RAG 的核心是把文档切成块、向量化、建索引用户提问时检索相关文档片段然后拼到上下文里。注意RAG 检索的对象是“你的知识库文档”比如接口文档、公司 wiki、产品手册。而 claude-mem 检索的对象是“你和 Claude 之间发生过的对话本身”是你们协作过程中产出的结论、偏好和决策记录。这决定了它更适合承载“交互型记忆”而不是“知识型问答”。MEM0 这类通用记忆框架则更偏“给应用开发者提供的记忆中间件”它要接入的是你自己的产品后端跟你是不是用 Claude Code 没关系。而 claude-mem 是从 Claude Code 这个特定工具的生态里长出来的它深度绑定 Claude Code 的 Hook 机制和 MCP 协议安装方式也是围绕 Claude Code 的配置体系设计的。换句话说RAG 是让模型会查资料MEM0 是给开发者一套记忆组件claude-mem 是让 Claude Code 这个工具本身长记性。三者着眼点完全不同不存在谁取代谁反而可以叠加用。2. 架构拆解四个关键零件很多人拿到 claude-mem 第一反应是“又一个 mcp server”。这么理解不算错但要真正把它用好、出了问题能排查你得把它的工作链路拆开看。我习惯把它分成四层捕获层、提取层、存储层、服务层。下面一层层说。2.1 Hook 层在对话发生的瞬间截获数据Claude Code 有一套 Hook 机制简单说就是系统在特定事件发生时会调用你预先配置的外部命令并把事件相关内容以 JSON 形式传给这个命令。claude-mem 用的主要就是用户提交提示词这个时机也就是UserPromptSubmit事件。每当你在终端里敲下一段话发给 ClaudeHook 就会触发一次claude-mem 被唤起。这里有个关键细节单一的用户提示词事件本身只包含你输入的文本Claude 的回复你是拿不到的。那 claude-mem 怎么能存下完整对话呢奥秘在于 Claude Code 会在事件里附带一个transcript_path指向当前会话的转录文件路径。这个文件是 JSONL 格式逐行记录了会话中的每条消息包括用户输入、Claude 回复、工具调用结果。claude-mem 读取这个文件按行解析就能拿到一轮完整对话的双方内容。这也是为什么它能在不侵入 Claude Code 源码的前提下实现对话捕获——它走的是官方留好的缝。选择在这个层级做捕获好处是显而易见的你不需要改 Claude Code 的任何配置也不需要在代码里埋点只要在settings.json里把 Hook 命令写上它就安静地在后台运行。坏处则是Hook 的触发时机、传递参数和转录文件格式都是 Claude Code 内部行为版本升级后有可能变化。所以 claude-mem 通常会对齐主要版本做适配你使用时如果突然发现记忆不更新了第一个怀疑对象就应该是 Claude Code 最近是不是升过级。2.2 提取与向量化不是全文都存成向量捕获到对话之后紧接着的问题就是怎么存一种做法是把每一轮对话原文都塞进数据库查询时做关键词匹配。这种方案不是不行但它有明显的弊端——大量寒暄、调试过程、报错信息都是噪声你真正需要记住的是结论性内容。而且纯关键词匹配没法处理“说法不同但语义相近”的情况。claude-mem 选择了另一种路线先提取再沉淀。具体来说它会对截获的会话片段做信息抽取识别哪些内容是值得长期保留的“记忆点”。这些记忆点是结构化的通常包括对话发生的项目、涉及的关键实体、得出的结论或约定以及提取时间等元信息。提取这一步本质上也在调用大模型来完成所以会有一层 LLM 调用开销。项目文档里通常会允许你配置提取用的模型比如继续使用 Claude也可以换成别的兼容接口这步做得越精细后续检索时记忆的精确度就越高。提取完之后再对记忆做向量化——把文本转换成一组浮点数组让语义相似的文本在向量空间里距离更近。存储和检索时用的都是这组向量而不是原始文本。不过原始文本还会留一份在库里供向量检索命中后展示给 Claude 阅读。这个“提取 向量化”的组合拳决定了 claude-mem 的记忆不是流水账而是一张经过提炼的要点卡。2.3 存储层轻量级 SQLite 向量索引存储层没有用重型的向量数据库比如 Milvus、Weaviate、Qdrant 这些而是很务实地选择了 SQLite 配合本地向量扩展。这一点我特别欣赏。原因很简单Claude Code 的使用场景绝大多数是个人电脑或者小型开发机并发量低单机这个量级完全够用而引入独立向量数据库意味着要多维护一个服务进程安装复杂度、资源占用都会成倍上升。SQLite 则零配置单文件备份就是把文件一拷。在这个架构下记忆数据落在两个层面一是传统的结构化字段比如项目路径、会话 ID、创建时间、记忆内容原文这些用 SQLite 的普通表就存了方便按条件过滤二是向量字段存浮点数组交给 sqlite-vec 这类扩展来处理相似度检索。查询时先按候选范围过滤比如只看当前项目、限定最近时间窗口再对筛出的记忆计算余弦相似度返回与当前问题最相关的前 N 条。这里要提醒一句很多人以为向量检索就是把所有样本都算一遍相似度其实不是。真实场景里数据量大了以后完全暴力扫描会慢到没法用。sqlite-vec 支持建向量索引来加速 top-K 查询但前提是你插入数据的时机要正确而且索引的维度要提前确定好不然中间改维度会非常痛苦。这个坑我后面专门讲。2.4 MCP 服务层让 Claude 自己查记忆前面三层解决的是“记忆怎么写进去”服务层解决的是“记忆怎么被读出来”。claude-mem 以 MCP Server 的方式常驻运行Claude Code 作为 MCP 客户端连接它。MCP 的直观理解就是给 Claude 插上一批可调用的外部工具箱。工具箱里的每个工具都有名字、参数说明和返回格式Claude 在对话中会根据当前任务判断是否需要调用某个工具并等待工具返回的结果再组织回答。在 claude-mem 这个场景里MCP Server 暴露的工具主要分两类一类是写入工具比如把一条重要结论主动存为记忆另一类是查询工具比如“根据当前问题检索相关记忆”。会话开始时Claude 可以默认先把“当前项目有哪些历史约定”这种宽泛记忆拉出来也可以根据任务中途按需查询。这个设计非常灵活记忆不是每次都全量注入而是按需触发token 开销可控而且 Claude 会自己判断哪些历史信息跟当前任务有关。有一个误传需要澄清claude-mem 并不是把整段历史会话都塞回到 Claude 的上下文里。事实上MCP 工具返回的内容是筛选后的摘要或片段通常按 token 预算做了截断Claude 看到的只是最相关的几个记忆块。这个度把握得好记忆才有用如果一股脑全倒给它跟直接把完整上下文塞进去没区别照样爆窗口。3. 从零到一把记忆链路跑通讲了半天机制下面进入实操环节。这节我按我实际的安装和配置顺序来写尽量不跳步。假设你已经装好了 Claude Code并且 Node.js 环境版本能支持 npm 全局安装建议 Node 18 以上。3.1 安装一个 npm 命令起步claude-mem 最简单粗暴的安装方式就是 npm 全局安装。包名就是claude-mem装完敲一下版本号验证是否成功npm install -g claude-mem装完之后跑一句claude-mem --version能看到版本号就说明基础环境没问题。注意如果你在安装时遇到 EACCES 之类的权限错误通常说明 npm 的全局目录没有写权限这时候别急着sudo更干净的解法是用nvm这类版本管理工具管理 Node 环境把全局目录放到用户目录下再重装。我见过不少同事因为贪图省事用了 sudo导致后面每次升级都要 sudo包更替时还会碰上部分二进制文件权限错乱的问题得不偿失。接下来执行初始化命令。这个命令会根据当前项目目录生成 claude-mem 自己的工作区配置文件并打印出后续需要补充配置的提示。不同版本的子命令名可能有差异我最稳的做法是直接看帮助claude-mem --help把命令列出来之后找到init或者setup那一项逐项执行。执行完当前目录下会出现一个.claude-mem之类的隐藏工作区里面存放数据库文件和运行日志。记住这个位置后面排查问题全用得上。3.2 配置 Hook 与 MCP Server安装只是第一步真正把写入和读取两条通路打通要改两处配置Hook 配置和 MCP 配置。先说 Hook。Claude Code 的 Hook 配置在项目的settings.json也可能是用户级配置文件里你要在hooks字段下注册一个UserPromptSubmit类型的监听事件命令指向 claude-mem 的某个子命令。大致长这样{ hooks: { UserPromptSubmit: [ { matcher: .*, hooks: [ { type: command, command: claude-mem collect } ] } ] } }collect这个动作就是读取当前事件带过来的转录文件路径解析对话抽取记忆写入数据库。注意这个命令本身执行速度要尽可能快因为 Hook 是同步参与对话流的如果拖太慢你终端上等待 Claude 回复的时间会明显变长。所以 claude-mem 内部通常会把耗时操作做成异步队列Hook 里只做轻量采集真正耗时的提取和向量化在后台线程完成。基于常见实践的补充如果在实操中发现敲完回车后系统卡顿明显优先检查是不是自己改了 Hook 命令、把后台逻辑同步化了或者把提取模型配置成了网络延迟很高的远端接口。再说 MCP。你要让 Claude Code 能连上 claude-mem 的 MCP Server需要在 Claude Code 的 MCP 配置里新增一条 stdio 类型的服务命令指向claude-mem mcp具体入口名以项目的 CLI 帮助为准。配置完成后重开一个 Claude Code 会话在对话里问一句“你现在能访问哪些记忆相关工具”如果配置成功Claude 会告诉你它有哪些记忆工具可用。这一步是整个链路里最容易出岔子的所以我强烈建议配置完先做一次工具可见性验证再谈后续效果。3.3 首次验证用一次对话测试完整链路配置完别急着开干花两分钟做一次端到端验证。流程是这样的新开一个会话故意说一句带有明确结论的内容比如“记住本项目所有价格字段统一命名为 price_cents”。这句话会触发 Hookclaude-mem 应当捕获并在后台开始提取。等几秒手动查一下数据库或者运行对应的查询命令确认那条记忆已经入库。这一步是在验证“写入链路 OK”。退出当前会话重新开一个全新的会话然后主动触发一次记忆检索比如问 Claude “本项目价格字段的命名约定是什么”如果它能正确答出 price_cents说明“读取链路 OK”。这一步走通你对 claude-mem 的信任感就建立起来了。后面再谈优化和调参就有底了不会再像无头苍蝇一样瞎试。实测下来整个链路首次跑通最花时间的反而不是配置而是模型提取那一层——如果当时用的是远端大模型接口每条记忆抽取要等网络往返测试时要有耐心。还有一个小技巧在验证阶段可以故意让对话内容包含精确、可验证的数字或代码片段这样检索结果正不正确一眼就能看出来不用靠感觉判断。4. 日常使用与调优安装配置跑通之后接下来就是真正用起来。这节讲三件我实际使用中最关心的事新会话里怎么让记忆自然起作用、记忆质量怎么控制、以及多项目数据怎么隔离开。4.1 新会话里怎么“想起来”有些朋友以为配好 claude-mem 之后新会话里的 Claude 会像失忆者突然恢复记忆一样自动把所有旧约定都想起来。其实不是。MCP 工具是“按需调用”的Claude 不会闲着没事就把记忆库全翻一遍。所以你在新会话开始时要么直接问一句“我们之前对这个项目有哪些约定”触发它去检索要么在提示词里带一句“先查一下历史记忆中跟这个任务相关的内容”。更聪明的用法是把这条指令固化到项目里的 CLAUDE 自定义指令文件里或者写成项目级模板让每个新会话默认就带上一句“开始前请先检查 claude-mem 中是否有与本项目相关的记忆”。这样一来Claude 大概率会在任务开始前主动调用记忆检索工具把相关背景捞出来。实测下来主动触发检索在准确率上的表现远远好过让 Claude 凭感觉决定什么时候查记忆因为模型对“何时该查记忆”的判断并不总是准有时候会漏有时候又会过度调用。另外要适应的一点是记忆检索结果不是每次都能派上用场。它返回的是“相关但不一定直接命中答案”的线索Claude 会结合当前上下文来判断怎么用。所以心态上不要把它当数据库精确查询而当成一张提示卡——它的价值是把你俩过去讨论过的结论重新端到桌面上让模型少走弯路。4.2 记忆质量的关键提取粒度、向量维度与检索阈值记忆质量是我调得最多的一块。先说粒度Claude Code 一个会话动不动就几十轮对话如果每一轮都抽一堆记忆库里存的全是碎片查询时噪声巨大如果一个会话只抽一条总纲又太粗细节全丢。我调出来的经验是按“主题片段”来切——比如围绕同一个函数改动的一系列对话归一个片段从里面抽结论性内容而不是逐条对话去抽。这个切分粒度通常是通过配置里的窗口长度参数来控制的你可以先从默认值开始观察几天库里记忆的稀疏程度再决定要不要调小或调大。然后是向量维度这块水很深。embedding 模型会把文本编码成固定维度的向量比如 768 维、1536 维。维度越高通常语义表达能力越强但计算量也越大。claude-mem 的向量库初始化时就会确认维度中途换模型、改维度会特别痛苦所以我建议你选定一个 embedding 模型后就不要轻易换避免推倒重来。基于常见实践的提醒如果你换了 embedding 模型旧记忆的向量和新向量不在同一空间里相似度检索基本失效这种情况只能重建索引或者干脆清库重来。检索阈值同样要看场景。阈值设高了检索结果少而精漏掉边缘相关的内容阈值设低了返回一堆不太相关的记忆稀释真正的有效信息。我个人的做法是先低阈值跑看完整返回结果再逐步调高找到一个“大多数查询都能返回 3 到 5 条有用记忆”的甜点值。这个甜点值跟你的对话风格、项目复杂度都相关没有统一的黄金数字。4.3 多项目隔离和团队共享Claude Code 本来就是按项目用的claude-mem 的记忆库也倾向于按项目隔离。同一个项目目录下的记忆存在一个库里换一个项目目录读取的就是另外一个库。这样设计是有道理的不同项目的技术栈、命名风格差异极大混在一起检索纯粹添乱隔离反而是效率最优解。实操上你不需要做什么额外操作只要你在不同的目录下跑 Claude Codeclaude-mem 会自动按当前工作目录定位数据库位置。如果你在子目录里打开会话记得确认工作区根路径正确否则可能出现“在子目录问了半天发现记忆库里啥都没有”的尴尬。团队共享场景下这工具的价值就更有意思了。一个小组几个人都改同一个项目每个人的本地记忆只属于自己claude-mem 不会自动共享。如果你的团队想统一记忆库最省事的方案是把工作目录建在共享盘上或者约定每个人都把项目 clone 到同一个相对路径下再通过同步手段把数据库文件同步到各终端。但这么做要非常小心并发写入冲突SQLite 对多进程同时写同一个库文件支持有限至少我实测下来两个人同时往一个库里写偶尔会报 database is locked。我不建议在团队场景下强撸一个共享库更现实的用法是每个人维护自己的记忆库但把项目级的约定文档沉淀到项目库里靠 claude-mem 补位而不是承重。5. 踩坑实录与排查速查下面这部分是我实际用了两个多月以后才攒出来的经验几乎每条背后都站着一个熬过的夜。我按“现象 - 原因 - 解法”列出来最后做成速查表。5.1 Hook 不触发先别怀疑工具最典型的坑是命令配置完看着没啥问题但对话结束后发现库里空空的。这时候别急着怀疑 claude-mem 不能用先确认 Hook 本身有没有被触发。最简单的验证方式是把 Hook 里执行的命令临时改成一行写入日志的脚本比如echo hook fired /tmp/hook.log然后跑一句对话看看日志文件有没有新增记录。如果日志没动静说明问题出在配置格式或者 Claude Code 版本不认这个事件名如果日志有动静但记忆库里仍是空的再往下一步查是不是 collect 命令路径不对是不是转录文件读取权限有问题还有一个容易忽略的点Hook 命令里如果用了相对路径而 Claude Code 发起 Hook 时的工作目录跟你预期的不同命令就会因为找不到文件而静默失败。这种失败通常不会报错给你看日志里也干干净净。所以我的原则是所有 Hook 命令都用绝对路径或者先把工作目录切换到项目根目录再启动 Claude Code。这个细节能干掉一半的“Hook 不生效”问题。5.2 检索结果明明不相关、或者啥都查不到如果说 Hook 问题算入门坑检索效果差才是真正磨人的。一种常见情况是库里确实有相关记忆但查不出来。我排查过几次后发现多数原因是向量维度不一致或者索引失效——比如中途换过 embedding 模型、或者数据库是从旧版本迁移过来的。这种情况下重新初始化向量索引往往能解决。另一种情况是记忆确实存了但检索时被其他条件过滤掉了比如时间窗口范围太窄或者项目路径匹配错位。这种就容易误判为“claude-mem 没用”其实它只是没被正确问到点上。另外检索效果还依赖你提问的方式。Claude 调用记忆工具时会发现内容并组织成一句话比如“看看我们之前对这个支付接口有什么讨论”。这种话说得越具体、越贴近当时讨论里的关键词检索效果就越好。反过来如果只是笼统地查“这个项目有没有约定”往往返回一堆低质量结果。我自己的习惯是重要任务前让 Claude 先用两三个不同的查询词分别检索然后汇总去重比单次检索靠谱很多。5.3 隐私、数据库膨胀与备份用 claude-mem 的过程中你一定会碰到一个灵魂拷问这些对话到底被谁看过了答案是默认情况下它存在本地不会上传到公共服务器。但有一点必须强调如果你配置的 embedding 或信息提取模型是远端的 API那么相关对话片段会根据 API 请求发送到对应服务商那边做推理。所以但凡项目里有敏感代码、商业机密你要么在配置里明确屏蔽这类内容要么干脆把提取和向量化都配置成纯本地模型比如通过 Ollama 跑本地 embedding。这条边界线决定了这个工具适不适合引入你的工作流。数据库膨胀和备份则是长期使用者的必修课。记忆是会积累的跑几个月之后我见过单项目库文件轻松超过几百 MB只要你把聊天里所有媒介内容都记下来。解决方案无非定期清理把已经失效的约定删掉把几个月前的讨论归档压缩必要时直接归档旧库文件、开一个新库重新积累。备份最简单把工作区目录打包拷贝就行恢复时放回原路径即可。注意一点备份和恢复要连同向量索引一起做只拷一份裸数据文件回来索引可能需要重建那就要多花时间。这个坑我踩过一次现在备份一律整个工作区目录走。踩坑速查表现象大概率原因处理建议Hook 不生效库为空配置格式错误、事件名不对、命令路径不对先用 echo 探针确认 Hook 触发再逐级排查检索结果不相关向量维度不一致、索引失效、提问词太泛重建索引改用多个具体查询词再汇总对话响应明显变慢Hook 里同步调用了远端模型确认提取向量化在后台异步执行降低网络请求频率多进程共享库报错SQLite 并发写限制按项目隔离库文件不搞多人强共享某个版本之后不再更新记忆Claude Code 升级导致 Hook 事件变化检查更新日志升级 claude-mem 对应适配版本库文件越来越大记忆碎片过多、备份内容过多设置清理周期归档旧库并重建这里想再多说一句关于排查心态的体会。工具链这种东西出问题时最忌讳的就是“感觉它坏了”然后一通乱试。像 claude-mem 这种数据链路比较长的工具最简单的排查方法就是沿着数据流方向逐个环节打点对话有没有被捕获有没有入库查询有没有命中命中后有没有被正确注入上下文。哪一步断了就修哪一步千万不要跳过验证直接改配置参数那样只会越改越乱。因为我自己吃过的亏反而是决策层面的多过于技术层面的。它终究是个记忆辅助工具不是全能记录仪。我身边有朋友把它当给 Claude 装“外脑”恨不得让 Claude 把所有决策都自动记下来结果库里的记忆越堆越多真正被 Claude 用回来的却少得可怜。后来我收敛了用法只在真正产生“约定”和“结论”的对话里留痕日常的调试流水账一概不管。这样记忆库才从玩具变成了可靠的生产辅助工具。最后再分享一个小技巧每天收工之前我会随手在当前会话里问一句“把今天聊出来的重要结论整理成几条记忆”然后让 Claude 调用写入工具固话一遍——这个动作的收益比我前面折腾任何配置参数都要多。