
1. 为什么我说 Claude Code 缺的从来不是上下文而是记忆如果你主力用 Claude Code 写项目超过两周大概率遇到过这个场景昨天刚跟它确认过这个服务用 Go 重写接口保持兼容今天新开一个会话它又问你这个服务的接口定义在哪里你花半小时把项目背景、技术栈、目录职责讲得明明白白关掉窗口再打开它又变成了第一次见面的陌生人。Claude Code 本身不是没有上下文机制但那个 context 是会话级别的——进程活着上下文就在进程一关什么都留不下。你只能用两种笨办法对抗这个问题一是反复把背景信息粘贴进每一轮新对话二是维护一份越来越长、越来越难更新的 CLAUDE.md 手动喂给它。两种办法我都用过很长时间说实话都别扭。第一次听说 claude-mem 的时候我其实没抱太大期望。市面上给大模型对话加记忆的方案不少但大多停留在把聊天记录存到一个地方的水平检索时基本靠关键词 LIKE换个说法就找不到了更不要说在合适的时机自动把记忆注入回对话里。真正让我决定试一下的是它的设计思路和别的方案不一样它不存原始对话流水账而是让 Claude 自己从对话里判断哪些东西值得长期记住再按语义关联度检索、按需注入。这意味着记忆不是堆积是被筛选过、结构化过的。这篇文章我不打算复述一遍 README而是从实际接入和使用的角度把它的原理、配置过程、参数调优和踩过的坑一次讲清楚。适合谁看如果你正在用 Claude Code并且已经被每次开新会话都要重新交代一遍项目背景这件事折磨过这篇文章应该能帮你省下不少时间也让你对AI 伴侣到底能不能记得住我这件事有个更清醒的判断。2. 记忆的两种形态为什么非要同时用 SQLite 和 ChromaDBclaude-mem 的存储设计是我觉得它做得最聪明的地方。它没有把所有记忆一股脑塞进同一个数据库而是把信息分成两类各自用最合适的工具管理。理解了这个分层后面所有配置和调优你都能自己推导出来。2.1 结构化记忆专门回答事实是什么的问题第一类叫结构化记忆存储在 SQLite 里。这类记忆的特点是确定性高、字段清晰、适合精确查询。典型的例子包括这个项目使用 Python 3.11 和 FastAPI、用户偏好 TypeScript 而不是 JavaScript、数据库连接信息放在 .env 文件不要提交到 Git、这个 API 的鉴权方式是 Bearer Token。每条结构化记忆在 SQLite 里有几个关键字段memory_type 标记记忆类型content 存具体内容timestamp 记录创建时间source 指向来源会话importance 是重要度评分metadata 是附加的 JSON 元数据。这套字段设计让精确查询变得非常直接——比如你想知道用户对测试框架的偏好是什么直接跑一条 SQL 按类型过滤就能拿到精确结果根本不需要做向量相似度计算。SQLite 在这里的优势很明显轻量、单文件、查询语义确定、零运维成本。它适合放事实型记忆但不适合处理表达不同、意思相近的模糊语义匹配——那是下一类记忆的工作。2.2 语义记忆专门处理不同的话其实在说同一件事第二类是语义记忆存储在 ChromaDB 里。它的作用是解决语义关联问题。举个例子你某次对话里说这个服务的延迟太高了得想办法优化另一次对话里说API response time is really bad, we should do something。字面上完全不同但指向的很可能是同一件事。SQLite 的 LIKE 查询处理不了这种跨表达方式的关联向量检索可以。ChromaDB 会把每条语义记忆转换成 embedding 向量存起来检索时把用户当前的上下文也转成向量通过余弦相似度找到最相关的记忆。这个机制的含金量在于claude-mem 不需要你维护任何关键词规则不需要预设匹配模式它能靠语义层面的相关性猜到哪些记忆对当前对话有用。2.3 双库协作检索时怎么合并结果实际检索时claude-mem 会把两边的结果合并再经过一轮排序和过滤最终只挑出最相关的若干条注入给 Claude。合并策略大致是结构化记忆按重要度和时间衰减系数加权语义记忆按相似度得分加权两边归一化之后取 Top N。默认情况下注入条数有限这是刻意的——否则上下文会被一堆相关性不高的记忆撑爆反而稀释掉真正有用的信息。提示claude-mem 的设计理念是少而精。它宁可一次只注入 5 条高质量记忆也不愿意塞 50 条相关性一般的记录进去。理解了这条原则你就能明白为什么它要经过 LLM 抽取而不是简单地把对话原文搬进数据库。3. 接入全过程hooks 机制如何把记忆接进 Claude Code如果你看过 Claude Code 的文档应该知道它有一套 hooks 系统可以在特定事件发生时执行外部脚本。claude-mem 就是靠这个机制活着的它把自己挂到 PostToolUse、Stop、SubagentStop 这几个事件上在 Claude 每次回答完、或者完成某个工具调用之后自动触发记忆抽取逻辑。3.1 两条安装路径我推荐先用一键脚本claude-mem 提供了两种安装方式。我推荐用官方的一键脚本curl -LsSf https://raw.githubusercontent.com/thedaviddias/claude-mem/main/install.sh | sh这个脚本会做几件事检查 Python 版本要求 3.10 以上、把 claude-mem 安装到当前 Python 环境、创建配置目录、初始化 SQLite 和 ChromaDB 的存储路径。如果你电脑上有多个 Python 版本建议先确认默认 python3 指向的是 3.10 以上的版本否则装完可能会报依赖冲突。如果你更喜欢用 pip 控制安装细节也可以pip install claude-mem claude-mem initclaude-mem init会生成默认配置文件地址在 ~/.claude-mem/config.yml。这个目录名和 Claude Code 自己的配置目录 ~/.claude 只差一个后缀别搞混了。3.2 配置 Claude Code hooks这一步最容易被忽略装好 CLI 之后真正关键的一步是让 Claude Code 知道对话结束时要调用 claude-mem。方法就是编辑 Claude Code 的 hooks 配置。全局配置在 ~/.claude/settings.json项目级配置在项目根目录下的 .claude/settings.json。我建议先配全局的让所有项目都能用记忆跑通后再按需收窄范围。需要添加的 hooks 配置大致长这样{ hooks: { PostToolUse: [ { matcher: bash, hooks: [ { type: command, command: claude-mem capture } ] } ], Stop: [ { hooks: [ { type: command, command: claude-mem capture } ] } ] } }这里有一个非常实用的细节PostToolUse 事件触发的频率很高如果每个工具调用之后都执行一次 capturetoken 消耗会很夸张。所以建议加 matcher 限制触发条件比如只匹配 bash 类型的工具调用意思是只有 Claude 执行了 bash 命令之后才做一次捕获。Stop 事件是每次对话回合结束时触发这个频率比较合理通常不需要额外限制。3.3 三步验证怎么知道它真的在工作配置完之后怎么判断接入成功我的习惯是走一个简短的验证流程。第一步随便跟 Claude Code 聊几句说一些明确的偏好。比如我对这个项目的代码风格要求是注释要详细尤其是复杂函数。第二步等对话结束后用 CLI 查一下记忆claude-mem search 代码风格 claude-mem list --limit 10如果 list 有输出说明捕获流程已经跑通了。如果一直是空的优先排查三件事hooks 里 command 的路径是否真的指向 claude-mem 可执行文件、capture 执行时的环境变量是否正常、Claude Code 是否真的触发了 hooks可以看 verbose 日志确认。注意Mac 用户很容易踩一个坑——用 pip 的 user 目录安装包之后shell 里敲 claude-mem 能用但 Claude Code hooks 执行子进程时 PATH 不对找不到命令。解决办法是提前把 claude-mem 的 bin 目录加进全局 PATH或者在 hooks 配置里直接写绝对路径一劳永逸。4. 核心流程拆解一段对话是如何变成一条高质量记忆的claude-mem 最核心的步骤是 capture 命令。搞懂它你就知道为什么有时候抽出来的记忆质量高、有时候一团糟。4.1 capture 的三步流水线当 hooks 触发 capture 时claude-mem 会执行三个环节。第一步拉取当前会话上下文。它不是把整个历史对话都拿过来而是从 Claude Code 的上下文机制里取最近的有效内容包括用户消息、助手回复、工具调用结果。这样既保证抽取有足够信息量又避免重复捕获造成 token 浪费。第二步调用 Claude 对这段上下文做语义分析。claude-mem 会把一段结构化提示词发给 Claude让它判断这段对话里是否存在值得长期记住的信息。值得记住的定义非常关键主要包含几类用户明确表达的偏好、关于项目结构或技术栈的事实、用户身份相关的背景比如我是前端开发对后端不太熟、重要的决策记录、工具使用方法相关的知识。第三步把分析结果结构化写入存储。Claude 返回的信息会被解析成 JSON每条记忆带类型、内容、重要度等字段分别写入 SQLite 和 ChromaDB。写入 ChromaDB 之前还要做向量化这个环节消耗的是本地 CPU通常毫秒级完成。4.2 记忆抽取结果长什么样我用自己的实际数据举个例子。我在一次对话里跟 Claude Code 说过这个项目的 API 文档用 OpenAPI 规范维护每次改动 schema 要同步更新文档capture 之后记忆库里多了一条类似这样的记录{ id: 8f3a2b91, memory_type: project_context, content: API 文档使用 OpenAPI 规范维护改动 schema 后需要同步更新文档, importance: 4.2, timestamp: 2025-01-18T14:32:10Z, source: session_7c9e }注意这里的 memory_type 是 project_context不是 preference。这个分类直接影响后续检索时的权重策略所以 claude-mem 在抽取提示词里对类型定义得很细。如果你发现某些记忆的类型分得不准——比如应该算 project_context 的记成了 preference——可以去 Web UI 里手动改。4.3 记忆衰减机制为什么要让记忆被遗忘claude-mem 有一个被很多人忽略但非常实用的设计记忆是会时间衰减的。它给每条记忆算一个衰减后的权重公式大致是score importance × (0.5 ^ (age / half_life))half_life半衰期默认是 30 天意味着 30 天后这条记忆的权重只剩一半。这样设计的好处是老记忆不会永远霸占检索前排新近发生的、和当前工作相关的记忆有更大机会被注入。这和我们人脑的遗忘曲线有点神似不算坏事。我一开始觉得这功能多余甚至有点反感——凭什么我一周前确认的重要决策要被降权但实际用下来发现它非常合理。项目是演进的三个月前定的技术选型可能已经被推翻了如果那条记忆永远排在前面Claude 反而会不断给出过时建议。衰减不是删除只是降低权重数据还在你随时能在 Web UI 里翻出来。4.4 为什么抽取必须交给 Claude而不是规则引擎早期不少同类插件是用正则和关键词规则做信息抽取的效果非常死板你写用户偏好四个字它可能匹配到所有包含这四个字的句子。claude-mem 选择让 Claude 自己判断什么值得记本质上是让模型理解语义之后再决定而不是机械匹配关键词。代价也很明显每次 capture 都要消耗一次 LLM 调用有 token 成本。好在 capture 的输入是经过截断的对话片段不是全量历史实际消耗可控。这带来一个很直接的现象记忆质量高度依赖对话本身的质量。如果你跟 Claude 的对话里有大量废话、没有明确结论抽取出来的记忆自然也比较水。反过来如果每次对话都有清晰的决策和偏好表达记忆库会越来越值钱。它像一个传感器采集的是你对话过程里真正有价值的那部分信号。5. 从命令行到 Web UI日常管理记忆的两种姿势claude-mem 装完之后默认会提供一组 CLI 命令日常使用基本够用。但如果你想可视化管理记忆库、手动修正自动抽取的错误它还有一个 Web UI 模式。5.1 常用 CLI 命令速查我平时用命令最多的场景就三个查记忆、删错误记忆、看统计数据。下面这个表基本覆盖了需求命令作用备注claude-mem capture捕获当前会话并抽取记忆hooks 会自动调用claude-mem search 关键词语义搜索记忆走 ChromaDB 向量检索claude-mem list列出近期记忆可按 --type 过滤claude-mem stats查看记忆库整体统计数量、类型分布、存储占用claude-mem forget --id xxx删除单条记忆删了不可恢复慎用claude-mem prune批量清理低价值记忆建议配合 --dry-run 先预览claude-mem serve启动 Web UI默认监听 8080 端口search 是含金量最高的命令。比如说我忘了之前跟 Claude 确认过什么部署流程直接claude-mem search 部署它会按语义把相关记忆列出来比我回到聊天记录里往前翻几个小时高效太多了。5.2 Web UI可视化审查记忆库的必备工具跑claude-mem serve之后浏览器打开 http://localhost:8080 就能看到记忆列表。界面不花哨按时间倒序展示所有记忆每条带有类型、内容、重要度。最重要的是这里可以直接编辑或删除单条记忆。我强烈建议把定期翻看 Web UI变成使用习惯。因为自动抽取偶尔会抽出语气夸张但实际价值不高的记录。比如某次对话里你随口抱怨了一句这个框架怎么这么难用它可能当成 preference 记下来了。这些垃圾记忆如果不手动清理会在检索时挤占注入名额让真正有用的记忆反而排不上号。我给自己定的习惯是每周花两分钟扫一眼最近新增的记忆看到不合理的直接删掉。5.3 项目间记忆隔离与共享机制claude-mem 默认按项目隔离记忆这个默认值很靠谱。你在项目 A 里确认的用 pnpm 不用 npm不应该跑到项目 B 里去干扰那边的架构判断。它识别项目的方式是当前工作目录的路径不同目录天然分开。但有些记忆确实是跨项目的。比如你作为开发者有一套属于自己的代码风格偏好或者你希望在所有项目里都记住提交信息要遵循 Conventional Commits 规范。这类记忆可以在 Web UI 里标记为共享类型标记之后它们会出现在所有项目的检索结果里。这个设计对我来说非常实用——个人偏好和项目事实被清晰地分层了。6. 参数调优让记忆引擎适配你的工作节奏claude-mem 的默认配置对大多数场景是够用的但用了一周之后你大概率会想根据自己的工作节奏调整几个参数。配置文件在 ~/.claude-mem/config.yml编辑后立即生效不需要重启服务。6.1 三个核心参数半衰期、注入条数、重要度阈值配置文件里的记忆模块大概长这样memory: half_life_days: 30 max_memories_per_injection: 5 min_importance: 0.3第一个参数 half_life_days 控制记忆衰减速度。如果你的项目需求变化快、技术选型频繁调整建议调成 14 天让旧记忆更快让位如果是长期维护的稳定项目调到 60 天甚至 90 天更合适不然重要的架构决策权重掉太快。第二个参数 max_memories_per_injection 控制单次注入到对话里的最大记忆条数。默认 5 条偏保守。如果你发现自己项目里对话经常需要更丰富的背景信息可以调到 8 或 10。但我不建议贪多——记忆注入过多Claude 反而会分不清主次回答时会往偏离方向跑。第三个参数 min_importance 是重要度阈值低于这个分数的记忆不参与检索。它相当于一个垃圾过滤开关调高可以过滤更多低价值记忆但代价是有可能把一些隐含的、尚未明确表达的偏好也滤掉。6.2 按场景调整的参考配置我用过几套不同配置可以给你做个参考场景half_life_daysmax_memories_per_injectionmin_importance快速原型、需求频繁变化1480.2中型项目日常迭代3050.3长期维护、技术栈稳定6040.4这不是标准答案只是一种倾向。关键是理解每个参数的语义然后按自己的体感调整。如果发现某次对话里 Claude 提到了完全无关的记忆内容优先怀疑是 max_memories_per_injection 调太高了而不是记忆库本身坏了。提示上下文里混入一条无关记忆比上下文缺一条相关记忆更容易让 Claude 跑偏。因为它会试图合理化那条记忆把回答往记忆暗示的方向带。所以一旦发现噪声干扰宁可把注入条数降下来。6.3 自定义记忆类型让它更懂你所在领域的黑话claude-mem 支持在配置里增加自定义记忆类型。默认的 memory_type 有 preference、project_context、user_identity、tool_knowledge、decision_log 这些通用分类。但如果你所在领域有特殊的、高频出现的信息类别扩展一个类型非常有用。比如你是做运维的经常加班处理告警可以加一个 incident_response 类型你是做设计的可以加一个 design_rationale 类型专门记录设计方案背后的理由。配置方式是在 config.yml 里加一段类型定义并告诉抽取提示词这个类型下的内容应该满足什么特征。这样记忆库的分类会明显更贴近你的实际工作检索时的过滤也更精准。7. 实测体验与避坑记录文档里不会写清楚的细节最后这部分我想写几个实际使用中遇到的具体问题。这些问题不一定每个人都会碰到但碰到了很头疼而且排查起来比较隐蔽。7.1 权限问题导致的静默写入失败如果你用多用户系统或者 home 目录权限比较特殊claude-mem 初始化时创建的 ~/.claude-mem 目录有可能没有写权限导致 capture 静默失败。这个坑很隐蔽因为安装过程完全正常hooks 也触发了但记忆库一条记录都没有。排查方法很简单ls -la ~/.claude-mem/ touch ~/.claude-mem/write_test如果 touch 报权限错误直接 chmod 或者把目录属主改成当前用户。改完之后删掉测试文件再重新跑一次 capture 验证。7.2 ChromaDB 体积膨胀与定期清理语义记忆因为是向量存储随着时间推移 ChromaDB 的目录会明显变大。如果你跑 capture 的频率高几个月后可能发现 ~/.claude-mem/chromadb 占了好几个 GB。磁盘占用是一方面更大的隐患是检索速度下降。我的处理习惯是每隔一两个月做一次低价值记忆清理claude-mem prune --min-importance 0.2 --dry-run先加 --dry-run 参数看会删哪些确认结果没问题之后去掉 --dry-run 真正执行。低重要度记忆不一定都是垃圾但留存的成本是磁盘和检索速度定期收割一波是值得的。7.3 和 CLAUDE.md 的分工两条腿走路用了 claude-mem 几个月之后我越来越清楚它和 CLAUDE.md 的边界在哪里。CLAUDE.md 适合放那些你完全不希望被遗忘的项目级铁律比如禁止修改 src/legacy 目录提交之前必须跑 lint。这类信息需要 100% 的确定性不应该依赖检索概率。而 claude-mem 更适合放会话中动态产生、带有上下文性质的信息比如某个 bug 的完整排查结论、客户对某个功能的具体偏好、某次架构讨论的取舍逻辑。两者的配合关系是CLAUDE.md 管边界和红线claude-mem 管背景和记忆。单用任何一个都有明显缺陷配合使用才是最优解。7.4 成本压力最大的来源不是对话是 capture 频率最后说一个成本问题。claude-mem 每次 capture 都会调用一次 Claude 做抽取这意味着每次对话结束都会产生额外 token 消耗。对话量大的开发者一天下来这个额外开销积累得很快。我自己踩过一个跟这个相关的坑某天跑了一堆测试命令PostToolUse 里挂了 bash matcher结果触发了上百次 capture。虽然单次很快但积少成多那一天的成本明显增加。后来我把 capture 只挂在 Stop 事件上大幅减少了调用次数记忆质量反而更稳定——因为整段对话结束后做抽取上下文更完整判断也更准。这段经历让我想通了一件事claude-mem 这类工具的核心哲学其实是少即是多。少捕获、精抽取、准注入。调教好了它就像一个真正记得你喜好的老搭档调教不好它只是另一个存储废话的数据库。我现在每天开工前的例行操作是花一分钟打开 Web UI 扫一眼昨天的记忆更新确认没有抽到不该记的东西再开始干活。这个过程很短但能让 Claude 的每一次回答都更接近它真的了解我这个项目的状态。