☰
claude-mem:给Claude Code接入跨会话长期记忆的实践指南
2026/10/9 3:55:40 网站建设 项目流程

每天打开一个新的 Claude Code 会话,你有没有一种感觉:这个 AI 又把我当成第一次见面的人了?项目背景要重新说明,代码风格要重新交代,连上一周刚讨论定的接口版本策略它也忘得干干净净。claude-mem 这个开源项目,就是冲这个痛点来的——它利用 Claude Code 的 hooks 机制,在会话结束时把关键信息提炼成结构化记忆,存进本地数据库,下一次会话开始时按需把最相关的几条注入上下文,让 AI 第一次拥有跨会话的长期记忆。如果你正在重度使用 Claude Code,或者准备给团队搭一套带"长期状态"的 AI 工作流,那这篇文章不是泛泛介绍,而是我从安装到上生产环境的完整折腾记录。

1. 为什么我在集成式AI工作流里加了一层"记忆插件"

1.1 会话隔离的代价:Claude Code 每次都像新人

Claude Code 天然就是"每开一个会话,从零开始"。这个设计本身没有错,隔离上下文能避免不同任务互相污染,但它有一个很扎心的副作用:同一个项目里,你上周已经和它讨论清楚的事情,这周又要重新解释一遍。我带过的团队里,几乎每个人都干过这种事——把项目背景、目录结构、接口约定、避坑指南,在会话第一轮用大段文字重新喂给 AI。然后第二周,再重复一次。

这不是用户不会用,而是工具的结构性缺陷。没有持久状态的 AI,就像没有 git 的代码库:你可以继续写代码,但没人记得上一次 commit 里改了什么、为什么改。当你同时在管三四个仓库、五六条需求线时,这个缺陷会被无限放大。我算过一笔账,按一天 8 小时严格使用 Claude Code 来算,每天至少有两成左右的 token 浪费在重复背景说明和纠正 AI 的"失忆错误"上。时间成本比 token 成本更贵——因为每次 AI 猜错项目约定,你都要停下来核对代码、翻文档、然后纠正它。

我自己试过用 CLAUDE.md 来缓解这个问题,把项目规则写在里面,让每个会话启动时自动读取。但它有两个天然短板:第一,CLAUDE.md 是静态的,你得手动维护;第二,它记不住"当时我们为什么这样决定"的语境,只有结果没有来龙去脉。真正的需求不是一份固定文档,而是一个能跟着项目进展不断更新的动态记忆层。这个记忆层要能回答三个问题:这个项目现在的约定是什么?上次讨论到哪了?哪些决定还没落地?

1.2 记忆插件的定位:不是"数据库",而是上下文过滤器

很多人的第一反应是:给 AI 加记忆,不就是把之前的对话全存下来,下次再一股脑塞给它吗?这个思路错得很彻底。上下文窗口是有限预算,你把一万条历史对话都塞进去,就算 Context 能装下,真正有用的信息也会被淹没,模型注意力被无关细节稀释,回答质量反而断崖式下降。

claude-mem 的核心设计理念是:记忆不是存储系统,而是过滤器。它只保留三类东西——事实、偏好、决策,并且每条记忆都是一个短小的原子条目,而不是一长串聊天记录。这就像复习考试时你不会把整个学期的教科书重新看一遍,而是翻自己整理的错题本和知识卡片。错题本帮你把几百页内容压缩成几十条关键信息,考试时一眼扫过去,就能快速唤起记忆。

理解了这一点,你才能明白为什么 claude-mem 要用"提炼 + 检索 + 注入"这三步走,而不是简单地把历史 log 倒出来。它是在模仿人脑的工作方式:遗忘掉大部分过程,只记住结论和教训。后面所有配置、调优、踩坑,都是围绕这个定位展开的。

2. claude-mem 的记忆管道:从对话转写到检索注入的全链路

2.1 捕获端:Hooks 挂钩的是对话生命周期

先看最底层的数据从哪里来。Claude Code 本身是有 hooks 机制的,它会在会话生命周期里触发特定事件,比如 SessionStart、Stop、PreToolUse、PostToolUse、Notification。claude-mem 主要挂在两个节点上:Stop 时抓取完整会话转写,SessionStart 时做记忆注入。

为什么要选 Stop 而不是每轮对话都抓?我最初也觉得实时抓取更靠谱,但实测下来问题很大。一是每轮都跑一次提炼,费用和时间成本翻数倍;二是会话中途的信息往往还没定型,你今天说"可能考虑迁移到 XX 方案",过三小时又说"算了还是维持原样",如果每轮都提取,就会把讨论中的想法固化成结论,反而制造噪音。只在 Stop 时做一次整体扫描,能拿到完整的上下文,提炼出的结论也更接近最终状态。

捕获完成后,会话转写并不会直接进记忆库。claude-mem 会先把转写落到一个临时文件,再交给后面的提炼模块处理。整个过程在 hooks 配置里就是一个命令的事,但真正的逻辑都在后台管道里。

2.2 提炼端:规则加模型,把文本压成结构化条目

如果把原始转写直接存库,记忆库很快会被垃圾信息淹没。你每句"帮我看看这个报错""试一下这个方案"都会被原样保存,检索时还容易和真正有价值的记忆抢排名。所以 claude-mem 在提炼端做了两层处理。

第一层是规则过滤器。它会先扫描文本,找出一批高信号词汇,比如"我决定""记住""以后都用""我们约定""不要再用"这类表达,把它们所在的目标句子圈出来,进入候选池。这个规则表是可以自定义的,我会根据自己团队的说话习惯往里加词——比如我们常说"这个接口已经废了",我就会把这个短语加进信号词表,让这类表述更容易被捕捉。

第二层是模型抽取。候选池里的句子会被交给一个模型,让它按照预设的 Schema 输出结构化记忆。每条记忆包含几个关键字段:内容、类型、作用域、时间戳、重要度、来源会话 ID。类型我一般分成四种:fact(客观事实)、preference(个人或团队偏好)、decision(敲定的决策)、todo(待办事项)。这样区分非常重要,后面检索和过滤都是靠类型来约束的。

结构化的好处是,记忆库不再是一堆散文,而是可以按条件查询的关系表。一条典型的记忆长这样:

{ "content": "前端新模块目录统一使用 kebab-case 命名,禁止用 snake_case", "type": "decision", "scope": "repo:frontend", "timestamp": "2025-06-12T14:30:00Z", "importance": 0.85, "source_session_id": "a3f9c1" }

2.3 存储端:SQLite 加向量索引的组合

存储层怎么设计,直接决定了检索性能的上限。我见过很多人一上来就上向量数据库,结果配置复杂、资源占用高,最后跑得还不如一个 SQL 查询快。claude-mem 的默认方案是 SQLite 主存储,外加一个向量索引。说白了就是:结构化字段放 SQLite,语义检索字段单独建索引。

SQLite 解决的是精确查询问题,比如"这个项目有哪些 decision 类型条目""最近三天新增了哪些记忆"。这些等值查询和范围查询用 SQL 非常快。向量索引解决的是语义相似问题,比如用户新会话里说了句"我们之前是不是定过 API 版本策略?",这句跟记忆库里的文字不一定有共同关键词,但向量空间里它们距离很近,能召回到那条 API 版本的决策记忆。

我建议的存储配置如下表:

方案优点缺点适用场景
纯 SQLite轻量、可审查、支持复杂过滤语义检索弱,只能关键字匹配手动维护、记忆量小
纯向量数据库语义召回能力强部署重、索引维护复杂大规模多项目共享
SQLite + 向量索引元数据过滤和语义召回兼顾实现稍复杂claude-mem 默认选型,适合日常开发

向量索引这里有个实现细节值得注意:它并不单独开一个常驻服务,而是作为本地文件保存在项目目录的隐藏目录下面,比如.claude-mem/vector.index。这样 clone 一个仓库时,记忆索引不会跟代码混在一起,也不会因为协作者不同的本地状态产生冲突。embedding 模型可以选本地模型,也可以调用云端 API,我建议先跑本地的轻量 embedding 模型,省去隐私顾虑,响应速度也更快。

2.4 注入端:把记忆装进 System Prompt 的合适位置

记忆提炼好、存储好,最后一步是"下次会话怎么用"。SessionStart 触发时,claude-mem 会做几件事:先拿到当前项目目录,作为 scope 过滤的键值,再拿用户的第一条消息或预先配置的任务描述作为查询向量,从记忆库里召回 Top-K 条最相关的记忆,最后把它们拼成一个固定的 Memory Context 文本块,追加到 system prompt 尾部。

这一步看似简单,但有几个关键参数需要控制。第一个是 Top-K,我默认设成 5,多了容易混入噪音,少了又可能漏掉关键决策。第二个是最低相似度阈值,默认 0.25,低于这个分数说明"相关但不够相关",不注入。第三个是注入的 token 预算,claude-mem 会限制整个 Memory Context 块的长度,默认不超过 3000 token,防止记忆喧宾夺主,把 Claude Code 本应处理的用户任务挤出上下文窗口。

这里还有一个细节要注意:把记忆明文塞进 system prompt,会让模型"认为"这些记忆都是高优先级约束。如果记忆库里有一条过时的决策,Claude 却把它当成当前规则,就会固执地按旧真相行事。这个问题非常常见,我单独拉一节专门讲,这里先按不表。

3. 安装与接入:从零跑通 claude-mem 的完整过程

3.1 前置条件:Claude Code 版本与 Node/Python 环境

claude-mem 的组成有点特殊,它不是单一体:capture 和 inject 等 hooks 入口是 Node.js 命令,所以你需要装好 Node;但真正做模型抽取和向量检索的模块是 Python 写的,所以还要保证 Python 环境干净可用。听起来有点绕,但习惯了就会发现这种组合很常见——接口层用轻量 Node,数据处理层用 Python 生态。

安装之前先确认三件事:

claude --version node -v python3 --version

Claude Code 的版本不能太老,hooks 机制是后面才加的,建议至少 0.1.43 以上。Node 和 Python 不需要最新版,稳定版本即可,我在 Node 18 和 Python 3.10 上都跑过,没有任何问题。

3.2 安装主程序与初始化数据库

环境备齐后,安装过程反而很轻量:

npm install -g claude-mem claude-mem init

init 命令会做三件事:在~/.claude-mem/config.toml生成默认配置、创建记忆数据库目录、下载/指定 embedding 模型。config 文件里最重要的几个字段是:

  • embeddings_model:默认 local,指定本地模型;也可以设成 api,走云端 embedding 接口。
  • memory_limit:单条记忆内容的字符上限,默认 500,避免存进去一整段对话。
  • inject_top_k:SessionStart 注入记忆条数,默认 5。
  • min_score:检索最低相似度阈值,默认 0.25。

我强烈建议第一次就跑 local 模式。理由很简单:claude-mem 的提取模块会把会话转写发给模型做强提炼,如果走云端 API,等于每一次会话结束都要把完整对话送到第三方,虽然不少团队不在意,但在公司仓库上这就是合规风险。本地模型慢一点,但胜在可控、不依赖外网、没有额外费用。

3.3 在 Claude Code 里注册 Hook

安装完只是装好了工具,还要让 Claude Code 知道自己该在什么时机调用它。这里的配置位置是~/.claude/settings.json或项目级的.claude/settings.json,后者优先级更高。用项目级配置的好处是,不同仓库可以挂不同的记忆作用域,同一个人的全局配置则会被所有项目共用。

一个常见的配置长这样:

{ "hooks": { "SessionStart": [ { "hooks": [ { "type": "command", "command": "claude-mem inject" } ] } ], "Stop": [ { "hooks": [ { "type": "command", "command": "claude-mem capture", "timeout": 120 } ] } ] } }

Stop hook 的 timeout 我特意调成了 120 秒,因为大项目的会话转写可能很长,提取模块跑完需要时间。如果你用的是云端模型做提取,这个 timeout 还得再放大一些。

注册完 hooks,重启 Claude Code 才能生效。这一步很多人会忘——我见过好几个同事配置改完后不重启,在那儿干瞪眼半小时。

3.4 验证最小链路:让它记住你的咖啡偏好

第一次接入完,别急着搞复杂场景,先做一个最轻量的验证,确认整条链路是通的。我自己习惯用"包管理器偏好"来做冒烟测试,风险为零、结果直观。

具体操作是这样:

  1. 新开一个 Claude Code 会话,输入一句话:"我喜欢用 pnpm 管理依赖,不喜欢 npm install。"
  2. 正常聊几句,然后/exit结束会话。
  3. 再次新开会话,直接问它:"我对包管理器有什么偏好?"

如果 claude-mem 生效,它会准确回答你偏好 pnpm。如果它答不上来或者答错,说明链路某个环节断了。这时候去看日志,最常见的坑是 Stop hook 没触发——检查一下你是不是真的用了/exit而不是直接关掉终端;SessionStart hook 没注入——检查一下 settings.json 的路径是否对、配置结构是否符合当前 Claude Code 的 schema。

4. 核心能力演示:让 Claude Code 记住"我们项目的关键决策"

4.1 场景排练:一次重构讨论后,新会话自动继承决策上下文

链路由 smoke test 之后,就可以拿真实项目场景来检验它的价值了。我用过最典型的场景是一次 API 版本策略讨论。

会话 A 里,团队在讨论是否要全面迁移到 /v2 接口。当时你说了很多:兼容期怎么定、哪些老接口要保、哪些直接砍掉,最后敲定结论:"/v2 从 7 月 1 日起全面接管,/v1 保留六个月的兼容窗口。"聊完直接/exit。

会话 B,第二天早上打开,你不用重复任何背景,直接问:"我们 API 的版本策略是什么?" claude-mem 在 SessionStart 时已经针对当前项目的 repo scope 召回到这条 decision 记忆,并把它放进了 system prompt。Claude 会直接告诉你"根据项目记忆,/v2 从 7 月 1 日起全面接管,/v1 兼容到年底"。

这个体验最爽的点在于:你不需要专门跟它说"这是昨天的结论",它自己就默认按既定决策行事。相当于你在团队里带了一个记性极好的实习生,你跟它说过一次的事情,它下次不会再来问第二遍。

4.2 用记忆做"项目标准"约束

除了临时的决策,项目里还有一类更长期的东西很适合交给 claude-mem,就是工程规约。比如"前端新文件命名统一用 kebab-case""所有对外接口必须带 OpenAPI 注解""后端不允许在业务代码里直接编写原生 SQL"。这些约束过去有两种处理方式:写进 CLAUDE.md 或者每次会话开头口头交代。前者维护成本高,后者容易漏。

claude-mem 给了第三种路径:从过往对话里自动提取,或者手动写入一次,之后每次 SessionStart 都会自动注入。我自己更喜欢手动写入的方式,因为工程规约通常发生在非常早期的讨论里,提取模型不一定能准确识别出来;而一旦你在某个会话里明确说过"记住,以后这里都按这个来",它就会进入偏好或决策类记忆,形成长期约束。

要注意的是,这类项目标准记忆的重要度通常很高。如果不想让模型自作主张,可以在 config 里开启"决策确认模式",让 Claude 在涉及关键决策时先说一句"根据项目记忆,你们之前约定……,是否遵循?"再行动。这样记忆只是参考,而不是把 AI 变成死脑筋。

4.3 通过命令直接写入手工记忆

自动捕获再牛,也不可能覆盖所有场景。有时候你想在会话中间快速塞一条约定,不想等 Stop 之后才被提炼,claude-mem 也提供了一组手动命令:

claude-mem add --scope backend --type decision "用户认证统一走 OIDC,不再自建 session 表" claude-mem list --scope backend claude-mem remove --id 23

这条命令我非常推荐在"想在代码里先写注释,但又不希望 AI 忘了这个约定"的场景用。比如你在设计评审会上刚确定了一个技术选型,趁热打铁跑一条 add,这个决策就定格了。比起先聊到 Stop 再让它自动理解和提炼,手动命令的优势是精准、无歧义,不会出现提取模型理解偏差的问题。

除此之外,claude-mem list很适合做定期盘点,看看库里面现在都有哪些条目。我每周至少跑一次,把它当项目记忆的健康检查——清理掉垃圾、修正错误、合并重复。

5. 实测中最容易翻车的三个环节:数据质量、匹配精度与级联失效

5.1 数据污染:当旧决策因为"曾说过一次"而变成真理

这是我对 claude-mem 印象最深的一个坑。有次我们讨论要不要把算力模块从 Python 重写成 Rust,讨论过程中我随口说了一句"要是能用 Rust 重写,性能应该能好不少"。结果这句话被提取成了一条 decision 类型记忆,重要度还挺高。之后几天里,不管聊什么功能,Claude 都时不时建议"可以考虑用 Rust 重构算力模块",甚至在我明确表示暂缓之后,它还坚持这个方向。

根子出在提炼端:模型分不清"假设性讨论"和"实际决策",只要语义上像结论,就可能入库。这个问题的解法思路是治理记忆质量。

一是靠分类。给记忆类型设置权重,decision 类型拥有最高约束力,fact、preference、todo 次之。当一条记忆的来源只是一句没有明显决策信号的随口语时,让它进 preference 甚至不进库。

二是开确认模式。高重要度决策在注入时,不是让模型直接奉为真理,而是先问一句"根据记忆,你们曾讨论过 Rust 重写,需要我按这个方向做吗?"——给模型一个"可以推翻"的出口。

三是定期清理。我习惯每个月跑一次claude-mem list --type decision,把那些已经落地、已经过时、或者根本就是讨论产物的条目直接删掉。记忆不是用来囤的,而是用来辅助当下决策的,过期的记忆比没有记忆更危险。

5.2 匹配精度:向量检索的 Top-K 选不好,注入的不是"相关"而是"噪音"

我一开始天真地以为,embedding 检索嘛,相似度算出来取 Top-5 就行。但实际跑下来,经常会出现一种情况:召回的第一名确实和当前任务高度相关,但从第二名开始就全是泛泛的团队偏好,比如"我们喜欢写测试""代码要简洁"。这些信息不是说没用,但它们对当前具体任务毫无帮助,反而占用记忆上下文。

这个问题的本质是:单纯依赖向量相似度会偏向"语言风格接近"而非"业务上下文相关"。我的优化实践分成三步。

第一步,先做 scope 过滤再召回。在检索时限定scope=当前项目,把候选集从几千条缩小到几百条,再去算向量相似度。这就好比你在一个城市里找人,先锁定街道,再拿着照片一个个认,效率完全不一样。

第二步,增加重排逻辑。召回 Top-K 之后,不要直接输出,而是用一条轻量规则给候选记忆打个加权分:重要度越高权值越大,时间越近权值越大,类型如果是 decision 则再加一分。最后按加权分排序,选出真正当前任务需要的。

第三步,调整top_k和min_score。top_k从 5 起步,如果发现注入的记忆里经常出现不相关内容,就调小;如果发现 Claude 经常问"这个项目是不是以前讨论过XX",就说明召回不够,调大。min_score则用来挡住那些"有点相关但不确定"的弱匹配,我一般维持在 0.25 左右。

5.3 级联失效:Hooks 没触发、提取失败、注入超大文本

整个 claude-mem 链路其实是一条数据管道,任何一环断了都会表现为"记忆没生效",但真正排查起来要分清三个故障区。

第一类是 hooks 没触发。Claude Code 版本升级后,settings.json 的 schema 可能变化,旧配置失效,或者 hooks 事件名称改了。排查方式是打开 logs 看 SessionStart 和 Stop 有没有对应执行记录,如果没有,就去检查配置结构和当前版本是否兼容。

第二类是提取失败。Stop hook 超时、模型调用报错、transcript 转写格式变化都会导致捕获得不到可用记忆。我遇到最多的是超大会话导致 Stop hook 超时。解决办法是把 capture 做成异步——hook 只负责把 transcript 丢进队列,真正的提取逻辑由后台 worker 慢慢跑,而不是阻塞在 hooks 里等结果。

第三类是注入的超大文本。如果记忆库条目太多、Top-K 太大,注入的 Memory Context 会挤爆上下文预算,表现为会话首轮响应变慢,甚至 Claude 开始无视上下文,回答变得答非所问。解决办法是在 config 里限制max_inject_tokens,同时把 Top-K 降到一个保守值。

我把排查常见症状整理成了一个表格,方便你对照:

症状可能原因排查路径解决方案
新会话完全不记得旧事SessionStart hook 未执行检查 hooks 日志升级配置结构,重启 Claude Code
记忆偶尔生效,但内容很旧Stop hook 超时未提取看 Stop hook 执行时间改成异步 capture,加大 timeout
首轮响应特别慢注入文本过大统计 Memory Context 长度降低 inject_top_k / max_inject_tokens
Claude 坚持错误决策记忆库有过期 decision运行 list 查看记忆条目删除过期条目,开启确认模式

6. 进阶:把 claude-mem 接进多人协作者工作流时的调优建议

6.1 多项目多分支的记忆隔离

当 claude-mem 只服务于你一个人一个仓库时,记忆混一点问题不大。可一旦团队里有好几个人、项目不再只是单个仓库,记忆隔离就变成了一件必须认真对待的事。

我的做法是给每个仓库设置独立的 scope,比如scope=repo:backend和scope=repo:frontend。这样后端仓库里讨论的"数据库连接池调大"不会跑到前端仓库里变成噪音。分支层面也一样,临时功能分支上的讨论最好用branch:feature-xxx这样的临时 scope 标记,等功能合并后再统一迁移到主干 scope。如果不管这些,最典型的结果就是你在 feature 分支上决定"这个版本先不做权限优化",等切回主分支之后,Claude 还老念叨这个决定,非常闹心。

claude-mem 的 config 里有include_scopes和exclude_scopes字段,可以控制哪些 scope 参与检索。我推荐主干记忆只保留稳定的项目事实和团队契约,临时分支讨论则放在独立的临时 scope 下,事后再清理。

6.2 共享记忆库与 Git 版本控制的取舍

团队协作避不开一个问题:记忆能不能跟代码仓库一起走?我的结论是,向量索引和 SQLite 数据库文件绝对不能提交进 Git。原因有三:这些文件经常变、体积会增长、二进制格式不适合 review。你自己本地跑得很爽的 embedding 索引,提交上去只会让队友在 clone 时拉下一堆没用的重复文件。

那怎么共享团队记忆?我采用的方案是"种子记忆"机制。维护一个claude-mem/seed/目录,里面放若干 Markdown 文件,每个文件对应一类基础记忆。比如seed/project-conventions.md里写清楚项目结构、命名规范、测试要求;seed/known-decisions.md里记录重要技术选型。新成员 clone 仓库后,第一件事是运行:

claude-mem init --seed ./claude-mem/seed

这个命令会把这些 Markdown 转成结构化记忆,导入本地库。这样团队的基础约定就实现了"写进仓库、可 review、可版本化",而每个人自己的 Session capture 产生的动态记忆只留在本地。这套方案完美分离了"团队共享的稳定知识"和"个人产生的临时上下文"。

6.3 与 CI/Agent 组合:把记忆用于自动 PR 检查和任务上下文传递

claude-mem 不只可以在人类开发者手里发光,也能在 CI 和自动化 Agent 场景里发挥价值。我后来把记忆检索的结果接到代码评审机器人上,效果非常显著。

思路是这样的:PR 触发的自动评审 Agent 本身也是"没有记忆的 AI",它对项目背景一无所知。但我在 CI 脚本里加了一步,在启动评审机器人之前先跑一次:

claude-mem inject --scope repo:backend --max-tokens 2000 > /tmp/agent_memory_context.md

然后把这份记忆上下文作为额外的 context 传给评审 Agent。Agent 在检查 PR 时就会知道团队"所有对外接口必须带 OpenAPI 注解""不得引入额外 session 管理依赖"这类约定,评审建议的命中率和准确度立刻上一个台阶。

这个用法还有一个潜在衍生场景:像任务调度 Agent 这种需要串联多轮任务的自动化组件,每次执行前注入记忆,可以让它记住批量任务之间的前置条件和后续要求,不再每次都像失忆了一样重新开始。代价是需要一个共享可读的记忆源,比如团队共享存储或 CI 产物的归档目录。

最后分享一个我自己的使用习惯:每个月底,我会手动跑一次claude-mem list --type decision --output markdown,把它当成"项目遗忘清单",把已经落地、已经过时、或者本来就不该记的条目删掉,给记忆库做一次下班前的整理。用 claude-mem 最深的体会是,它不是一个容量无限的笔记本,而是一个学会遗忘的助手。记忆系统能走多远,不取决于它存了多少,而在于它有没有勇气丢掉那些不再重要的。希望这篇基于实际折腾过程的分享,能帮你省掉我踩过的那些坑。

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

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

立即咨询