
要不要给 Claude 装个记性聊聊我实际用 claude-mem 的经历如果你天天用 Claude 做开发、写文档、处理长流程任务大概早就发现一个烦心事对话一长它就开始选择性失忆——昨天讨论过的接口设计今天问起来像第一次听说上一轮刚确认的命名规则下一轮它又按自己的理解来。Claude 本身不提供长对话记忆能力这是模型机制决定的抱怨没意义但活总得接着干。我用的解决方案是一个叫 claude-mem 的小工具名字很直白给 Claude 补一记记忆。它不是模型本身的升级而是通过命令行在本地持久化保存每一轮对话的关键信息让后续会话能按需检索、回填相当于给 Claude 配了个外部硬盘。这篇文章不聊什么玄乎的 AI 技巧就是我把这个工具从安装、配置到实际跑项目踩过的坑、总结出的用法全部分享出来。不管你是想给自己的 Claude 工作流加点缓存还是想看看 CLI 工具怎么跟大模型会话结合这篇都能给你一个能直接照做的参考。1. 需求拆解对话失忆的真正痛点1.1 大模型会话为什么记不住事先说个基本概念Claude 这类模型本身有上下文窗口比如一次能容纳几万 token超过这个长度就必须丢前面的内容。但实际用下来真正的瓶颈不是 token 数量而是信息价值密度。一个项目对话进行两小时后前面积累的决策、偏好、命名习惯只占很少的 token可一旦被挤出窗口后面所有回答都会失去这些上下文约束。更麻烦的是每次新开会话Claude 面对的是一个空白的上下文。它知道的知识是通用的但不知道你这个项目特有的约定。这就像来了个能力很强的新同事你每次都要重新交代项目背景、命名风格、已知结论他还未必记住。我早期试过的手动方案是每次对话快结束时让 Claude 自己总结要点然后复制到笔记里。下次开头再粘贴回去。能用但太笨了——总结质量参差不齐复制粘贴容易出错而且多轮之后越来越敷衍到后面干脆只写两行页面组件已完成。这就是 claude-mem 这类工具存在的真正意义把记忆变成自动化流程而不是靠人去维护。1.2 开发者真正需要的是上下文快照我梳理自己实际使用场景发现对记忆的需求分三层事实层做过哪些决定选了什么技术方案改了哪些文件偏好层代码风格偏好、命名习惯、回答问题时希望用什么形式复用层已经验证过的解决方案后续可以直接调用三层里第一层最紧急第二层影响长期协作质量第三层是锦上添花。 claude-mem 的定位就是解决好第一层兼顾第二层。它把每次对话的关键信息提取出来按会话归档提供检索能力并把最相关的历史记忆作为前缀注入下一次对话。这样做的好处很明显不需要模型原生支持持久记忆也不需要改模型调用方式主动权完全在你手里。需要它就拉取不需要就忽略记忆的增删完全可控。1.3 把记忆做成外部器官而不是内部补丁市面上也有给 Claude 加记忆的轮子但大多是在系统提示词里塞一长串历史告诉模型记住这些。这本质上是把记忆塞进上下文窗口一旦对话拉长仍然会被挤掉。 claude-mem 的思路不太一样它是把记忆存储在你的本地文件系统里到需要的时候再检索出来注入当前会话。相当于从让模型自带记忆变成了让工具替你记忆。这种外部器官式设计的核心价值是解耦记忆的保存、检索、删除、统计全部和模型能力无关。你可以随时换模型平台记忆数据仍然是你的。这也是为什么我后来坚持用这类工具而不是依赖任何平台的官方记忆功能——数据归属权在自己手里才真正踏实。2. 总体设计记忆到底装成什么样子2.1 核心数据模型消息、会话、记忆claude-mem 的底层数据模型很朴素几乎没有学习成本。它把记忆分为三个层次消息层每条用户消息和 Claude 的回复按时间戳和角色存储会话层以对话开始时间或会话 ID 为维度把一组消息归入同一会话记忆条目层从消息中提取出的、值得长期保留的信息片段记忆条目是核心。它不是原始消息的全文而是经过压缩的要点型文本。比如你在一轮讨论里说用户认证用 JWT过期时间设 60 分钟这条完整消息可能很长但沉淀出的记忆条目只需一句认证方案采用 JWT过期时间为 60 分钟。存储格式我用的是 JSONL每行一条 JSON。选这个格式的原因很实际追加方便就算文件很大也不需要全部加载逐行读取速度快出问题的时候能准确定位到某一行。如果你考虑自己实现建议不要用单个大 JSON 文件追加和并发写都会很痛苦。每条记忆我加了几个字段ID、所属会话ID、内容、来源消息ID、创建时间、标签。标签是手工斟酌的后面可以按标签过滤这在实际检索时帮了大忙。2.2 会话恢复让新对话继承旧记忆会话恢复是这个工具最有实用价值的部分。假设你昨天讨论了一个组件设计方案今天新开对话想继续不带任何上下文直接问Claude 大概率会重新发挥。 claude-mem 的做法是新对话开始时指定一个会话 ID它会把该会话下按时间倒序排列的记忆条目取出来作为上下文前缀注入系统提示词。注入量要控制。我一般取最近 20 条或者按标签过滤后取最相关的 10 条。这里有个关键细节注入的是记忆要点不是原始对话全文。原始对话可能几百条消息但提炼成记忆后可能只有 30 条。上下文占用大幅减少信息密度反而更高。这个压缩动作本身其实才是记忆系统的价值所在。 Claude 原生的上下文窗口再大也经不起无限塞原文但只要提炼成要点几百轮对话的记忆也能压缩进一个可控的 prompt 空间。2.3 记忆聚合跨会话的主题聚类除了单会话恢复 claude-mem 还支持跨会话的记忆聚合。比如你过去几周和 Claude 聊了好几个主题但都给同一个会话 ID这时可以按标签分组统计看看哪些主题密度最高。这个功能一开始我觉得是锦上添花直到有次想复盘一周工作发现能一条命令拉出本周讨论过的所有与数据模型相关的记忆才意识到它的价值它让你能以主题维度审视与 Claude 的协作历史而不是一条条翻原始记录。聚合的触发方式目前比较基础就是按标签或关键词过滤后分组。但基础够用就行实操中真正高频的场景是我记得我们聊过 XX但忘了细节——这时一次关键词检索比肉眼翻对话快太多。3. 核心实现一个能跑的 claude-mem 最小版本3.1 环境准备与目录规划在讲实现之前先说明我实际用的是 claude-mem 社区版命令行工具但为了弄明白原理我自己也写过一个最小实现。下面说的流程和代码是我抄作业 改作业后总结出的经验可以直接照做也可以按需修改。跑通这个工具需要三个基础依赖# Python 3.9 python3 --version # 可选用 uv 做依赖管理比 pip 快很多 curl -LsSf https://astral.sh/uv/install.sh | sh # 创建项目目录 mkdir -p ~/claude-mem cd ~/claude-mem目录规划上我建议把数据文件单独放一个目录别和代码混在一起。用环境变量指定数据路径这样升级代码不会影响已有记忆数据export CLAUDE_MEM_HOME$HOME/.claude-mem mkdir -p $CLAUDE_MEM_HOME/sessions $CLAUDE_MEM_HOME/memories会话原始归档和记忆提炼文件我分开存原因后面在踩坑部分会细说。3.2 CLI 命令行设计claude-mem 本质上是一个 CLI 工具核心命令就四五个。我优化的命令设计是这样的claude-mem record --session demo --role user # 记录一条用户消息 claude-mem record --session demo --role assistant # 记录 Claude 回复 claude-mem recall --session demo # 恢复会话记忆 claude-mem search --query JWT # 全局搜索 claude-mem stats --session demo # 统计这个设计有一个核心思路record负责写入recall负责读取search负责跨会话检索。职责清晰没有复杂的子命令嵌套。用 Python 里的 argparse 实现很简单import argparse def main(): parser argparse.ArgumentParser(descriptionClaude memory tool) subparsers parser.add_subparsers(destcommand) rec subparsers.add_parser(record) rec.add_argument(--session, requiredTrue) rec.add_argument(--role, choices[user, assistant], requiredTrue) recall subparsers.add_parser(recall) recall.add_argument(--session, requiredTrue) recall.add_argument(--limit, typeint, default20) search subparsers.add_parser(search) search.add_argument(--query, requiredTrue) args parser.parse_args() # ... dispatch3.3 消息记录与记忆提炼record命令是写入侧的核心。它做两件事把原始消息追加到会话归档如果这条消息包含值得保留的信息提炼成记忆条目写入记忆库。原始消息追加很直接JSONL 一行一条import json from datetime import datetime from pathlib import Path def save_message(session_id, role, content): path Path(os.environ[CLAUDE_MEM_HOME]) / sessions / f{session_id}.jsonl path.parent.mkdir(parentsTrue, exist_okTrue) record { id: uuid4().hex, ts: datetime.utcnow().isoformat(), role: role, content: content, session: session_id } with open(path, a) as f: f.write(json.dumps(record) \n)记忆提炼稍微麻烦一点。最直接的办法是调用 Claude 的 API让它把消息压缩成要点。但如果你不想在每次记录时都调 API费钱也费时间可以做一个简化版基于长度和内容特征自动截取。我当时的判断是超过 120 字的消息才值得提炼标准句式的决策型内容包含选择决定确定用等动词直接提取。这个规则简单但有效覆盖了大部分场景。完整版可以后续接模型调用把质量再提一档。3.4 记忆恢复的注入逻辑recall命令是读取侧的核心。它从记忆库中读取指定会话的条目按创建时间倒序取前 N 条然后转为文本块作为上下文前缀。def recall_memories(session_id, limit20): mem_path Path(os.environ[CLAUDE_MEM_HOME]) / memories / f{session_id}.jsonl if not mem_path.exists(): return [] lines mem_path.read_text().strip().split(\n) records [json.loads(x) for x in lines[-limit:]] return records注入到 Claude 的 prompt 时我用一个明确的标记块archive_memory 此处为 claude-mem 检索到的历史记忆 - 认证采用 JWT过期 60 分钟 - 用户表增加 email 唯一索引 - 前端路由已完成 3 个页面 /archive_memory这个格式起了很大作用。Claude 能明确区分记忆背景和当前真实提问不会把历史内容错当成当前指令。有次我没加标记直接把记忆文本和问题拼在一起结果 Claude 把一段历史结论当成了当前待办回答跑偏。加了清晰的分隔标签之后这个情况再没出现过。3.5 模糊搜索实现search --query 关键词这个命令单靠简单字符串匹配太弱。我用了 sqlite3 的 FTS5 全文检索把 JSONL 数据导入一个内存数据库建全文索引。速度很快几万条记忆毫秒级返回。import sqlite3 def search_memories(query, limit10): conn sqlite3.connect(:memory:) conn.execute(CREATE VIRTUAL TABLE mem USING fts5(content)) # load memories ... res conn.execute( SELECT content, session, ts FROM mem WHERE content MATCH ? LIMIT ?, (query, limit) ).fetchall() return res这个命令的价值在于跨会话检索。比如你三个月前和 Claude 讨论过数据同步方案但当时在哪个会话里已经忘了直接 search 就能捞回来。这个场景单靠会话恢复解决不了必须有一个全局索引。建议从一开始就做好 search 能力别等记忆攒多了再补那时 JSONL 已经很大遍历会很慢。4. 实际使用我的一周工作流实录4.1 一次完整的会话流程我用一个实际场景说明整套工作流怎么跑。周一早上我准备继续开发某跨平台系统的订单模块。直接新开一个 Claude 对话然后先执行两件事claude-mem recall --session order-module --limit 25输出大概是这样[记忆恢复] order-module 会话最近 25 条 - 订单状态机created - paid - shipped - done - 支付回调需做幂等处理增加 request_id - 库存扣减用乐观锁版本号字段已加 - 订单列表接口分页参数已确定page/page_size - ...我把这些内容复制进 Claude 对话作为背景资料。然后才开始问问题。这条命令让我省去了至少 10 分钟的背景复述时间更关键的是Claude 的回答从一开始就落在之前确定的方案框架内而不是另起炉灶。会话过程中我关键的操作是每当一个重要决定确认下来就手动执行一次claude-mem record --session order-module --role user \ --content 确认订单详情页展示物流轨迹接口返回轨迹数组按时序排列这里有一个实操要点record记录的内容不一定是用户提问的原文而是提炼后的结论。也就是说如果你在对话中让 Claude 确认了某件事可以自己把结论整理成一句简洁的话再写入。这个动作看似繁琐但换来的是后续记忆恢复时的高质量上下文。用确认决定注意这类前缀开头效果更好。一天的开发结束后整个会话过程的核心决定都沉淀在记忆文件里了。第二天继续时一行 recall 就能接上进度。4.2 记忆摘要的自动提炼 vs 手动提炼用了一段时间后我对记忆是怎么来的这个问题有了更深体会。理论上最理想的状态应该是全自动每条用户-Claude 对话结束后自动提炼成要点。这也是 claude-mem 完整版的设计方向。但实际执行时全自动有一个隐蔽问题提炼出来的要点质量不稳定。因为提炼动作如果依赖模型 API那每次对话后都要多一次调用如果依赖规则就会有大量冗余或漏提。我的折中方案是自动记录原始消息手动提炼关键结论。具体操作是每周五用一次 search 拉出本周所有记忆发现有重复或失效的条目批量清理一下。这样既保证了记忆的完整覆盖又维持了要点条目质量。4.3 何时该让 Claude失忆这一点可能和直觉相悖但我认为和记忆工具打交道久了选择性失忆反而比全记住更重要。有次我往某会话里塞了一个已经废弃的接口方案后续每次 recall 它都会出现在前缀里Claude 也会时不时把旧方案引入新讨论造成混乱。排查了半天才定位到是记忆污染。从那以后我开始定期清理记忆凡是已经明确废弃的设计、完成并无需回顾的任务、错误过的中间结论一律删除。claude-mem 里删除记忆的方式是直接编辑对应 JSONL 文件删掉不需要的行。我建议每两周固定清理一次别等记忆库膨胀到影响检索时才动手。记忆的价值不在于多而在于需要时找得到不需要时不碍事。另外注意不要把密码、密钥、内网地址这类敏感信息写入记忆库。因为记忆文件是纯文本 JSONL一旦泄露就是所有上下文同时泄露。我一般规定涉及密钥的信息在记忆条目里只写密钥已配置于某环境管理工具不放具体值。5. 踩坑记录与排查手记5.1 JSONL 并发写入问题第一个坑出现在同时开多个终端窗口操作的时候。两个终端几乎同时执行claude-mem record --session order-module结果出现文件内容交叉JSONL 中间一行变成了半截 JSON。排查后发现是追加写入没有加锁。解决办法很简单写操作用文件锁包起来。Python 里可以用fcntl.flockimport fcntl def append_with_lock(path, line): with open(path, a) as f: fcntl.flock(f, fcntl.LOCK_EX) f.write(line \n) fcntl.flock(f, fcntl.LOCK_UN)如果你在 Windows 上跑fcntl不可用可以用threading.Lock加进程内锁或者退一步接受偶尔的冲突——毕竟 claude-mem 本身就是单用户工具并发场景不算高频。但这个坑让我意识到任何追加写入型工具只要有可能被并发调用锁就是必需品。5.2 模糊搜索命中过多search 订单返回 300 条结果这不算搜索失败但也几乎等于没用。第一次遇到时我以为是搜索实现有问题后来发现症结在于FTS5 默认把 订单 匹配到所有包含这两个字的记忆条目而这些条目里很多只是顺带提到并非核心主题。解决办法是给搜索命令加一个排序权重关键词出现在开头比出现在结尾分值更高包含关键词的记忆条目比引用了关键词的条目更靠前。另外可以在 query 里用引号做短语匹配比如search --query \订单状态机\能显著提升精确度。实际使用中我发现对记忆条目做标签 关键词的组合检索最有效。比如给记忆条目加decision、bugfix、api这些标签然后 search 时同时过滤标签和关键词噪声会大幅下降。5.3 角色标识混乱--role user和--role assistant如果填反了记忆库里所有对话方向就反了。这个问题听着低级但恰恰是高频事故——因为很多时候你是手动复制粘贴对话内容复制着复制着就分不清哪条是谁说的了。我的解决方案是在 record 前先看一眼消息原文的角色标识不要凭感觉判断。如果批量记录建议把所有 user 消息放在一起先记再记 assistant 消息而不是一条一条交替来因为交替时最容易贴错。另一个更隐蔽的问题是如果你记录的是提炼后的结论角色其实已经没有意义了。结论是双方讨论共同得出的不是某一方的发言。这种情况下我干脆用--role summary这类额外角色来标记检索时看到 summary 就直接知道这是一条结论性记忆不是对话原文。5.4 记忆恢复导致上下文暴增recall --limit 20每条约 50 字换算下来约 1000 字上下文完全没有压力。但如果你把 limit 改成 100 或者 200很快会发现一个问题记忆本身占用的 token 越来越多而留给真实对话的空间越来越少。更麻烦的是久远的低价值记忆会淹没近期的重要决策Claude 会对当前重要的事失去判断。所以务必控制恢复数量。我实测下来15 到 25 条是最佳区间。如果真的要回顾很多条用 search 去定向检索而不是把几百条一股脑塞进 prefix。另外恢复记忆时要按时间倒序取--记忆越新鲜越重要这个原则在几乎所有场景下都成立。早期我把升序和倒序搞反过结果 Claude 的意识还停留在三个月前的旧方案上白白浪费了半天排查。5.5 特情升级工具的迁移问题claude-mem 更新版本后JSONL 的字段可能变化比如新版增加了tags字段旧数据没有。我的建议是升级前先备份数据目录然后用一个一次性脚本把旧文件补成新格式。如果迁移中有复杂的数据转换不要迷信工具自带迁移命令先跑一次diff确认数据没丢。数据是这整个工具唯一真正不可再生的资产。代码可以重写模型可以换但三个月的记忆沉淀一旦丢就真的是从头来过。我对它的态度一直是定期留备份操作前先想清楚再删。6. 一点个人体会用 claude-mem 这段时间我的一个直接感受是它解决的不是一个高大上的技术问题而是一个很日常但切肤的问题你跟 AI 的协作能不能像跟同事协作一样有连续性和沉淀。以前每开一个新对话之前的上下文就断了所有方案、决定、偏好都归零。现在有了记忆层至少昨天讨论的东西今天还在上周做过的决定下个月还能查到。如果你打算自己动手实现一个类似的记忆工具我的建议是先做一个最小闭环——只做 record、recall、search 三个命令存储用 JSONL外加一个 sqlite 索引。不用一上来就加各种复杂功能。用一段时间积累真实的使用场景后再往里面加自动摘要、多会话聚合这些进阶能力。工具的价值是解决问题不是堆功能claude-mem 本身的气质也是这样。再补一个小技巧把 claude-mem 的命令封装成 shell 别名能省很多事。比如alias cmrclaude-mem record --session alias cmlclaude-mem recall --session alias cmsclaude-mem search --query这样实际操作时手都不需要离开键盘太多效率提升明显。用顺了之后你会感觉跟 Claude 的合作方式不知不觉变了——不是每次对话都是初次见面而是越来越像一个有积累、有共同记忆的老搭档。