如果你跟我一样每天都要跟 Claude 这类编程助手打交道一定遇到过这种让人抓狂的瞬间昨天刚讨论过的项目架构今天开一个新会话它全忘了。你得重新把背景贴一遍把上次的结论再讲一次运气不好还要把踩过的坑原原本本复述一遍。这种“间歇性失忆”是当前大模型会话机制的天生短板——每次对话都是独立上下文聊完即焚下次从头再来。我做了个小工具叫 claude-mem目的就是给 AI 助手补上这一块“长期记忆”。简单说它能把每次会话中产出的事实、决策、偏好自动沉淀成可复用的记忆文件并在下一次会话开始前重新注入到提示词里。适合谁用三类人最需要经常用编程助手做项目的开发者、需要维护多个项目上下文的技术负责人、还想给 AI 工作流做自动化沉淀的折腾党。如果你只是想随手问点问题这个工具意义不大但只要你有一整套持续推进的技术脉络它就能帮你少说 70% 的废话。1. 先搞明白 claude-mem 到底在解决什么问题1.1 为什么 AI 助手总是“记不住事”先把这个“失忆”的根子说清楚。LLM 的推理过程是基于当前对话窗口里的全部 token窗口之外的信息对它来说等于不存在。关闭一个会话后历史记录虽然还在你的终端里但它的模型权重并没有发生任何更新下一次开新会话它还是那个“读了所有训练数据但不知道你们昨天聊了什么的”AI。这不是某个具体产品的 bug而是架构层面的限制。模型的设计思路是“无状态”——每次请求都按你给的上下文独立推理。没有状态就意味着没有“长期记忆”这个概念。为了在工程上弥补这一点各家产品都在做上下文管理有的靠把历史消息全部重放有的靠 RAG 检索知识库但本质上都是“把记忆放在外部随用随取”。我们遇到的痛点通常是这样的项目里已经定好的技术选型、目录约定、命名规范换了会话就丢用户表达过很多次的偏好“不要用 redux用 zustand”“错误信息要中文”下次照样违反还有一些从长对话里慢慢推敲出来的结论因为上下文太长被截断直接消失。这些信息其实不是“知识”而是“结果”是之前花了不少 token 和时间才得出来的结论丢了非常可惜。1.2 一句话说清楚它的定位claude-mem 做的事情就是在对话外部维护一个“记忆层”。它从每次会话中提取值得长期保留的信息写入本地文件等下次会话开始再把文件内容拼进提示词里给模型看。这样模型虽然本身无状态但每次开工都自带“会议纪要”行为的连贯性立刻就不一样了。它的定位被我刻意压在中间不是那种厚重的知识库平台也不是需要独立服务的检索系统就是一个有纪律的文件目录加上一套约定的读写逻辑。好处是你可以完全掌控数据所有记忆都是纯文本随时能用编辑器打开看、改、删不存在“数据进了黑盒”的问题。我把这种方案叫“手写记忆”——数据格式自己定写入逻辑自己写读取注入自己管正好也是理解 AI 记忆机制的最佳入门路径。2. 设计思路为什么“轻量纯文本”反而是最优解2.1 技术选型的对比与分析刚开始规划 claude-mem 的时候我确实动过用向量数据库的念头。毕竟一说到“记忆”很容易联想到知识库、嵌入向量、语义相似度检索。但仔细分析后我放弃了这条路而且理由很充分。方案优点关键短板适用场景向量数据库相似检索强、容量大依赖重需要安装服务数据不可读调试困难知识库文档量达到万级以上关系数据库结构化查询、并发安全需要建表、迁移看不到纯文本备份迁移繁琐多用户协同的强事务场景JSONL Markdown 文件零依赖、纯文本、可读可改、git 友好数据量上去后检索性能下降个人与团队小规模长期记忆个人项目的数据量其实远没有到需要用数据库的程度。一个人用一年沉淀下来的记忆也就是几千条文本几十万字符。这点数据量顺序读一遍的时间在毫秒级根本不需要建索引。更重要的是纯文本文件可以被人工审查——我可以在每次会话结束后打开 memory 文件快速扫一遍刚才写入的条目不对就改不想要就删。这种“看得见摸得着”的感觉是数据库和向量库都给不了的。2.2 目录结构与数据格式怎么定我最终确定的目录结构长这样~/.claude-mem/ ├── global/ │ ├── memory.md # 全局性偏好与常识 │ └── sessions/ │ └── 2025-05-01.md # 按日期归档的会话记录 ├── projects/ │ ├── project-name/ │ │ ├── memory.md # 该项目专属记忆 │ │ ├── session-logs/ │ │ │ └── 2025-05-01.jsonl # 原始会话记录备查 │ │ └── decisions.md # 关键决策与理由 └── config.yaml # 开关、路径、注入策略我把记忆分成两层global 放跨项目通用的偏好projects 下按项目隔离。这样设计的原因很直观——项目的技术栈决策不应该污染另一个项目的上下文全局偏好则适用于所有项目。比如“所有提交信息要用规范前缀”这类习惯放 global而“此项目用 pnpm workspace”则只出现在该项目记忆里。格式上原始会话记录用 JSONL 保存每条消息一行方便追加和按行处理长期记忆则用 Markdown 写因为它本身就是给人看的文本排版和分段都能自然表达。这里有一个我认为非常重要的原则记忆文件必须能直接被人读懂。如果哪一天工具逻辑全废了这些文件还能靠人手继续维护这才是最抗风险的存储设计。3. 核心实现把记忆管起来3.1 记忆从哪里来会话信息提取整个 claude-mem 的工作流可以拆成三环提取、存储、注入。先看提取。每次会话开始我都会在提示词里注入一段附加指令让模型在对话过程中主动识别“值得记忆的信息”并结构化地输出。这听起来像是给模型布置任务但实际效果非常好——现代大模型在遵循指令方面足够可靠你只要给出明确的标准它就能准确判断哪些信息需要沉淀。我定的提取标准有三条事实、决策、偏好。# 从会话记录中提取记忆条目的核心逻辑 def extract_memories(raw_messages: str, project_name: str) - list[dict]: prompt f请分析以下对话文本提取所有值得长期记住的信息。 提取标准 1. 事实 - 关于项目/系统的客观信息如技术栈、目录结构、运行命令 2. 决策 - 已经拍板定论的方案选择如选型理由、取舍结论 3. 偏好 - 用户表达过的倾向如命名习惯、代码风格、工具偏好 输出为 JSON 数组每项包含 type, content, source_topic 三个字段。 不要提取一次性步骤和临时性讨论。 对话文本 {raw_messages[-3000:]} 项目{project_name} # 调用模型解析返回的 JSON results call_model(prompt) return results这段代码模拟的是实际实现里的核心函数。你可能会问为什么只取最后 3000 字符因为提取指令只需要关注最近的对话内容——上下文越长模型反而抓不住重点。你说“内存”特征就说“提取临时题目”。我将指明在下面独立地解释。3.2 记忆怎么写存储层逻辑提取出条目后下一步是把它们写入对应文件。在写这一层时我踩过不少坑最典型的就是“重复写入”。同一件事在多个会话里被重复提起如果不做去重memory.md 很快就堆满了相似条目注入时既浪费 token 又干扰模型判断。我的解决策略是“先读后写同主题合并”。每个记忆条目都会绑定一个 source_topic 字段写入时先扫描已有内容如果发现同主题条目就把新旧内容合并成一条更新时间戳;如果没有则追加新条目。def write_memory(project: str, new_memories: list[dict]) - None: mem_path Path.home() / .claude-mem / projects / project / memory.md existing parse_existing_memory(mem_path) for mem in new_memories: topic mem[source_topic] if topic in existing: # 合并保留旧信息补充新信息更新修改时间 existing[topic].content merge_content(existing[topic].content, mem[content]) existing[topic].updated_at time_now() else: existing[topic] MemoryEntry( typemem[type], contentmem[content], updated_attime_now() ) rendered render_markdown(existing) mem_path.write_text(rendered, encodingutf-8)这个“同主题合并”的设计是记忆系统里最关键的细节。如果只是无脑追加看起来什么都记了实际上久远的细节早就被淹没了。相反合并会让文件保持稳定大小只记录“当前有效”的状态。用版本管理的思路来理解你不是在保存所有历史而是在维护一份持续更新的“当前基线”。3.3 记忆怎么用注入时机的选择存储做得再好如果注入时机不对效果等于零。记忆注入要解决的第一个问题就是“每次对话都要带上吗”我的答案是不要。我来解释为什么。记忆文件再精简一个月下来也会积累几百行文本。如果你每次发消息都把这些全塞进去token 消耗会持续增长而且大量与当前任务无关的信息会稀释模型的专注力。更合理的策略是分段注入会话开始注入全部记忆作为“项目背景”让模型一开始就进入状态。每轮对话只注入与当前问题关键词相关的记忆片段。上下文过长时优先注入最近更新的记忆丢弃低频旧条目。在实现层面“会话开始注入全部”是最好做的只要在初始化提示词前拼接一段记忆文本就行。难在中间阶段的关联注入——你需要在每个请求前做一次关键词匹配把 memory.md 中与当前用户提问相关的条目挑出来。# 简易实现按关键词匹配记忆条目 grep -i $(echo $USER_INPUT | cut -d -f1-10) ~/.claude-mem/projects/$PROJECT/memory.md | head -30这个方法当然算不上优雅它只是在做词面上的匹配但效果已经足够用了。毕竟个人项目的记忆量不大词面匹配带来的误差可以接受。真正讲究的时候你可以用向量检索替代这段逻辑但对一个小工具来说越简单越可靠。4. 实操实录跑通一个完整的记忆闭环4.1 从零初始化一个项目整件事的实操从初始化开始。我预设了 CLI 框架里的初始化命令claude-mem init --project my-api这条命令会创建好目录骨架并写入一个初始的 memory 文件。里面只有项目名、创建时间、和一段模板说明# 项目记忆my-api ## 项目概述 功能提供用户认证与数据管理 API 技术栈待补充 启动命令待补充 ## 已确认决策 此项目暂无记录 ## 用户偏好 - 才数据集错误用户偏好已记录如错误信息用中文提示。初始化阶段不急着写太多等会话慢慢长出内容。这也是记忆工具的特质——它不是一个配置完就能立刻看到效果的即时工具需要与 AI 助手协作一段时间记忆才会从无到有地积累起来。想验证效果请耐心跑完整跑完一个任务流程。4.2 一次真实的会话闭环我用“为 my-api 设计一个数据库模型”这个任务来做实测。第一次会话是全新的我打开了记忆中初始的 memory 片段模型会意识到“这似乎是一个新项目背景信息还很少”。对话中我明确表示“用 PostgreSQL不用 MySQL以后可能要做全文检索”模型很快围绕 PostgreSQL 给出了模型设计。会话结束后claude-mem 把这条决策写入 memory.md变成## 已确认决策 - [2025-05-01] 数据库选型PostgreSQL考虑全文检索需求MySQL 不合适第二天我重新开一个会话让它继续完善 API 设计。这次注入记忆后模型一开始就自动说“基于你们项目已经确定使用 PostgreSQL我这边建议...”——看到这种情况真的很爽它记得你昨天拍过板的事不需要你从头再解释一遍。这就是记忆闭环跑通以后的效果。4.3 中途审查与人工修正但我很快发现不能完全信任自动提取人工审查环节必须有。有一次它把“这次部署到测试环境验证一下”这种一次性操作也记成了长期记忆理由是“部署”听起来像项目信息。这种误判如果不纠正就会污染后续所有会话。所以我在每次会话结束后的收尾逻辑里加了一个确认步骤claude-mem review --project my-api这条命令把最近新增的记忆条目列出来让你确认或删除。实际操作中我发现这个 review 步骤不是可选项而是必须项。AI 提取记忆的标准再准也不可能完全理解你的意图有些信息你虽然说了但你并不希望它被沉淀下来。人机协同的朴素道理在这里体现得很充分机器负责批量化生产人负责做最终裁决。5. 常见问题与避坑指南5.1 记忆文件越来越长上下文都被吃掉了这是使用记忆工具必然遇到的第一个瓶颈。当 memory.md 膨胀到几千行即使分段注入也会带来性能负担。我的处理办法是“分层老化”活跃记忆最近 30 天内更新过的条目每次会话全量注入。归档记忆超过 30 天未更新的条目移入 archive 文件只在人工调用时检索。淘汰机制与当前活跃项目无关的旧决策可以安全删除或用 git 历史找回。这套老化策略很朴素但它解决了一个关键问题记忆不是越全越好而是越贴切越好。一条一年前的技术选型如果今天还在全量注入它不仅帮不上忙还可能误导模型——因为项目早就换了技术栈。5.2 多项目同时推进记忆乱窜如果你同时维护五个项目最怕的就是 A 项目的记忆跑到 B 项目的对话里。我在实现里用目录隔离彻底解决了这个问题projects 下的每个子目录对应一个项目读取时只扫描对应目录。但还有一个更隐蔽的坑全局偏好与项目记忆冲突。比如全局记忆里写了“代码风格使用 4 空格缩进”而某个项目的 memory 里明确写了“此项目使用 2 空格”。如果不做优先级规则模型会被矛盾信息搞糊涂。我的解决方式是给记忆注入做层级排序让具体项目记忆覆盖全局记忆# 注入顺序项目记忆在后全局记忆在前 GLOBAL$(cat ~/.claude-mem/global/memory.md) PROJECT$(cat ~/.claude-mem/projects/$PROJECT/memory.md) PROMPT全局背景${GLOBAL} 项目背景优先级更高${PROJECT} 现在开始处理任务优先级的含义在提示词里写清楚让模型明确知道“冲突时以项目记忆为准”。这是提示词工程里很小但很关键的一个细节不需要复杂的逻辑只需在文本顺序和表述中埋入信号。5.3 隐私与数据边界怎么守这一点我必须单独拎出来强调。claude-mem 默认把所有记忆存在本地不经过任何第三方服务这是它最大的安全优势。但使用中仍要注意一旦你把记忆内容注入到大模型的请求里就等于把它交给了模型服务商。所以敏感数据、密钥、未公开的商业信息不要留在记忆文件里。我养成了一个习惯每个月把 memory 目录 git 提交一次定期检查有没有混入敏感内容。也建议你在提取环节就加上过滤规则比如正则匹配身份证号、密钥格式等直接丢弃。常见问题症状解决思路记忆注入太多响应变慢、token 消耗激增设置 max_memory_chars 上限超限只取最近更新过时决策误导模型还在用旧方案给建议定期 review删除失效条目并标注 deprecated跨项目串记忆项目 A 的偏好出现在 B检查目录隔离确认未误读全局文件重复记录同一事实memory.md 大量相似内容合并逻辑加入主题字段写前先查重提取误判一次性操作被记录加入 review 确认步骤人工过滤5.4 我踩过最大的一个坑最后说一个最隐蔽的坑。我早期把记忆注入放在每轮对话的固定位置不管用户问什么都不变。结果发现当用户问一个简单问题时模型也会先“回顾”一遍记忆回答反而变得啰嗦。后来我调整策略把记忆注入分成“全量”和“定向”两档会话开头用全量建立背景普通轮次用关键词匹配定向注入。就这么一个小改动回答质量和 token 消耗都立刻好转了不少。这种教训的核心是记忆工具的目标不是让模型记住所有事而是让它在正确的时机想起正确的事。无差别注入是一种偷懒的做法短期看不出问题长期一定导致信息熵爆炸。6. 关于这个工具的后续想法做到这一步claude-mem 对我来说已经不只是一个工具更像是我和 AI 助手之间的一种协作协议。它的价值不在于代码本身有多精巧而在于它重新定义了“记忆”这个概念在 AI 工作流里的位置——由外部系统管理、可审查、可修正而不是模型里的隐层参数。有一点我想强调这类第三方记忆工具的效果高度依赖你自己的维护习惯。不要指望装完就一劳永逸你需要花时间定期 review、清理失效内容、调整提取标准。我用下来的体会是当记忆文件能真实反映你当前的工作状态时AI 助手的表现会有一个肉眼可见的提升而如果你放任它乱长记忆反而会成为干扰源。如果你也打算在自己的项目里实现类似的功能我建议从最小闭环开始先做一个能写入 memory.md 的小脚本再做一个能在提示词里拼文件内容的模板跑通一次“记忆→注入”的流程后再逐步加检索、去重、老化这些进阶功能。千万别一上来就去搞独立的记忆服务或者向量引擎过度设计是这类项目最大的敌人。最后再分享一个小技巧把记忆文件纳入版本管理。git 不仅能帮你回溯误删的内容还能让你在历史记录里观察 AI 记忆的演变过程——当你发现某一条记忆反复出现、反复被修正那一件事多半就是你工作流里真正的痛点。顺着这个线索去优化你的提示词和工作方法效果往往比单纯调工具来得更快。