1. 为什么需要 claude-mem:把 AI 的“短暂记忆”变成“长期记忆”
1.1 无状态 API 的失忆坑
只要是认真调过 Claude API 的人,应该都体会过同一个诡异瞬间:上一轮明明已经交代好的技术约束,下一轮它又给你按老思路写了。比如我负责的一个文档爬虫项目,第一轮明确说“数据库统一用 SQLite,不许上 PostgreSQL”,结果第三轮生成迁移脚本时,它直接给我写了CREATE DATABASE crawler。我当时的反应是“这模型是不是傻”?后来才反应过来,这锅不该让模型背。
Claude 的 API 本质上是一种无状态接口。你和它对话时,它并不是一个拥有长期记忆的“人”,而是一个每次都被临时唤醒的重读机器。你发给它的每一次请求里,除了携带用户消息之外,还必须把所有历史消息、系统提示、工具结果原样放进 messages 数组里,它才能保持所谓的“连贯”。一旦某个请求没有带上历史,上一轮说过什么它就完全不记得了。换句话说,不是它记性差,而是你的客户端没把记忆喂给它的能力。
1.2 我们过去解决上下文的土办法
早期我做 AI 工具的时候,最常用的方案是“手工维护上下文文档”。做一个project_brief.md,把关键决策、代码约定、已定方案全写进去,每次开新会话先复制粘贴到 system prompt 里。这种方案在单项目、单会话的场景下确实能跑,但问题会在几个维度上同时爆发:
- 上下文长度失控:一个跑了几个月的项目,brief 文档动辄上万字,塞进去高频轮次里,token 直接被吃掉大半。
- 信息污染:旧决策和新变化混在一起,模型看到一条“禁止使用 Redis”的旧记录,不知道后来已经改为“允许使用 Redis 做短时缓存”,于是不敢写缓存逻辑。
- 维护成本高:每一轮改完代码,我还得手动回填文档,一旦忘了,下个会话就失忆。
我也试过用向量数据库做 RAG,把零零散散的笔记、报错日志都存进去。但那套做法的门槛在于:你得自己写 chunk、自己管理 embedding、自己处理召回阈值,最后还要把这个检索能力“接”到对话主流程里。搞着搞着,我怀疑自己不是在写业务代码,而是在造一个兼职客服系统。
1.3 claude-mem 想解决的那个“痛点”
后来我接触到了 claude-mem 这个项目,它的思路非常直接:与其让模型每次从零理解上下文,不如在模型外挂一层“笔记本”,也就是记忆层。模型在对话过程中说什么、做了什么决定、产生了什么结论,这套层会把它结构化地存下来,并在下一次会话需要时自动调出来。
我觉得这个定位很有意思。它不试图改变 Claude 的无状态本质,也不假装模型有“自我意识”,而是老老实实做了一个中间层:你来用,我来记,下次再喂给你。对做 AI 应用和自动化 workflow 的人来说,这种设计比“反复重述全量历史”靠谱得多。后面我会把架构、实操、踩坑过程挨个拆开说清楚。
2. 先从架构看起:claude-mem 的记忆层到底长什么样
2.1 它和 MCP 是什么关系
先说一句个人层面的总结:如果你是第一次接触这类工具,可以直接把 claude-mem 理解为一个“自带记忆管理的 MCP Server”。
MCP,全称 Model Context Protocol,是一个用于连接大模型客户端和外部工具服务的开放协议。它规定了一套 JSON-RPC 消息格式,使得 Claude Code、Claude Desktop 这类客户端通过标准接口调用工具,比如读取文件、操作数据库、查询知识库等。相当于给模型配了一个“USB-Hub”,外设插上协议就能通,不用每个外设都单独定制一根线。
claude-mem 正是以一个 MCP Server 的身份存在的。它对外暴露的工具大致是mem_store、mem_query、mem_summarize、mem_forget这几个动作。对话过程中,Claude 会把值得沉淀的内容写入 memory;新会话开始时,Claude 又根据当前项目、话题,去 memory 里检索相关内容并注入上下文。整个过程对用户是透明的,你不需要手动拖拽任何文件。
2.2 三个核心动作:记录、抽取、召回
很多人以为记忆功能就是“把聊天记录存下来”,实际上远远不够。聊天记录是流水账,直接灌给模型,既占 token 又带回噪声。claude-mem 把这件事拆成三块:
- 记录(Capture):监听每一轮对话,把需要保存的内容以结构化条目形式写入存储。项目名、标签、类型、内容、关联会话 ID 都是独立字段。
- 抽取(Extract):借助 Claude 或本地模型,把一次长对话压缩成若干个高密度的“记忆点”。比如一场两小时的架构讨论,最后抽出来可能就是“确定用 SQLite”“认证方案改成 API Key”“不用 Redis”这几条。
- 召回(Recall):新会话开始前,根据当前项目、标签、向量相似度,把与之相关的记忆条目拉出来,再按 token 预算拼接成一段补充上下文。
这三块缺一不可。如果只做“记录”,那就是个日志文件;如果只做“召回”,拿什么召回呢。claude-mem 把抽取放在中间,相当于把印象笔记和搜索引擎缝到了一起。
2.3 数据落盘:一条记忆到底怎么存
默认情况下,claude-mem 使用 SQLite 作为主存储,记忆目录下会有一个memory.db,同时按项目分目录保存可读的 Markdown 摘要,方便你直接打开看。给个简化版的记忆条目 JSON,能直观看出它的数据结构:
{ "id": "mem_8f3a2c", "type": "decision", "project": "web-doc-crawler", "tags": ["architecture", "database"], "created_at": "2025-06-02T10:24:00+08:00", "source_session": "sess_01J2", "summary": "爬虫项目统一使用 SQLite,不引入 PostgreSQL", "detail": "单机运行、预估数据量不超过 500 万行;等需要多人并发写入时再迁移", "references": ["docs/db.md"], "embedding": "[0.012, -0.087, ...]" }embedding字段是可选的,用于做语义相似度召回。如果你不需要向量检索,可以关掉 embedding,claude-mem 也能通过标签和关键词完成基础召回。个人建议在项目初期先不开向量,用标签就够,后续量大了再开启,可以省掉不少调试成本。
2.4 为什么不直接用数据库存全量聊天记录
我在改造时也想过,既然要存,干脆每条原始消息都落库,需要时再全文搜索,不是更省事?实际跑下来发现不行。全文搜索只能做关键词匹配,而模型回忆时往往是说“之前我们讨论过那个关于数据库的方案”,它根本不会精确命中“SQLite”这个词。向量相似度虽然能缓解,但原始聊天记录里噪声太多,检索出来的片段经常是“这个我们再看看”这种废话。
所以 claude-mem 的做法是:原始会话只在本地留一段短期限转存,用于抽取和审计;真正长期保存的是抽取后的结构化记忆点。这本质上是“先压缩、再存储、后检索”,把脏活累活都放在了写入侧,读取侧就轻松了。
3. 上手实操:安装、配置与接入 Claude Code
3.1 安装与初始化
我用的环境是 macOS + Node 18 + Python 3.11。在写这篇总结的版本上,claude-mem 的安装方式很简单,直接通过 npm 或 pip 安装都行,两者提供的子命令基本一致。如果你主要在 Claude Code 生态里用,推荐 npm 版本;如果你的改造场景偏 Python,走 pip 更顺。
npm install -g claude-mem # 或者 pip install claude-mem安装完成后,先初始化数据目录。这一步会自动创建~/.claude-mem目录、SQLite 数据库和默认配置文件:
claude-mem init初始化脚本会问你数据目录放哪、是否开启 embedding、召回 token 上限等。新手阶段建议一路默认,先把链路跑通再看指标。我最初一上来就开了一堆高级选项,结果排查了半天才发现是 embedding 模型没配置对,反而影响了第一印象。
3.2 把它接入 Claude Code
接下来需要把 claude-mem 注册成 Claude Code 的一个 MCP Server。最省事的方式是直接用 CLI 添加:
claude mcp add claude-mem -- npx claude-mem serve如果你用的是 Claude Desktop 或自建客户端,可以手动编辑 MCP 配置文件。以 Claude Desktop 为例,配置在claude_desktop_config.json里的mcpServers节点:
{ "mcpServers": { "claude-mem": { "command": "npx", "args": ["claude-mem", "serve"], "env": { "CLAUDE_MEM_DATA_DIR": "/Users/liz/data/claude-mem", "CLAUDE_MEM_EMBEDDING_DIM": "256" } } } }CLAUDE_MEM_DATA_DIR一定要指向真实的、有权限写入的目录。我之前在 Windows 机器上配过相对路径,结果 claude-mem 一直拒绝启动,查了半天才发现它把相对路径解析到了当前工作目录,导致每次启动都在找不存在的路径。
3.3 核心命令:如果只想记住六个动作
把 claude-mem 跑起来之后,我实际用的命令就这几个:
# 手动添加一条记忆 claude-mem note add --project web-doc-crawler --tag architecture "统一使用 SQLite" # 按项目查询记忆 claude-mem query --project web-doc-crawler "数据库选型" # 查看统计信息 claude-mem stats # 导出/备份 claude-mem export --format json > backup.json # 删除某条记忆 claude-mem note remove mem_8f3a2c # 健康检查 claude-mem doctordoctor命令对新手特别友好,它会把 MCP 连通性、数据库完整性、embedding 模型加载状态一次查完。遇到问题先跑它,能帮你排除掉一大半环境层面的坑。
3.4 召回策略:三种模式怎么选
claude-mem 的召回策略有三种,我是在改到第三个版本时才真正理解它们的差异:
| 模式 | 行为 | 适合场景 |
|---|---|---|
| auto | 每次对话前自动注入相关记忆 | 单项目长期开发,上下文稳定 |
| semi-auto | 先让模型判断是否要查记忆,需要时再调用工具 | 多项目并行,token 预算紧 |
| manual | 只在用户显式要求时查记忆 | 对输出纯度要求很高的任务 |
刚开始我全用 auto,因为省事。后来发现项目一多,auto 模式会把好几个项目的记忆都捞进来,反而相互干扰。现在我的习惯是:单一长期项目用 auto,其他场景一律 semi-auto。它只会在模型判定“这个问题需要历史背景”时才触发mem_query,避免无关记忆抢占上下文窗口。
配置文件里的召回上限,我放在~/.claude-mem/config.yaml:
recall: mode: semi-auto max_memory_tokens: 1200 default_projects: ["web-doc-crawler"] filters: min_score: 0.45 max_age_days: 90max_memory_tokens我一般给 800 到 1500 之间。太少了,喂进去的信息不够模型展开;太多了,对话刚开始就已经消耗了大量 token。1200 是我调了三四轮之后找到比较舒服的平衡点。
4. 实战场景:一个跨周项目不再“翻脸不认人”
4.1 场景设定:文档爬虫的第二次开发
这里用一个我真实跑过的例子来演示。项目名web-doc-crawler,目标是爬取公司内部文档站的几十个页面,清洗后转成结构化 Markdown。第一次会话,我花了不少时间定架构:用 Playwright 抓页面、用 SQLite 存原始 HTML、用 Python 脚本做清洗。结束会话时,claude-mem 自动把“确定 Playwright”“数据落 SQLite”“清洗脚本放 scripts/ 目录”这些决策封存了起来。
三周后,我要接着给这个项目加“增量更新”功能。如果不加记忆层,我需要重新把之前的架构约定口头复述一遍,甚至可能因为遗忘而推翻旧设计。这次我在 Claude Code 里直接新建会话,只写了一句:
继续推进 web-doc-crawler 的增量更新功能Claude 在后台调用了 claude-mem 的mem_query,拿到了一串与该项目相关的记忆条目。然后它问我:“按之前的方案,你是想保持 SQLite 不变,只新增一个 last_crawled 字段来记录上次抓取时间,对吗?”
看到这句话,我其实蛮高兴的。它没有问“这是个新项目吗”,也没有等我重新灌输背景,而是直接基于记忆里的决策往前推理。这说明记忆不是白存的,真的在下一个会话里起到了“接续”作用。
4.2 记忆抽取的现场效果
为了让读者更直观地了解抽取过程,我把那次会话里 claude-mem 生成的 Memory 摘要贴出来。它的数据和上一节里的 JSON 结构对应:
## Memory: web-doc-crawler - 类型:decision - 内容:统一使用 SQLite,不引入 PostgreSQL - 原因:单机运行、数据量小,后续需要共享时再迁移 - 相关文件:docs/db.md - 创建时间:2025-06-02这种摘要形态有两个好处。第一,它不是原始对话的碎片复制,而是经过抽取的信息,噪声被过滤掉了。第二,它保留了原因字段,等到项目规模增长、需要重新审视决策时,模型能看到当初做这个决策的背景,避免因为看到一条孤立的结论就直接执行。
4.3 注入之后,模型行为有什么变化
我把同样的开发任务分别在“开记忆”和“关记忆”两种状态各跑了一次,差别非常明显。
关闭记忆时,Claude 会自然地按照通用最佳实践来写方案,比如建议我用 Redis 做去重队列、用 PostgreSQL 存储,原因是“大规模爬虫通常应该这么做”。这没有错,但它不符合项目实际。
开启记忆后,Claude 开头就会说:“项目历史记录显示你已经确定使用 SQLite,我会在此基础上设计增量更新。”整个方案的代码都是围绕 SQLite 写的,连表结构变更都考虑了ALTER TABLE的兼容性。对一个已运行一段时间的项目来说,这种“顺着历史走”的能力,比生成一个标准答案有用得多。
4.4 需要留意的副作用
当然,记忆层不是没代价。我发现它偶尔会把旧结论当成“不可动摇的事实”,在需要调整时反而成了阻力。比如这个项目前期定的“不做分页处理”,到后期页面数量涨到几千时,其实已经需要重新评估了,但 claude-mem 把旧结论召回后,Claude 有一轮确实自动维护了这个不够合理的假设。
所以后来我给自己立了个规矩:每次新会话开始,如果发现记忆里描述的“过期决策”,第一件事就是手动更新或删除旧记忆,而不是强行让模型基于过期条件干活。记忆是工具,不是真理。这个分寸感,用多了自然会有体会。
5. 常见问题与排查实录
5.1 记忆生效路径排查
我刚开始接入时,最困惑的就是“到底有没有生效”。后来把排查思路固定成三步:先看 claude-mem 自己能不能查到数据,再看 MCP 客户端能不能连上服务,最后看模型有没有调用记忆工具。
claude-mem doctor claude-mem query --project web-doc-crawler "数据库" claude code --verboseclaude code --verbose会打印工具调用日志,如果模型执行了mem_query,日志里会显示对应的 tool_use 信息。这也是判断召回模式是否配置正确的直接证据。0.4.x 版本的默认配置下,如果召回模式是 manual,并且提示词里没有任何明确触发词,模型可能从头到尾都不会碰记忆工具。这不是 bug,是设计如此,但新手很容易误以为是接入失败。
5.2 常见问题速查表
我整理了这段时间实际踩过和修复过的问题,按“症状 - 原因 - 解决办法”列成一张表,方便大家直接对着查:
| 症状 | 常见原因 | 解决办法 |
|---|---|---|
| 新会话中模型完全不知道历史项目 | MCP Server 没注册成功,或注册了但连接失败 | 运行claude mcp list,确认 claude-mem 在线;再跑claude-mem doctor |
| 召回的内容和当前项目无关 | 配置文件里default_projects没设,或项目名不一致 | 统一项目命名规范;为每次对话设置当前项目前缀 |
| 上下文窗口很快被吃满 | max_memory_tokens设置过高,且召回条目过多 | 降到 800-1200;开启更严格的阈值过滤 |
| 写入失败,报数据库文件被占用 | 多个 claude-mem 进程同时打开同一个 SQLite 文件 | 检查是否有后台残留进程;把服务配置固化到 systemd/launchd |
| embedding 召回结果很差 | 存储时和查询时的 embedding 模型不一致 | 固定同一个 embedding 模型,禁止中途切换 |
| Windows 下启动失败 | 配置里的路径带反斜杠且未转义 | 改用正斜杠路径,或使用环境变量注入 |
5.3 关于敏感信息的隐私意识
这一点必须单独拿出来提醒:记忆层把所有对话提炼后集中存放,等于给你的 AI 助手装了一个“日记本”。里面很可能有业务数据、源码片段、内部架构信息。claude-mem 默认支持加密存储,我建议一上来就开启,而不是等项目上线后再补。
其次,要为一个长期项目设定记忆的保留期限。我在配置里把max_age_days设成 90 天,超过 90 天的决策会退出默认召回范围。这个数字不小,但旧记忆确实是越来越不重要的,比起让模型被半年前的某条结论绑架,宁可让旧信息“遗忘”。
我也养成了一个习惯:每周用claude-mem export导出一次 Json 快照。不要完全相信本地库不会坏,尤其是跑了几百个会话之后,多一份备份总是安心。
6. 从个人工作流到团队共享:claude-mem 还能怎么用
6.1 独立数据库后端
默认的 SQLite 适合单机单用户。如果团队里好几个人共用一套 Claude 工作流,各写各的库就乱了。claude-mem 支持把后端切换到独立数据库,比如把数据落到团队内部的 MySQL 或 PostgreSQL。我目前在公司内网搭了一个共享实例,所有成员的项目记忆都写到同一个库,配合项目名做隔离。新同事接手项目时,只要查一次历史记忆,就能快速掌握前几轮讨论的决策脉络。
这个做法的前提是字段设计要规范。尤其是project和tags,团队里必须约定统一写法。否则 A 写web-doc-crawler,B 写doc-crawler,同名项目就会分裂成两条记忆线,召回也不稳定。我目前的做法是:在项目的 README 开头固定加一行“memory-project: web-doc-crawler”,成员开新会话时统一以这个标识打开。
6.2 把它嵌进 CI 的自动化流程
除了在对话中接入,claude-mem 也可以当普通 CLI 工具集成进脚本。我在 CI 里跑过一个定时任务:每天晚上把当天的 issue 讨论、代码 review 结论抽取成记忆条目,写入团队共享库,然后清理掉超过阈值的旧记录。
这个用法的好处是,即使没有人主动打开 Claude 做对话,项目的关键演进过程也会沉淀下来。等到将来要复盘“某个技术决策是什么时候定的”,直接在记忆库里按时间检索就行。虽然我自己更常用“对话中自动记录”的方式,但这个定时压缩方案确实适合维护频率低、但历史包袱重的老项目。
6.3 和知识库配合,而不是替代知识库
最后说一个容易被误解的点:claude-mem 不是知识库管理系统的替代品。知识库存的是“确定性的、可供查阅的资料”,比如 API 文档、架构设计文档、操作手册;记忆库应该存的是“动态的、会话级的决策碎片”,比如“这次我们选了方案 B,没选方案 A,因为性能测试数据不支持 A”。
如果把文档硬塞进记忆库,召回时很可能会产生上下文混乱。我试过把一个几十页的技术方案扔进 claude-mem,结果后面的对话里,模型频繁引用其中某一段,但抓取到的上下文又不够完整,反而比不带记忆时更容易“断章取义”。正确姿势是:文档继续放在知识库里,claude-mem 只负责记录“哪些文档是当前项目相关、这些文档在历次会话里被如何解读、最终做下了什么决定”。
这层配合做得好,Claude 既是那个懂背景的项目协作者,也是那个知道去哪里查权威资料的检索者,两层互补,效果最好。
我个人实际用下来的结论是:claude-mem 这类记忆层工具的成熟度还没有到开箱即用的完美状态,数据目录、召回阈值、团队规范都得自己磨合,但它解决了一个真实存在、且长期被忽略的问题——大语言模型会话之间的“断片”。如果你也在维护一个需要跨多轮、跨多天持续迭代的 AI 项目,不妨先以最小配置跑一周,把“自动注入记忆”这件事变成日常,再来评判它值不值得接入。