
忘了是第几次用户在群里问“Claude 能不能记住上次聊的事”——我第一反应是能但默认不能。Claude 本身有上下文窗口可窗口一关该忘的照样忘。真正长期项目跑起来之后需求变成了“让 Claude 记住两周前确认过的技术方案”而不是每次重新交代一遍。“claude-mem”就是冲着这个缺口做的在 Claude 应用外面加一个轻量记忆层把对话里的关键事实、结论、偏好抽出来落盘下次要用的时候再按需塞回上下文。它不是什么重框架也不依赖专门的向量数据库核心思路就是“抓重点、存下来、找得到、注入回”。如果你正在用 Claude API 或 Claude Code 搭自己的 Agent、客服机器人、自动化流程这篇文章会帮你把一个可用的长期记忆模块从零到一搭出来顺带把里面容易踩的坑都摆到明面上。1. 先把核心思路拆开记忆不是“聊天记录”1.1 为什么应用里必须加一层记忆先说一个很现实的问题Claude 的记忆能力取决于上下文窗口可窗口是有上限的。你不可能把三个月内的全部聊天记录都塞进 prompt那既塞不下也没必要。而且就算塞得下token 成本也扛不住。更重要的是原始对话里充斥着大量冗余信息——寒暄、语气词、重复的解释、局部无效的讨论。把这些全塞回给模型既浪费 token又会稀释关键信息。模型面对一堆噪声反而容易忽略真正重要的约束。所以“记忆”这个东西在应用层不该被设计成“对话存档”而应该是“结构化沉淀”。我们需要做的是把每次会话里的有效事件抽出来变成几条短小精炼的记录然后暂时存放在本地。下次模型需要参考时只检索相关条目回填到上下文里。熟悉 RAG检索增强生成朋友应该已经看出来了这种模式和 RAG 高度重合。但 claude-mem 更轻它不做复杂的混合检索也不做大规模文档切分它就是服务 Claude 单会话长期记忆这个场景。1.2 claude-mem 的五个功能模块拆解这个项目大致可以分成采集、处理、存储、检索、注入五个环节每个环节解决一块独立问题模块职责关键问题采集层拿到一次对话的原始文本或消息列表如何拿到干净、完整、可回放的对话数据处理层调用 Claude 对对话做摘要和事实抽取怎么用最小 token 换最大有效信息存储层把记忆条目写入本地文件或轻量 DB结构要可人读可机读方便后续维护检索层根据当前 prompt 找出相关历史记忆匹配方式要快、准、不丢上下文注入层把检索到的记忆拼进新的 request messages加在哪个位置、加多少条、如何控制 token第一版做的时候我最容易犯的错就是想着一步到位搞全流程自动化。实际上先把这五层边界划清楚后面加新功能才不会被绕进去。比如有人想换存储从 JSON 换成 SQLite如果处理层和存储层耦合得太死改一处全崩。claude-mem 这一套分层方式和我后来在公司做的 Agent 中间件几乎一致通用性很强。1.3 为什么不用一条龙全量存储中间也有人问我为什么不直接把所有对话分块存起来搜索的时候用关键词匹配全量存储看起来简单实际有两处硬伤。第一存储规模大。一个活跃项目跑几十轮迭代对话记录轻松破几万条即使只用文本文件查询性能也非常难看。第二检索质量差。用户前一天说“支付回调接口要加签名校验”第二天调 Claude 改支付模块关键词若是对不上模型根本想不起来。把每次对话压成几条“高密度记忆条目”再用带权重的语义检索来找是兼顾效果和成本的做法。我们现在看到的很多会话式 AI 产品本质都在做这件事不是在内存里硬记而是将要点“外置”起来。claude-mem 相当于给 Claude 装了个随身笔记本只记重点翻得快用完合上。2. 关键细节与设计决策记忆分几种、怎么存2.1 三种记忆类型别混在一起真上手之后我发现如果只分“长期”和“短期”两类远远不够。实际跑业务场景记忆至少得分三种会话级记忆Session Memory——当前这一轮对话里需要临时记住的中间状态比如“用户刚上传了一份 CSV表头是日期、金额、商品名”。对话结束就可以丢弃最多保留在临时文件里。项目级记忆Project Memory——和整个项目全局相关的长期事实比如技术选型、接口协议、验收标准、历史决策原因。这类记忆要跨会话持久保留是 claude-mem 存储的主体。用户级记忆User Memory——和具体终端用户绑定比如用户偏好的回复语气、常用术语、使用习惯。多租户场景下尤其重要。如果一上来就把三种记忆写进同一个文件后面检索时会互相干扰。你会搜出一堆用户偏好却找不到针对支付模块的决策记录。我的建议是分目录、分标识至少在存储层上做隔离检索时也优先限定对应 scope。2.2 目录结构与文件格式一个不依赖重数据库的实现用目录加 Markdown 文件就能跑通.claude-mem/ ├── sessions/ │ ├── 2025-06-01_payment-fix.md │ └── 2025-06-02_ui-refresh.md ├── projects/ │ ├── payment-gateway.md │ └── frontend.md └── users/ ├── alice.md └── bob.md记忆条目建议写成 Markdown每个条目包含“事件”和“结论”。这样人可以直接读模型检索回来也能用。举个例子--- scope: project tags: [payment, callback, security] updated: 2025-06-01 --- # 支付回调签名校验 ## 决策 回调接口必须校验 sign 参数使用 RSA-SHA256私钥由支付平台下发。 ## 背景 支付回调曾出现伪造请求导致订单状态被恶意篡改因此确定强制验签。这种格式有头信息front matter有正文描述。检索时可以先读头信息做快速过滤再对正文做语义匹配。更新时也可以按标签增量更新不用整文件重写。2.3 更新策略如何避免记忆互相冲突记忆写入和用户聊天是并行的这就出现一个大大坑模型今天说“回调验签用 RSA”明天又改成“统一走网关签名”旧记忆没删新记忆又进来了。两次检索都会命中模型反而会被弄晕。处理逻辑要做到“同主题覆盖”。我采用的方式是每条记忆维护一个“决策编号 标签集合”写入新条目之前先搜索同 scope、同标签的旧条目将状态标记为 superseded新条目主动指向旧条目编号。这样模型能看懂演进过程而不是两条互相打架的独立事实。这个细节容易被忽略却值得多花时间琢磨。很多所谓“模型记不住”其实不是模型问题是记忆库本身乱成一锅粥。2.4 安全问题什么内容不该进记忆记忆一旦落盘就代表“数据离开会话上下文”隐私边界必须重新审视。我在 claude-mem 里做了一条硬性过滤规则处理层抽取完信息之后先过一次脱敏组件把疑似密钥、Token、密码、身份证号、明文手机号这类内容打码再写入存储。宁可漏记不能乱记。命中的敏感信息只保留最后一截或直接写“已脱敏”。真正需要原文的场合单独走安全通道不走记忆库——这是我在实际项目里吃过亏之后总结出来的底线。3. 从零跑通一个 claude-mem 最小实现3.1 准备环境与初始化先交代一下基础依赖Python 3.10一个能访问 Claude API 的 Key加上本地的 OpenAI 或本地 embedding 模型即可。我这里演示先用内置的轻量检索不引额外向量库保证任何人照着能跑通。pip install anthropic claude-mem claude-mem init --dir ~/.claude-meminit 会在指定目录生成存储目录并创建默认配置文件。配置文件大致长这样memory: default_scope: project max_memories_per_prompt: 5 max_tokens_per_memory: 300 embedding_model: local-hash summarize_model: claude-3-5-sonnet这里有几个参数后面会被反复调整max_memories_per_prompt 控制回填数量太多会顶爆 token太少又不够参考5 是起步值。max_tokens_per_memory 限制单条记忆长度摘要阶段会强制按这个值压缩。embedding_model 我用 local-hash 是为了零依赖启动正式环境会切换到真正的语义向量模型。3.2 对话处理摘出记忆再落盘采集层拿到一组消息之后处理层要生成记忆。核心就是让 Claude 充当“记笔记的人”把对话压缩成若干条目。调用方式很直接from anthropic import Anthropic from claude_mem import MemoryStore client Anthropic() store MemoryStore(~/.claude-mem) def extract_memories(conversation): prompt f 你是一个记忆提炼助手。下面是一段对话请提炼出 【项目级决策】【用户偏好】【待办事项】三类记忆。 每条记忆控制在80字以内用Markdown列表输出。 对话内容 {conversation} resp client.messages.create( modelclaude-3-5-sonnet-latest, max_tokens1000, messages[{role: user, content: prompt}], ) return resp.content[0].text这段代码的原理是把“提炼记忆”当成一次独立任务不占用主会话上下文。实际跑出来的文本会是类似“决策支付回调必须做RSA-SHA256验签密钥由支付平台下发”这样的条目。这一步比想象中费 token所以要在对话结束或用户明确停顿后再执行而不是每一条消息都触发。提取完解析成结构化数据直接写入存储memories extract_memories(raw_text) store.add_entries(project, memories, tags[payment, callback])3.3 检索回填让 Claude 用上记忆记忆不注入等于白存。注入时机要比多数人想得更早——在构造主调用的 messages 之前就要完成检索。def build_prompt_with_memory(question, scopeproject): candidates store.search(question, scopescope, top_k5) memory_block \n\n.join([f- {m.text} for m in candidates]) system_prompt f以下是关于当前项目的历史记忆回答时优先参考 {memory_block} return [ {role: system, content: system_prompt}, {role: user, content: question}, ]历史记忆放进 system prompt 而不是 user prompt是我反复对比后的选择。模型对 system 层指令的遵循优先级更高放这里能有效避免被用户长文本淹没。检索的匹配逻辑先用关键词过滤再做简单的词频加权。真正语义匹配太依赖模型延迟高没必要在每个请求上都跑。如果后期记忆量超过几千条再引入 SQLite FTS5 或本地向量索引即可。3.4 自动清理与过期管理记忆不能只增不减。跑了一段时间后项目文件会长得越来越臃肿。claude-mem 的思路是给每条记忆加 created 和 updated 字段定期执行 prune 指令。过期策略有两种一是直接删除超过 N 天未引用的记忆条目二是把旧条目压成更浓缩的“月度摘要”。推荐后者保留历史脉络同时压缩体积。claude-mem prune --older-than 90d --compress这个命令会把 90 天前的记忆重新交给 Claude 做二次聚合生成一页顶多 20 条的“长线记忆”原条目进封存区。核心逻辑就是记忆也有生命周期没法一条记录永流传。4. 实操记录与问题排查4.1 典型故障速查表以我跑 claude-mem 三个多月的经验大部分问题集中在检索和注入两环。下面这张表可以直接当排查手册用现象可能原因处理方式模型完全不理历史记忆记忆放进了 user 消息且被长问题淹没改到 system prompt 中收紧指令语气同一段记忆反复注入浪费 token没有做去重也没限制最大条数开启同标签覆盖调低 top_k检索命中率越来越差记忆条目过长语义被稀释把单条记忆压缩到 20~60 字生成内容引用过期决策旧记忆没标记 superseded强制扫描同标签冲突置旧状态记忆文件乱码或格式错乱抽取层返回了非 Markdown 结构增加输出校验解析失败则跳过写入多用户共享记忆串数据scope 混用按用户维度拆分目录并限制检索范围这里面最严重的是“模型引用过期决策”。一旦发生用户会明显感觉模型“变笨了”。排查时先看检索命中的记忆条目是不是老版本再看旧条目有没有写死到 prompt 里。多数情况下是记忆更新逻辑没处理“覆盖”语义导致的。4.2 一次真实排障为什么搜不出转账限制的记录有次用户问“转账单笔限额多少”模型答得完全不对。翻了日志发现相关记忆条目里明明写着“单笔限5万大额需双人复核”但没被检索出来。进一步检查发现那条记忆存在 projects/payment-gateway.md 里但当时的提问带了很强的前缀“帮我改一下后台界面里转账相关的文案” 。检索层按词频权重打分把“后台”“界面”“文案”权重拉高导致“限额”“风控”这些关键词被稀释。我调整了两处一是检索时把名词短语权重调高二是加入“query 重写”环节——先让 Claude 把用户问题抽象成 3 个候选搜索词再做匹配。改完之后命中率明显提升。经验就是别指望一次检索满足所有问法用户不会按你存的关键词提问。有条件就加 query 扩展没条件也要在检索时做同义词归一。4.3 成本控制记忆模块不能变成电老虎每次调用 Claude 做摘要会额外消耗 token。控制不好记忆模块的开销可能比主对话还大。我实践下来的规则只在会话结束且消息数超过 10 条时才触发摘要摘要模型使用更便宜的快速模型不占主模型的并发重复出现的相同文件比对文件哈希后直接跳过检索时不把系统提示词重复注入只注入本次命中的记忆条目。这套做下来记忆模块的额外 token 开销能压到整体消耗的 10% 以内。一个常见误区是频繁对聊天记录做全量摘要这会带来大量不必要的费用。增量摘要和哈希比对才是长期维护的正解。5. 扩展路径与避坑心得5.1 从单机版走向团队共用的四个改造点单机版的目录文件方案在一个团队里会暴露出权限和共享问题。要变成团队可用至少要做四处改造存储迁移从本地目录换成 PostgreSQL 或 SQLite利用事务保证并发写入安全接入鉴权每条记忆带上 owner/project 等字段搜索时强制按权限过滤写入审批涉及“覆盖旧记忆”的操作预留 review 机制防止模型自动刷新造成集体串味审计日志记录谁在什么时间改过哪条记忆尤其是涉及删除操作的时候。这四个点不做完团队项目我不建议直接上不然很容易出现 A 同事的项目记忆把 B 同事的覆盖掉的问题。5.2 和 Agent 工具链结合的可能路径claude-mem 除了手动调用也可以做成 MCP 工具让 Claude 自主决定什么时候读记忆、什么时候写记忆。这个扩展方向我特别看好。设想一个场景用户要求“按上个月的需求文档更新 README”。Agent 通过工具调用读入对应历史的项目记忆再对比当前代码状态最后生成 diff。整个链路里记忆工具和普通检索 API 一样属于“按需调用”。这比每次把所有记忆都塞进上下文要优雅得多。要把工具接口做好关键是设计好入参。我的建议是至少提供三个参数scope、tags、max_results。scope 决定查哪个记忆域tags 做预过滤max_results 控制 token 上限。这些参数直接暴露给 Agent比让 Agent 猜文件名要可靠。5.3 个人实践中的几个反直觉体会第一条体会记忆条目越短越好用。写 300 字的记忆模型用起来反而容易丢重点20~40 字的关键短语命中率最高。所以宁可多拆几条不要堆长文。第二条体会不要试图让记忆模块“懂所有事”。它只是一块能长能短的便签真正复杂的关系和推导过程应该留在原始对话记录里。记忆库只有索引和结论复杂逻辑仍靠主模型去完成。第三条体会定期重构记忆库比整天调 prompt 有用得多。我会每个月把整个 .claude-mem 目录交给 Claude 做一次结构优化合并重复项、拆分混合主题、添加缺失索引。做完之后整个系统突然又变得可靠了这种“洗数据”带来的收益往往超过调整 prompt 模板。“claude-mem”并不复杂核心就是把对话里容易消散的重点稳定固化为可复用条目再通过注入机制把历史决策变成模型可感知的上下文。如果你也正在搭类似的东西我建议先跑最小实现再一步步把检索、覆盖、过期管理做厚。等跑了几周回头对比你会明显感觉到模型不再像一个只会面对当下问题的“失忆助手”而更像是那个真正参与过项目全过程的老同事。