1. 项目概述与核心定位
1.1 这个工具到底解决什么问题
claude-mem 是一个为 Claude 对话场景设计的记忆管理工具。它的核心目标很直接:让 Claude 在跨会话、跨项目的使用过程中,能够记住之前聊过的内容、做过的决策、踩过的坑,而不是每次开新窗口都从零开始。
我最初接触这个方向是因为一个很现实的痛点。日常工作中我会用 Claude 处理大量技术方案讨论、代码审查、架构设计类的问题,但每次新开一个会话,之前积累的上下文全部归零。你得重新解释项目背景、技术栈、约束条件,甚至之前已经否决过的方案还得再否决一遍。这种重复劳动累积起来非常消耗精力。
claude-mem 要做的就是把这层记忆持久化下来。它通过一套本地化的存储和检索机制,把对话中的关键信息提取、压缩、归档,然后在需要的时候自动注入到新的对话上下文中。你可以把它理解成一个专门为 Claude 服务的“外挂记忆层”。
1.2 适合哪些人使用
这个工具的目标用户画像比较清晰:
- 重度 Claude 使用者:每天有大量对话交互,跨会话上下文丢失造成明显效率损失的人。
- 多项目并行开发者:同时维护多个代码仓库或技术方案,需要 Claude 记住不同项目的背景和约束。
- 技术方案讨论场景:需要 Claude 记住之前的技术选型理由、架构决策记录、已知问题清单。
- 长期研究类工作:比如持续几周甚至几个月的研究课题,需要 Claude 保持对整体脉络的理解。
如果你只是偶尔用 Claude 问几个独立问题,那这个工具的价值可能没那么明显。但只要你的使用模式涉及“连续性”和“上下文累积”,claude-mem 就能显著改善体验。
1.3 核心设计理念
claude-mem 的设计哲学可以概括为三个关键词:本地优先、按需注入、分层压缩。
本地优先意味着所有记忆数据存储在本地文件系统中,不依赖任何外部服务。这既保证了数据隐私,也避免了网络延迟带来的体验问题。按需注入是指记忆不是无脑全部塞进上下文,而是根据当前对话的主题和关键词做相关性检索,只注入最相关的片段。分层压缩则是把原始对话经过多轮处理,从原始记录到摘要到关键要点,逐层提炼,既保留信息又控制体积。
这三个理念贯穿了整个工具的实现,后面我会逐一拆解每个环节的具体做法。
2. 核心架构与关键技术点拆解
2.1 整体架构分层
claude-mem 的架构从下到上大致分为四层:
| 层级 | 职责 | 关键组件 |
|---|---|---|
| 存储层 | 持久化记忆数据 | 本地文件系统、索引文件 |
| 处理层 | 提取、压缩、索引记忆 | 摘要生成器、关键词提取器 |
| 检索层 | 根据上下文匹配相关记忆 | 相似度计算、关键词匹配 |
| 注入层 | 将记忆注入对话上下文 | 上下文组装器、格式适配器 |
存储层用最朴素的方式——本地目录加 JSON 文件——来保存数据。这个选择看起来不够“高级”,但实际使用中非常可靠。你随时可以打开文件看看里面存了什么,出问题了直接手动改,不需要连数据库也不需要跑迁移脚本。
处理层是整个工具最核心的部分。它负责把原始对话内容变成结构化的记忆条目。这里面涉及几个关键决策:什么时候触发记忆写入、写入时提取哪些信息、如何压缩。
检索层的任务是在新对话开始时,根据当前输入的内容去记忆库中找相关条目。这里用的是关键词匹配加语义相似度的混合策略,纯语义检索在本地环境下计算成本太高,纯关键词又容易漏掉同义表达,两者结合是比较务实的方案。
注入层负责把检索到的记忆片段格式化成 Claude 能理解的上下文前缀,拼接到用户输入前面。格式设计上要尽量紧凑,避免占用过多 token。
2.2 记忆提取的触发时机
什么时候把一段对话标记为“值得记住”,这是整个工具设计中最需要斟酌的问题。触发太频繁会导致记忆库膨胀、检索噪音大;触发太少又会让关键信息丢失。
claude-mem 采用的是多信号触发策略:
- 显式标记触发:用户在对话中主动说“记住这个”或“这个很重要”,直接触发记忆写入。
- 会话结束触发:当一个会话被关闭或超时,对整段对话做一次摘要提取。
- 关键节点触发:检测到对话中出现代码块、配置文件、架构图描述等结构化内容时,单独提取为记忆条目。
- 周期性触发:每 N 轮对话做一次增量摘要,避免长对话后期信息被稀释。
我实际用下来,显式标记和会话结束这两个触发点覆盖了大部分有价值的场景。关键节点触发对技术类对话特别有用,因为代码片段和配置信息往往是最需要跨会话保留的内容。
2.3 记忆压缩的分层策略
原始对话直接存下来体积太大,检索效率也低。claude-mem 用了三层压缩:
第一层:原始记录。完整保存对话原文,但只保留最近 N 条,更早的会被压缩。这一层主要用于回溯和审计。
第二层:会话摘要。每个会话结束时生成一段 200-500 字的摘要,包含讨论主题、关键结论、待办事项。这一层是检索的主力。
第三层:主题索引。把多个会话的摘要按主题聚类,生成更高层的知识索引。比如“项目 A 的数据库选型”这个主题下可能聚合了五六个会话的摘要。
压缩过程不是简单的截断,而是用 Claude 自身来做摘要生成。具体做法是把对话内容发给 Claude,用特定的 prompt 要求它提取关键信息。这个 prompt 的设计很关键,需要明确告诉它保留什么、丢弃什么。
注意:摘要生成会消耗额外的 API 调用。如果你的使用频率很高,这部分成本需要纳入考虑。可以通过调整触发频率来控制。
2.4 检索匹配的混合策略
检索层的工作流程是这样的:新对话开始时,取用户的第一条输入作为查询,去记忆库中找相关条目。
匹配算法用了三个信号的加权组合:
- 关键词重叠度:对查询和记忆条目分别做分词,计算 Jaccard 相似度。这部分权重占 40%。
- 语义向量相似度:用本地的小型嵌入模型把查询和记忆条目转成向量,算余弦相似度。权重占 40%。
- 时间衰减因子:越近的记忆权重越高,按指数衰减计算。权重占 20%。
最终得分 = 0.4 × 关键词相似度 + 0.4 × 语义相似度 + 0.2 × 时间衰减。
这个权重分配不是拍脑袋定的。我做过一轮小规模的对比测试,纯关键词方案在技术术语匹配上表现好,但遇到换一种说法描述同一件事时就失效了。纯语义方案反过来,泛化能力强但精确匹配差。四六开的混合方案在测试集上综合表现最好。
语义向量用的是本地部署的小模型,不需要联网。模型体积控制在 100MB 以内,推理速度在普通笔记本上单条 50ms 左右,完全够用。
3. 实操部署与核心环节实现
3.1 环境准备与依赖安装
claude-mem 的运行环境要求不高,但有几个关键依赖需要提前处理好。
基础环境要求:
- Python 3.10 或以上(推荐 3.11,性能和兼容性平衡最好)
- 至少 2GB 可用磁盘空间(记忆库会随时间增长)
- 本地嵌入模型文件(约 80-100MB)
安装步骤:
# 创建虚拟环境 python -m venv claude-mem-env source claude-mem-env/bin/activate # Windows 用 claude-mem-env\Scripts\activate # 安装核心依赖 pip install sentence-transformers numpy scikit-learn # 下载嵌入模型(以 all-MiniLM-L6-v2 为例) python -c "from sentence_transformers import SentenceTransformer; model = SentenceTransformer('all-MiniLM-L6-v2'); model.save('./models/minilm')"这里选 all-MiniLM-L6-v2 作为嵌入模型有几个考虑:体积小(约 80MB)、速度快(CPU 上单条推理 30-50ms)、在短文本相似度任务上表现稳定。如果你对语义匹配精度要求更高,可以换成 paraphrase-multilingual-MiniLM-L12-v2,体积翻倍但中文支持更好。
目录结构规划:
claude-mem/ ├── data/ │ ├── raw/ # 原始对话记录 │ ├── summaries/ # 会话摘要 │ └── index/ # 主题索引和向量缓存 ├── models/ # 嵌入模型文件 ├── config.yaml # 配置文件 └── claude_mem.py # 主程序这个目录结构的设计意图是让不同层级的记忆数据物理隔离。raw 目录可以定期清理,summaries 是核心资产需要备份,index 目录可以随时重建。
3.2 配置文件详解
config.yaml 是整个工具的行为控制中心。我把关键配置项和推荐值列出来:
storage: base_dir: "./data" max_raw_entries: 500 # 原始记录最大保留条数 summary_retention_days: 180 # 摘要保留天数 extraction: trigger_on_session_end: true trigger_on_code_block: true periodic_interval: 10 # 每10轮对话触发一次增量摘要 min_content_length: 100 # 少于此长度的对话不触发记忆提取 retrieval: top_k: 5 # 每次检索返回的最大记忆条数 min_score: 0.35 # 最低相关性阈值 keyword_weight: 0.4 semantic_weight: 0.4 time_decay_weight: 0.2 time_decay_half_life: 30 # 时间衰减半衰期(天) injection: max_tokens: 800 # 注入记忆的最大token数 format: "compact" # compact | detailed几个参数需要重点说明:
min_score 设为 0.35是经过调参的。设太低会注入不相关的记忆,干扰对话;设太高会漏掉有价值的上下文。0.35 在我的使用场景下召回率和准确率比较平衡。如果你的记忆库内容比较杂,可以适当提高到 0.4。
time_decay_half_life 设为 30 天意味着一个月前的记忆权重减半。这个值适合项目周期以月为单位的场景。如果是长期研究项目,可以调到 60 或 90。
max_tokens 设为 800是考虑到 Claude 的上下文窗口虽然大,但注入太多记忆会挤占正常对话的空间。800 token 大约能容纳 3-5 条精简摘要,实际使用中够用了。
3.3 记忆提取的完整流程
记忆提取从对话结束或触发条件满足时开始,整个流程分为五个步骤。
第一步:内容预处理。把原始对话中的代码块、配置文件、命令行输出等结构化内容单独标记出来。这些内容在后续压缩时会被特殊处理——代码块保留原文,自然语言部分做摘要。
第二步:摘要生成。构造一个摘要 prompt,把对话内容发给 Claude。prompt 的核心要求是:
请从以下对话中提取: 1. 讨论的核心主题(一句话) 2. 达成的关键结论或决策(列表) 3. 提到的待办事项或未解决问题(列表) 4. 涉及的技术栈、工具、文件路径等关键实体(列表) 5. 如果对话中包含代码或配置,保留其核心内容 输出格式为 JSON,字段名分别为 topic, conclusions, todos, entities, code_snippets。这个 prompt 的设计逻辑是:topic 用于后续检索匹配,conclusions 和 todos 是记忆的核心价值,entities 用于建立实体索引,code_snippets 保留可复用的技术内容。
第三步:关键词提取。从摘要中提取关键词,用于建立倒排索引。关键词提取用的是 TF-IDF 加位置权重的方案。出现在 topic 和 conclusions 中的词权重更高,出现在 entities 中的技术术语单独加权。
第四步:向量化。把摘要文本用嵌入模型转成向量,存入向量索引文件。向量索引用的是简单的 numpy 数组加 faiss 的扁平索引,数据量在几千条以内时检索速度完全够用。
第五步:写入存储。把摘要 JSON、关键词列表、向量分别写入对应的存储文件。同时更新主题索引,把新记忆归入已有的主题簇或创建新簇。
实操心得:摘要生成的质量直接决定后续检索的效果。我在 prompt 里加了一条“如果对话中没有明确结论,conclusions 字段留空数组,不要编造”,这条约束显著减少了幻觉问题。
3.4 检索与注入的实现细节
新对话开始时,检索流程自动触发。用户的第一条输入作为查询,经过以下处理:
def retrieve_memories(query, top_k=5, min_score=0.35): # 1. 关键词提取 query_keywords = extract_keywords(query) # 2. 向量化 query_vector = model.encode(query) # 3. 加载所有记忆摘要 memories = load_all_summaries() # 4. 计算综合得分 scores = [] for mem in memories: kw_score = jaccard_similarity(query_keywords, mem['keywords']) sem_score = cosine_similarity(query_vector, mem['vector']) time_score = exp(-days_since(mem['timestamp']) / 30) total = 0.4 * kw_score + 0.4 * sem_score + 0.2 * time_score if total >= min_score: scores.append((total, mem)) # 5. 排序返回 scores.sort(reverse=True, key=lambda x: x[0]) return [mem for _, mem in scores[:top_k]]注入格式用的是 compact 模式,每条记忆压缩成一行:
[记忆] 主题:数据库选型讨论 | 结论:选用PostgreSQL,放弃MongoDB | 待办:评估连接池方案多条记忆按相关性排序后拼接,总长度控制在 max_tokens 以内。如果超出,优先保留得分最高的几条,后面的截断。
注入位置是在用户输入之前,用分隔符隔开:
--- 相关历史记忆 --- [记忆] ... [记忆] ... --- 记忆结束 --- 用户当前输入:...这个格式的好处是 Claude 能清楚区分哪些是历史上下文、哪些是当前问题,不会混淆。
3.5 主题索引的构建与维护
主题索引是记忆库的“目录”,它把零散的会话摘要按主题聚类,方便宏观检索和浏览。
聚类算法用的是层次聚类,距离度量用摘要向量的余弦距离。聚类的阈值设为 0.6,意味着相似度高于 0.6 的摘要会被归入同一主题簇。
每个主题簇有一个自动生成的标签,标签生成的方式是取簇内所有摘要关键词的 TF-IDF 最高几个词组合。比如一个簇的关键词是“数据库、PostgreSQL、连接池、性能”,标签可能就是“数据库选型与性能优化”。
主题索引的更新是增量的。新记忆写入时,先计算它与现有各簇中心的距离,如果小于阈值就加入最近的簇并更新簇中心,否则创建新簇。
注意:主题索引需要定期做一次全量重建,因为增量更新会导致簇中心偏移。我一般每积累 50 条新记忆就手动触发一次重建。重建过程大约需要几秒钟,对使用没有影响。
4. 常见问题与排查技巧实录
4.1 记忆检索不准确怎么办
这是最常见的问题。表现是:明明之前讨论过相关内容,但新对话开始时没有检索到,或者检索到了不相关的记忆。
排查思路按以下顺序进行:
第一,检查摘要质量。打开 data/summaries/ 目录,找到相关时间段的摘要文件,看看摘要是否准确反映了对话内容。如果摘要本身就跑偏了,检索肯定不准。摘要质量差通常是 prompt 需要调整,或者对话内容本身太零散没有明确结论。
第二,检查关键词提取。看看摘要中的关键词列表是否包含了你期望的检索词。如果关键词提取遗漏了重要术语,可以手动往关键词列表里补充,或者调整关键词提取的权重配置。
第三,调整检索参数。如果摘要和关键词都没问题,那就是检索参数需要调。可以尝试:
| 问题表现 | 调整方向 | 具体操作 |
|---|---|---|
| 检索不到相关记忆 | 降低 min_score | 从 0.35 降到 0.25 |
| 检索到太多无关记忆 | 提高 min_score | 从 0.35 升到 0.45 |
| 技术术语匹配差 | 提高 keyword_weight | 从 0.4 升到 0.5 |
| 同义表达匹配差 | 提高 semantic_weight | 从 0.4 升到 0.5 |
| 旧记忆被忽略 | 提高 time_decay_half_life | 从 30 天升到 60 天 |
第四,检查向量模型。如果你用的是英文模型处理中文内容,语义匹配效果会很差。确认模型支持你的主要使用语言。all-MiniLM-L6-v2 对中文的支持一般,中文场景建议换 paraphrase-multilingual-MiniLM-L12-v2。
4.2 记忆库膨胀过快怎么控制
用了一段时间后,记忆库可能积累了几百上千条摘要,导致检索变慢、噪音增多。
控制策略:
- 提高 min_content_length:把触发记忆提取的最小内容长度从 100 字提高到 200 字,过滤掉短对话。
- 关闭周期性触发:如果 periodic_interval 设得太小(比如 5),会产生大量碎片化摘要。调到 15-20 比较合适。
- 定期归档:把超过 90 天的摘要移到 archive 目录,不参与日常检索,但保留备查。
- 合并相似摘要:写一个脚本,把相似度高于 0.85 的摘要合并成一条。这个操作我一般一个月做一次。
# 合并相似摘要的简化逻辑 def merge_similar_summaries(threshold=0.85): summaries = load_all_summaries() merged = [] used = set() for i, s1 in enumerate(summaries): if i in used: continue group = [s1] for j, s2 in enumerate(summaries[i+1:], i+1): if j not in used and cosine_similarity(s1['vector'], s2['vector']) > threshold: group.append(s2) used.add(j) merged.append(merge_group(group)) return merged4.3 注入记忆后 Claude 回答变差
有时候注入记忆反而让 Claude 的回答质量下降,表现为:答非所问、被历史记忆带偏、或者把旧结论生搬硬套到新问题上。
原因分析:
- 注入的记忆与当前问题只是表面相关,实际场景不同。
- 注入格式不够清晰,Claude 分不清哪些是历史、哪些是当前。
- 注入内容太长,挤占了正常推理的空间。
解决方法:
- 提高 min_score 到 0.45,只注入高度相关的记忆。
- 在注入格式中加一句明确说明:“以下历史记忆仅供参考,如与当前问题场景不符请忽略。”
- 降低 max_tokens 到 500,强制精简。
- 如果问题确实和记忆无关,可以在对话开头加一句“忽略历史记忆”,手动禁用注入。
实操心得:我在 config 里加了一个开关
injection.enabled,默认开启,但遇到需要纯净对话的场景可以临时关掉。这个开关救过我很多次。
4.4 摘要生成消耗太多 API 调用
摘要生成需要调用 Claude API,如果对话频繁,这部分成本会累积。
优化方案:
- 批量处理:不要每轮对话都触发摘要,攒到会话结束一次性处理。
- 本地预筛选:先用本地规则判断对话是否值得摘要。比如包含代码块、包含“决定”“结论”“方案”等关键词的对话才触发。
- 降低摘要频率:把 periodic_interval 从 10 调到 20,减少增量摘要的次数。
- 用更小的模型做摘要:如果 API 支持,摘要生成用 Haiku 级别的模型,成本能降一个数量级,质量损失在可接受范围内。
我自己的配置是:只在会话结束时触发摘要,且对话长度超过 200 字才触发。这样一天下来摘要生成的 API 调用控制在 10-20 次,成本完全可接受。
4.5 数据备份与迁移
记忆库是长期积累的资产,丢了很麻烦。备份策略要简单可靠。
备份方案:
# 打包核心数据 tar -czf claude-mem-backup-$(date +%Y%m%d).tar.gz data/summaries/ data/index/ config.yaml # 恢复到新环境 tar -xzf claude-mem-backup-20250101.tar.gzraw 目录不需要备份,因为它是原始对话记录,体积大且价值密度低。summaries 和 index 是核心,必须备份。config.yaml 也建议一起打包,方便在新环境快速恢复配置。
迁移到新机器时,注意嵌入模型文件也要一起拷贝,或者在新机器上重新下载。模型文件在 models/ 目录下,大约 80-100MB。
4.6 常见问题速查表
| 问题 | 可能原因 | 快速解决 |
|---|---|---|
| 检索不到记忆 | min_score 太高 | 降到 0.25 试试 |
| 检索到无关记忆 | 摘要质量差 | 检查 summaries 目录 |
| 中文匹配差 | 模型不支持中文 | 换多语言模型 |
| 记忆库太大 | 触发太频繁 | 提高 min_content_length |
| 注入后回答变差 | 记忆不相关 | 提高 min_score 或临时禁用 |
| API 成本高 | 摘要太频繁 | 改为仅会话结束触发 |
| 向量检索慢 | 记忆条数过多 | 归档旧记忆或重建索引 |
| 主题索引混乱 | 增量更新偏移 | 手动触发全量重建 |
5. 进阶用法与扩展思路
5.1 多项目隔离
如果你同时维护多个项目,不同项目的记忆混在一起会互相干扰。claude-mem 支持按项目隔离记忆库。
实现方式是在 config 中增加 project 字段,不同项目的记忆存储在不同的子目录下:
data/ ├── project-a/ │ ├── summaries/ │ └── index/ ├── project-b/ │ ├── summaries/ │ └── index/ └── shared/ └── summaries/ # 跨项目通用的记忆检索时优先查当前项目的记忆库,如果结果不足再查 shared 库。这个设计让项目间的记忆既隔离又能共享通用知识。
5.2 记忆的手动编辑与修正
自动生成的摘要不可能百分百准确。claude-mem 的摘要文件是纯 JSON,可以直接手动编辑。
我经常做的修正是:
- 补充遗漏的关键结论。
- 删除摘要中不准确或过时的内容。
- 调整关键词列表,加入更准确的检索词。
- 修改主题标签,让分类更符合自己的认知习惯。
编辑完摘要后,需要重新生成向量和更新索引。工具提供了一个 rebuild 命令:
python claude_mem.py rebuild --summary-id abc123这个命令会重新计算指定摘要的向量并更新索引,不需要全量重建。
5.3 与其他工具的集成
claude-mem 的记忆数据是纯文本 JSON,很容易和其他工具集成。
与笔记软件集成:写一个脚本把 summaries 导出为 Markdown,导入到 Obsidian 或 Notion 中,形成可浏览的知识库。
与代码仓库集成:把技术决策类的记忆导出为 ADR(架构决策记录)格式,提交到代码仓库的 docs 目录。
与任务管理集成:把记忆中的 todos 字段提取出来,同步到任务管理工具中。
这些集成的实现都不复杂,核心就是读 JSON 然后转换格式。我自己的做法是每周跑一次导出脚本,把记忆库同步到 Obsidian,方便回顾和检索。
5.4 记忆质量的自评估
定期评估记忆库的质量,可以帮你发现系统性问题。
评估指标:
- 检索命中率:随机抽 20 次检索,人工判断有多少次返回了真正相关的结果。目标 > 70%。
- 摘要准确率:随机抽 20 条摘要,对照原始对话判断摘要是否准确。目标 > 85%。
- 记忆利用率:统计注入的记忆中有多少被后续对话实际引用。这个指标低说明检索策略需要优化。
我一般每个月做一次这样的评估,花不了多少时间,但能及时发现记忆库的退化趋势。
5.5 性能优化经验
当记忆库积累到一定规模(几千条摘要),检索速度会开始下降。以下是我实测有效的优化手段:
向量索引优化:从扁平索引换成 IVF 索引,检索速度提升 5-10 倍。代价是召回率略微下降,但可以通过调整 nprobe 参数来平衡。
关键词索引优化:用倒排索引替代全量扫描。只对包含查询关键词的记忆计算完整得分,其余跳过。
缓存机制:把最近 7 天的高频检索结果缓存起来,避免重复计算。缓存命中率在我的使用场景下大约 30%。
异步处理:摘要生成和向量化放到后台线程,不阻塞主对话流程。用户感知不到延迟。
这些优化做完之后,即使记忆库有 5000 条摘要,单次检索也能控制在 200ms 以内,完全不影响使用体验。
5.6 后续可以扩展的方向
claude-mem 目前是一个相对轻量的工具,但架构上留了不少扩展空间。
记忆重要性评分:给每条记忆打一个重要性分数,检索时作为额外权重。重要性可以根据被引用次数、用户手动标记、内容类型等因素综合计算。
自动遗忘机制:模拟人类记忆的遗忘曲线,长期不被检索且重要性低的记忆自动降权或归档。
多模态记忆:目前只处理文本,未来可以扩展到图片、截图等内容的记忆管理。
协作共享:团队场景下,把记忆库放在共享目录,团队成员可以共享技术决策和项目上下文。
这些扩展方向我自己也在陆续尝试,有些已经跑通了原型,有些还在设计中。核心思路是保持架构的简洁性,每个扩展都是可插拔的模块,不影响核心功能的稳定性。
我个人在实际使用中最大的体会是:记忆工具的价值不在于技术多复杂,而在于它是否真正融入了你的工作流。claude-mem 的很多设计决策都是围绕“不打扰”这个原则做的——后台静默处理、按需注入、随时可手动干预。用了一段时间之后,你会发现自己越来越少重复解释背景信息,Claude 的回答也越来越贴合你的实际场景。这种体验上的改善是渐进式的,但累积起来非常可观。