跟你讲个真实的场景:我前一天让Claude Code帮我重构了一个模块,当时口头约定了“函数命名不要缩写、接口返回值用Result包装”,第二天打开终端准备继续改下一个文件,它完全不记得这回事,上来又被我重复训了一顿。这个问题其实不是个例——Claude Code的每次会话都是独立的,上下文窗口再大,也不会天然带上昨天的结论。后来我在社区里翻到一个叫claude-mem的开源工具,专门解决“AI助手跨会话失忆”的问题:它自动扫描Claude Code的本地会话记录,把值得长期记住的信息分类沉淀成Markdown文件,并在下一次对话开始时自动把相关记忆注入提示。这篇文章把我从安装配置、工作原理、日常用法到进阶调教和踩坑过程完整写一遍,给同样被重复沟通折磨的人一个参考。
1. 为什么AI助手需要“外挂记忆”
1.1 上下文窗口再大,也装不下长期偏好
很多人一开始觉得,LLM上下文窗口已经很大了,10万token甚至上百万token,还需要额外做记忆吗?实际用起来不是这么回事。我手上同时维护着三四个项目,每个项目的代码风格、依赖管理方式、测试习惯完全不同:一个用pnpm,一个用npm,一个还是老旧的pip+requirements.txt。Claude Code开一个新会话就相当于来了个零基础实习生,所有约定都要重新解释一遍。你可以在每个会话开头写一大段引导词,但引导词本身会占用上下文窗口,而且项目越多、引导词越长,实际留给代码和业务讨论的空间就越小。
更麻烦的是,引导词只能解决“显式约定”,解决不了“隐性积累”。比如上个礼拜调试一个并发写入问题,最后定位到是数据库连接池配置不合理,这个结论散落在那次会话的几十轮对话里。下次再遇到类似错误,Claude Code根本不知道你之前已经排查过一遍。上下文窗口是线性的,它只能看到当前会话的内容;而个人和团队的经验是持续累积的,这两者之间存在结构性矛盾。所以与其每次手动把历史拉出来贴进提示,不如在会话之外建立一个持久的记忆层。
1.2 claude-mem的定位:给Claude Code的随身记事本
claude-mem就是用在这个位置上的工具。它本身是一个Python写的命令行程序,核心思路很朴素:Claude Code在本地运行CLI时会自动留下JSON格式的会话记录(transcript),claude-mem读取这些记录,调用LLM从中提炼“值得长期保留的信息”,按类型存成本地Markdown文件;然后通过Claude Code的hooks机制,在每次对话提交之前把相关记忆自动注入用户提示。整个链路是:会话记录 → 记忆提炼 → 本地存储 → 自动注入。
可以把它理解成给AI助手配了一本随身记事本。你不必记得每一次聊天细节,它会替你把重点划好、分门别类摆在抽屉里,下次要用的时候自动递上来。这个工具的适用人群很明确:重度Claude Code用户、同时维护多个项目的人、以及希望AI助手“越用越懂我”的人。它解决的不是“单次对话质量”问题,而是“跨会话连续性”问题,这是靠提示词优化绕不过去的一环。
2. 安装与初始配置:先让记忆系统跑起来
2.1 环境要求与pip安装
安装claude-mem之前,先把前提条件确认好:你已经在用Claude Code,并且至少跑通过一次会话。因为claude-mem的“原料”是Claude Code留下的transcript文件,没有会话记录可扫,装上也白搭。当前版本是用Python实现的,环境建议Python 3.10以上,太老的版本可能在依赖解析阶段就报错。
安装命令很简单:
pip install claude-mem装完验证一下:
claude-mem --version能正常输出版本号,基本就没问题。我自己习惯用虚拟环境装,不直接往系统Python里塞,这样后面升级或换版本不会污染其他项目。如果你用的是uv管理Python环境,也可以直接用uv tool install claude-mem,效果一样,还能自动隔离依赖。
这里有个很容易忽略的点:claude-mem的安装路径要在Shell的PATH里。之前遇到一个朋友装完后运行命令提示找不到,排查半天发现是装到了用户目录下的Python环境里,终端没有把那个目录加进PATH。用which claude-mem看一下,能输出真实路径就没问题。
2.2 bootstrap一键配置Claude Code hooks
装好之后,最推荐先跑这个命令:
claude-mem bootstrap它会扫描你的Claude Code配置目录,一般在~/.claude/或者由$CLAUDE_CONFIG_DIR指定的位置,然后询问你是否要把记忆注入到每次对话的提示中。确认之后,它会自动帮你把hooks配置写进Claude Code的settings文件。
为什么一定要用hooks而不是自己改启动脚本?因为hooks是Claude Code官方支持的扩展点,专门用来在特定时机执行自定义命令。claude-mem利用的是UserPromptSubmit这个时机:用户在终端里按下回车、提示文本正式提交给模型之前,先执行一次claude-mem,读取当前相关的记忆并追加到提示文本前面。整个注入过程对用户是透明的,什么都不用手动做。
配置完成后,可以去检查一下~/.claude/settings.json,里面应该能看到一段跟hooks相关的配置。如果不想手动翻文件,也可以跑claude-mem doctor,它会诊断当前配置状态、依赖是否齐全、transcript目录是否可读,一站式把配置问题暴露出来。这个命令很像体检报告,省去自己猜的功夫。
2.3 首次对话与记忆生成验证
配置完不要急着下结论,先跑一个真实会话验证效果。我当时的做法是打开一个项目目录,跟Claude Code聊了几分钟,特意说了一句“以后定义接口时,方法参数都用关键字参数,别用位置参数”。这句话是明显的偏好声明,适合用来测试记忆有没有被抓到。结束会话后,执行:
claude-mem search 关键字参数如果一切正常,你应该能看到一条分类为preference的记忆,内容就是刚才那句约定。也可以直接打开记忆目录~/.claude-mem/memories/看生成的Markdown文件,文件名和YAML头部会标明分类、时间戳、来源会话等元信息。
第一次验证时最常见的误判是:会话刚结束就立刻搜索,结果什么都没有。别急,记忆构建是异步的,transcript生成、扫描、LLM提炼需要一点时间,慢的时候可能要等十几秒。等一小段时间再搜,或者手动跑一次claude-mem schedule强制触发扫描,基本就能看到结果了。
3. 跑通之后,拆一拆它的工作原理
3.1 transcript扫描:记忆从哪里来
Claude Code每次通过CLI启动会话,都会在本地留下会话记录,路径一般是~/.claude/projects/<项目路径哈希>/这样的目录结构,里面按时间存放JSON格式的transcript文件。这些文件记录了用户消息、助手回复、工具调用等完整交互过程。claude-mem做的事情,就是主动去扫描这些新产生的transcript。
这里有个设计思路很值得说:它不去实时监听对话流,而是基于事后的transcript做解析。实时旁路意味着要在Claude Code运行中途插入agent逻辑,这会引入复杂度,而且Claude Code一升级就可能挂。transcript方案是“事后重放”,稳定性好,可追踪,即使扫描挂了也不会影响实际对话,最多记忆延迟个几十秒。我后面踩坑时才发现,这个设计救了很多次,scan失败最坏也就是没记忆注入,会话本身完全不受影响。
需要注意的一点是,claude-mem对transcript目录只读不写。它不会修改、删除或移动原始会话记录,记忆文件独立放在自己的目录,这对有审计需求的人很友好。
3.2 记忆分类与提炼过程
拿到transcript之后,claude-mem要做的不是“整段存进去”,而是“提炼”。它会调用LLM把一段冗长的对话压缩成若干条信息密度高的记忆条目,每一条都要归类。默认支持的分类大致有这些:
- preference:用户偏好,比如“代码注释用中文”“回复尽量精简”
- code-pattern:固定代码习惯,比如“实体类统一继承BaseEntity”
- project-decision:项目级决策,比如“认证模块用JWT,不做Session”
- learning:你在对话中学到的知识点
- bug-fix:排查记录,比如某类并发问题的根因
- pitfall:坑位记录,比如“这个库的旧版本有内存泄漏”
- project-structure:项目结构约定,比如“业务代码放在app/services下”
分类不是锦上添花,它直接决定记忆的筛选和注入粒度。想象一下:你在一个Node项目里聊React组件,结果把Python项目的pip依赖偏好也注入进来了,这不但没帮助,还纯属干扰。有了分类和项目维度的配合,Claude Code才能做到“只带该带的记忆”。
提炼过程依赖LLM分析,所以这里也解释了一个现象:为什么第一次运行时会感觉记忆生成有点慢,因为每个transcript都要经过一次模型调用。等到积累一段时间后,这个过程是在后台跑,基本感知不到。
3.3 记忆注入闭环
理解了记忆来源,再看记忆怎么回到对话里。完整的注入链路大概是:
- 用户在Claude Code里输入消息,按下回车;
UserPromptSubmithook触发,Claude Code在把用户提示交给模型之前,调用claude-mem;- claude-mem根据当前工作目录和配置,读取相关记忆;
- 记忆文本按模板包裹后,追加到用户提示文本前面;
- Claude Code把“用户提示 + 记忆上下文”一起发给模型,模型在回答时天然能看到这些历史信息。
为什么要把记忆放在用户提示的前面而不是改系统提示?因为系统提示是模型行为的主基线,随便往里塞内容会影响模型的整体性格和输出风格。而放在用户提示前部,本质上只是补充了一段上下文,模型能感知到,但不会改动它底层的交互方式。说得直白一点:系统提示是“身份”,用户提示是“当次任务”,记忆属于后者。
4. 日常用法:查询、搜索、会话摘要与手动添加
4.1 用search找回关键记忆
随着记忆库越来越大,你不可能每次都翻Markdown文件。“claude-mem search”才是日常高频入口:
claude-mem search 分页器搜索结果会展示记忆内容、分类、创建时间、来源会话编号。用这个命令的时候有个经验:它的搜索本质是本地文本匹配,不是语义向量检索,所以关键词要带“特征词”,不要带“语气词”。搜“那个分页的问题”基本搜不到,搜“分页器 后端分页”反而能精准命中。这个差别刚上手时很容易觉得“工具不好用”,其实只是没用对。
4.2 用session捡起上次会话
还有一个我特别喜欢的命令是session相关的功能。如果你隔了几天回到项目,完全忘了上次聊到哪,直接执行:
claude-mem session 上次最后讨论的问题它会返回一条上次会话的摘要,相当于对旧会话内容做了一次“快照压缩”。这个功能适合跨天工作流:今天收工时讨论的方案,三天后回来一句话就能接上。我的习惯是每个长时间任务结束前,主动跟Claude Code做一次阶段性总结,让摘要质量更高,等下次回来时调session摘要,衔接成本几乎为零。
4.3 手动添加:不等它自己发现
自动沉淀再聪明,也有漏网的时候。比如客户临时在电话里说了一个需求,你没跟Claude Code聊过;或者一个约定只在对话里出现了一次,模型没把它当重点提炼。这时候就该手动补一条:
claude-mem add --content "客户明确要求:导出功能必须支持Excel格式" --classification preference手动添加的意义不只是补漏,它还能让Claude Code在未来的会话里马上表现出“懂你”的状态,不用等它从某次历史对话里慢慢提炼。手动添加时content要写完整、具体,别写“用户偏好excel导出”,要写“用户明确要求:导出功能必须支持Excel格式”,因为注入提示时模型会原文看到这句话,细节越清楚,理解越准确。
4.4 记忆的导出与备份
claude-mem支持不同的输出格式,比如把全部记忆导出为JSON、YAML或CSV:
claude-mem --output-format json这个功能主要用于备份、迁移和二次处理。我自己换机器的时候,习惯直接备份~/.claude-mem/整个目录,记忆文件本来就是纯文本Markdown,复制过去就能接着用。比导出再导入更省事。如果你需要把记忆丢给其他工具做统计分析,再用--output-format格式化导出也不迟。
5. 进阶:记忆系统的定制与调教
5.1 config.json 里的关键开关
claude-mem的配置集中在~/.claude-mem/config.json。我用的版本里,几个值得关注的配置项包括:是否自动注入记忆、记忆作用范围、启用的记忆分类、输出格式偏好等。第一次接触时别急着全改,先理清楚两个最核心的:
- 自动注入开关:控制是否把记忆自动加到提示里。如果只想把claude-mem当记忆数据库用、不想影响每次对话,可以关掉;
- 作用范围:区分全局记忆和项目局部记忆。全局适合个人偏好,局部适合单项目约定。
修改配置之后,新开一个会话才会生效,因为hooks在会话启动时读取配置。如果改了没反应,别疑惑,退出当前会话重新进就好。
5.2 用模板定制注入格式
注入不是简单把记忆文本往前面一堆,claude-mem允许你定义模板,在模板里使用变量占位,比如{{classification}}、{{content}}这样的字段。模板的主要用途是让注入内容带上分类标签,让模型一眼就能看出这段记忆属于偏好还是代码模式。举例来说,你可以把模板调整成带[preference]标签的结构,模型看到标签后,对这段记忆的语义把握会更强,实际效果确实比自己不加标签好一些。
不过别一上来就设计特别复杂的模板,先跑默认配置几天,观察注入内容是否符合预期,再逐步调整。我见过有人第一次就去配置多级嵌套模板,结果格式语法写错,注入内容全是乱序的,反而影响对话质量。
5.3 控制记忆范围:全局与项目的边界
多项目场景下,记忆范围是最容易被忽略的坑。全局记忆适合放个人通用偏好,比如“所有代码注释用中文”“翻译时保持中英双语对照”;但项目级约定必须隔离,比如项目A用pnpm,项目B用npm,项目C用pip,这类信息如果混进全局记忆,就会出现一种很滑稽的情况:在项目B里讨论依赖安装,结果Claude Code用项目A的pnpm风格来提供建议,让人摸不着头脑。
我的建议是把scope配置改成更适合当前工作模式的策略:通用偏好放全局;单项目约定放局部。在哪个目录启用哪个范围的记忆,关键词是“项目目录隔离”。用scope=local的模式之后,Claude Code在对应项目目录会话中只读取该项目自己的记忆,干扰会大大减少。
6. 踩坑记录与维护建议
6.1 装了却不注入?从三个方向排查
我遇到过最头疼的问题就是配置半天,结果Claude Code好像完全没读取记忆。这时候别慌,按这个顺序排查:
- 配置位置对不对:claude-mem读取的settings路径,和Claude Code实际使用的路径是否一致。如果你设置了
$CLAUDE_CONFIG_DIR,两边指向就可能不同; - hook是否注册成功:跑
claude-mem doctor,它会输出诊断状态,直接告诉你哪一步异常; - transcript目录可读性:有些项目目录权限受限,或者Claude Code因为某些原因没生成transcript,导致没有“原料”可扫。在终端里手动去
~/.claude/projects/看一眼有没有新生成的JSON文件就知道。
排查的耐心很重要,这三个方向已经能覆盖绝大多数“不注入”情况。如果还不行,打开调试日志,一步一步定位,不要盲目重装。
6.2 记忆文件膨胀与定期维护
自动记忆系统有个副作用:记忆只增不减,时间长了会积累大量过时信息。比如半年前你还在用某个库的旧API,后来整个模块重写了,但旧的记忆文件还躺在目录里。如果不清理,Claude Code就可能把已经废弃的方案当成当前约定来用,这时候记忆反而成了干扰源。
我现在的维护节奏是每个月清理一次:直接进入~/.claude-mem/memories/,按文件修改时间排序,把明显过期、错误、与当前项目无关的记忆删掉。记忆文件本身就是普通Markdown,手动编辑和删除没有任何门槛。这就是本地明文存储的好处,你永远可以兜底纠错,不会被困在系统里。
6.3 隐私与API调用的边界
这一点必须认真提醒。claude-mem在构建记忆时依赖LLM来提炼,这意味着部分transcript内容会被发送到对应模型的API端点。如果你的项目代码高度敏感,要么选择本地兼容的模型端点,要么对敏感域名关闭自动记忆,只通过claude-mem add手动保存必要信息。
另一个高频事故是密钥泄露。我见过有人把数据库密码、API token当成记忆内容保存下来,理由是“让Claude Code下次直接帮我填”。这个想法很危险,记忆文件是本地明文,一旦本机被攻破或者目录被同步到云盘,麻烦就大了。明文存储密钥永远是安全事故的导火索,不要把它写进记忆库,更不要让它出现在注入的提示里。
最后说点个人体会。我刚开始用claude-mem时最不适应的一点,是注入的旧记忆偶尔会把话题带偏,后来用scope和分类过滤把这个问题收敛住了。但整体跑了两周之后,重复沟通成本确实下降了一大半,最明显的变化是开新会话时不用再啰嗦背景了,Claude Code自己带着“记忆”进场。记忆系统这种东西,刚开始觉得是锦上添花,真正用上一段时间后就会变成工作流里的默认配置。当然,任何第三方工具的版本迭代都会调整命令和配置字段,我上面写的内容以你本地的claude-mem --help和官方文档为准,工具是拿来用的,别让它变成新的负担。