给Claude加持久记忆:跨会话上下文连续性的架构设计与实操
发布时间:2026/10/8 5:01:55 作者:尧图编辑部 阅读量:1,286

1. 从聊完就忘说起claude-mem 到底想解决什么如果你用 Claude 这类对话式 AI 做过稍微长一点的项目大概率遇到过这种尴尬昨天聊了三个小时把需求、约束、命名规范、踩过的坑都对齐了今天开个新会话它一脸无辜地问你请问你想做什么。你只能把昨天的上下文再喂一遍喂到一半发现 token 快满了于是又得删删减减最后干脆放弃回到每次只问一个小问题的原始状态。这不是模型不行而是对话式 AI 的默认记忆模型是会话级的——一次会话就是一个封闭的上下文窗口窗口一关记忆清零。claude-mem这个项目从名字就能看出来它瞄准的正是这个痛点给 Claude 加一层跨会话的持久记忆。你可以把它理解成给 AI 配了一个外部笔记本每次对话结束后把值得留下的东西写进笔记本下次开新会话时先把笔记本里相关的部分翻出来塞进上下文再开始聊。它解决的问题很具体上下文窗口有限、会话之间不共享状态、重复交代背景成本高。适合谁来参考三类人最受益。第一类是长期用 Claude 做开发、写作、研究的知识工作者项目周期动辄几周几个月上下文连续性直接决定效率第二类是想自己动手搭一套AI 记忆系统的工程师claude-mem 是一个很好的参考实现能看清记忆的写入、检索、注入这条完整链路第三类是对 RAG、向量检索、上下文工程感兴趣但还没上手的人这个项目把抽象概念落到了具体代码上。需要先说明一点claude-mem这个名字在社区里对应的实现不止一个有基于 MCP 协议的、有基于本地文件加检索的、也有做成 CLI 工具的。本文不绑定某一个具体仓库而是围绕给 Claude 做持久记忆这个核心命题把这类项目通用的架构、关键决策、实操步骤和踩坑经验讲透。你拿到的可能是一个开源仓库也可能要自己动手拼思路是通用的。2. 记忆系统的三层结构写入、存储、召回在动手之前得先把记忆这件事拆开看。很多人一上来就想我要让 AI 记住所有东西结果做出来一个又慢又贵又不好用的东西。真正可用的记忆系统一定是分层的。2.1 为什么不能把所有对话都存下来最朴素的想法是把每次对话的完整记录都存进数据库下次全量塞回上下文。这个方案在 demo 阶段能跑通但一上真实场景就崩。原因有三个。第一是成本。上下文是按 token 计费的你把过去一个月的对话全塞进去一次请求可能就几万 token钱烧得飞快而且大部分内容是无关的。第二是信噪比。上下文窗口里塞的东西越多模型越容易分心真正重要的信息反而被淹没回答质量下降。第三是时效性。三个月前的一个临时决定可能早就被推翻了你把它塞进去模型会拿旧信息当事实产生误导。所以记忆系统的第一原则是存的时候要筛选取的时候要排序。不是记住一切而是记住该记的忘掉该忘的需要时能找回来。2.2 写入层什么内容值得被记住写入层要回答的问题是一次对话结束后哪些内容应该被持久化我的经验是分成四类优先级从高到低。事实性信息项目名称、技术栈、目录结构、命名规范、API 约定。这类信息一旦确定长期有效必须记。决策与理由为什么选 A 方案不选 B为什么放弃某个库。这类信息价值极高因为它能防止后续重复讨论同一个问题。待办与状态当前进行到哪一步、下一步要做什么、有哪些阻塞。这是工作记忆时效性强需要带时间戳。偏好与风格用户喜欢简洁还是详细、代码风格、文档格式。这类信息积累起来能显著提升体验。反过来不该记的也很明确寒暄、重复确认、已经被推翻的中间结论、大段的原始代码除非是核心片段。判断标准很简单这条信息在两周后的新会话里还有参考价值吗没有就别存。2.3 存储层文件、数据库还是向量库存储层的选型直接决定了系统的复杂度和能力上限。常见的有三种路线各有取舍。存储方案优点缺点适用场景本地 Markdown 文件零依赖、可读、可版本控制检索靠关键词语义能力弱个人使用、记忆量小SQLite 全文索引单文件、查询快、支持结构化字段语义检索需额外扩展中等规模、需要元数据过滤向量数据库语义检索强、模糊匹配好依赖嵌入模型、有运维成本记忆量大、检索质量要求高我的建议是从 Markdown 起步需要时再升级。原因很实际早期你根本不知道自己的记忆会长成什么样用文件能随时打开看、随时改调试成本最低。等记忆条目超过几百条、关键词检索开始频繁失效时再引入向量检索也不迟。很多项目一上来就上向量库结果调 embedding 模型的时间比写业务逻辑还多得不偿失。2.4 召回层怎么把相关记忆找出来召回层是整个系统里最考验功力的部分。它要解决的是新会话开始时用户说了一句话我怎么从几百条记忆里挑出最相关的几条塞进上下文纯关键词匹配的问题是词不达意。用户说那个登录的问题记忆里存的是认证模块的 token 刷新逻辑字面上一个词都对不上但语义上高度相关。纯向量检索的问题是过度联想有时候会把八竿子打不着的东西也捞出来。实践中比较稳的做法是混合检索先用元数据项目名、时间范围、类型做粗筛再用关键词和向量做精排最后按分数截断只取 top-K 条。K 取多少这取决于你的上下文预算。一般来说记忆部分占整个上下文的 20% 到 30% 比较合理剩下的留给当前对话。如果单条记忆平均 100 token那 K 大概在 10 到 20 之间。这个数字不是拍脑袋是要根据你实际用的模型窗口大小反推的。3. 把记忆接进 Claude几种集成路径的取舍搞清楚记忆系统的内部结构后下一个问题是怎么让它和 Claude 协同工作这里有几条技术路线复杂度、灵活性、维护成本差别很大。3.1 MCP 协议路线标准化但需要理解协议MCPModel Context Protocol是目前把外部能力接进 Claude 的主流方式。它的思路是你写一个 MCP Server暴露几个工具比如save_memory、search_memoryClaude 在对话过程中可以主动调用这些工具来读写记忆。这条路线的好处是标准化、可复用。你写好的 Server理论上能被任何支持 MCP 的客户端使用不绑定某一个产品。而且 Claude 是主动调用工具的它可以根据当前对话判断这条信息值得记比被动全量存储聪明得多。代价是你得理解 MCP 的基本概念Server 怎么注册、工具怎么定义 schema、请求和响应怎么序列化。如果你之前没接触过建议先跑通官方的最小示例再往记忆逻辑上套。别一上来就写完整的记忆系统那样调试起来会很痛苦。3.2 本地文件加脚本路线最土但最可控如果你不想引入协议层的复杂度最直接的办法是写一个脚本在会话开始和结束时手动触发。会话结束时把对话导出跑一个脚本让 Claude 自己总结出值得记的条目追加到 Markdown 文件会话开始时跑另一个脚本根据当前任务描述检索相关条目拼成一段背景提示粘贴到新会话开头。这条路线的优点是完全可控、零黑盒。每一段记忆你都能看到、能改、能删。缺点是手动需要你养成习惯。但对于个人使用来说手动触发反而是一种保护——它逼你在每次会话结束时花两分钟想想这次到底产出了什么这个反思过程本身就有价值。3.3 自动化钩子路线体验最好但坑最多最理想的是全自动会话一结束自动写入会话一开始自动召回用户完全无感。实现方式通常是利用客户端的钩子hook机制或者包装一层代理。这条路线体验最好但坑也最多。首先是触发时机不好把握会话结束的判定标准是什么关窗口算吗切换话题算吗其次是写入质量自动总结出来的记忆往往很水因为模型不知道什么对你重要。最后是调试困难出问题时你很难定位是钩子没触发、总结没做好还是召回没匹配上。我的建议是先用手动路线跑通闭环确认记忆质量达标后再逐步自动化。跳过手动阶段直接上自动化大概率会得到一个存了一堆垃圾、召回全是噪音的系统。4. 实操从零搭一个最小可用的记忆闭环下面这部分是干货我会把最小可用版本MVP的搭建过程拆成可复现的步骤。假设你选择的是本地文件 脚本这条最稳的路线。4.1 目录结构与文件约定先定一个清晰的目录结构这决定了后续所有操作的一致性。claude-mem/ ├── memories/ │ ├── facts.md # 事实性信息 │ ├── decisions.md # 决策与理由 │ ├── todos.md # 待办与状态 │ └── preferences.md # 偏好与风格 ├── index.json # 元数据索引 └── scripts/ ├── save.py # 写入脚本 └── recall.py # 召回脚本为什么按类型分文件而不是全塞一个文件因为召回时的过滤维度不同。事实和偏好是长期有效的召回时几乎总要带上待办是时效性的超过一定时间就该忽略。分文件让过滤逻辑简单很多。每条记忆的格式建议统一成带元数据的块## [2024-06-15] 项目认证方案选型 - 类型: decision - 项目: my-web-app - 标签: auth, jwt, security - 内容: 最终选择 JWT refresh token 方案放弃 session。 原因是前后端分离部署session 需要额外的共享存储 而 JWT 无状态水平扩展更简单。refresh token 有效期 7 天 access token 15 分钟。这个格式的关键是元数据齐全。日期用于时效过滤类型用于分类召回项目用于隔离不同项目的记忆标签用于关键词匹配。内容部分要写清楚是什么和为什么后者往往比前者更重要。4.2 写入脚本让 Claude 帮你总结写入脚本的核心逻辑是把一段对话丢给 Claude让它按上面的格式输出记忆条目。提示词的设计是关键我试过很多版本下面这个比较稳你是一个记忆整理助手。请从以下对话中提取值得长期记住的信息 按指定格式输出。判断标准这条信息在两周后的新会话里还有参考价值吗 只提取以下四类 1. 事实性信息项目配置、技术栈、约定 2. 决策与理由选了什么、为什么 3. 待办与状态进行到哪、下一步 4. 偏好与风格用户习惯 不要提取寒暄、重复确认、被推翻的结论、大段原始代码。 输出格式 ## [日期] 标题 - 类型: fact/decision/todo/preference - 项目: 项目名 - 标签: 逗号分隔 - 内容: 具体内容包含理由 对话内容 {conversation}这个提示词里有两个细节值得说。第一是给了明确的判断标准两周后还有价值吗比笼统说提取重要信息效果好得多。第二是明确列出了不要提取的内容负向约束往往比正向约束更能提升输出质量。脚本跑完后把输出追加到对应的 Markdown 文件同时更新index.json记录每条记忆的日期、类型、项目、标签方便后续检索。4.3 召回脚本混合检索的具体实现召回脚本要做三件事粗筛、精排、拼装。粗筛用元数据精排用关键词加语义拼装成一段可以直接粘贴的背景提示。粗筛的逻辑根据当前任务描述里的项目名过滤出同项目的记忆根据类型决定是否包含待办比如超过 30 天的待办默认不召回根据日期给新记忆更高权重。精排我建议先用简单的关键词加权别急着上向量。具体做法是把当前任务描述分词和每条记忆的标签、标题、内容做匹配标题命中权重 3标签命中权重 2内容命中权重 1加总后排序。这个土办法在记忆量小于 500 条时效果往往比你想的好。拼装时要注意控制长度。我的做法是给每类记忆设一个 token 上限比如事实 500、决策 800、待办 300、偏好 200超了就截断。拼出来的提示大概长这样以下是你之前和用户协作时积累的背景信息请在回答时参考 【项目事实】 - my-web-app 使用 React TypeScript后端 Node.js Express - 数据库 PostgreSQLORM 用 Prisma 【关键决策】 - 认证用 JWT refresh token理由前后端分离无状态易扩展 【当前待办】 - 用户列表页的分页逻辑还没做 【用户偏好】 - 喜欢简洁回答代码示例要带注释这段提示粘到新会话开头Claude 立刻就有了上下文不用你再从头交代。4.4 验证闭环是否真的跑通搭完之后一定要做验证别自己骗自己。验证方法是开一个全新会话只粘贴召回提示然后问一个依赖历史信息的问题。比如我们上次定的认证方案是什么为什么这么选如果 Claude 能准确答出 JWT 和理由说明闭环通了。如果答不出来或者答错就回去查是写入没存对还是召回没匹配上。我建议至少准备五个这样的验证问题覆盖四类记忆。每次改动脚本后都跑一遍确保没有回归。这个习惯能帮你省下大量以为能用其实不能用的时间。5. 那些文档不会告诉你的坑前面讲的是应该怎么做这一节讲实际做的时候会怎么翻车。这些都是我在真实使用中踩出来的网上教程基本不会提。5.1 记忆污染错误信息一旦写入就很难清除最隐蔽的坑是记忆污染。某次对话里 Claude 理解错了你的意思总结出一条错误的记忆写进了文件。之后每次召回都带着这条错误信息Claude 基于它继续推理产生更多错误形成恶性循环。等你发现时可能已经污染了十几条相关记忆。防范的办法有两个。第一是写入时人工过目。手动路线的好处在这里体现得淋漓尽致——每次写入前你扫一眼明显不对的直接删掉。第二是给记忆加置信度字段自动总结的标记为待确认你确认过的标记为已确认召回时优先用已确认的。这个字段看起来多余但真出问题时能救命。5.2 召回过度塞太多背景反而让回答变差新手容易犯的另一个错误是召回过度。觉得多给点背景总没坏处结果塞了 3000 token 的记忆进去Claude 的回答反而变得啰嗦、跑题。原因是上下文里信息太多模型分不清哪些是当前任务相关的哪些是历史噪音。判断是否召回过度的信号Claude 开始主动提一些你没问的历史细节或者回答里出现根据之前的记录这种话但内容并不相关。出现这种情况就该收紧召回策略减少 K 值或者提高匹配阈值。5.3 时间衰减三个月前的待办不该再出现待办类记忆必须带时间衰减。我踩过的坑是一个两个月前就完成的待办因为没标记完成一直被召回Claude 每次都提醒我你还有个任务没做烦不胜烦。解决办法是给待办加状态字段pending/done/dropped召回时只取 pending 的并且超过一定天数比如 14 天的 pending 自动降权提示里标注可能已过期请确认。这个细节很小但直接影响使用体验。5.4 多项目串味不同项目的记忆互相干扰如果你同时用 Claude 做多个项目项目隔离是必须的。我一开始没做隔离结果做 A 项目时召回出了 B 项目的技术栈Claude 给出的建议完全跑偏。隔离的实现很简单每条记忆都带项目字段召回时先按项目过滤。但要注意共享记忆的处理——有些偏好比如喜欢简洁回答是跨项目的这类记忆项目字段设为global所有项目都召回。区分项目专属和全局共享是隔离设计的关键。6. 从能用走向好用几个进阶方向MVP 跑通之后如果你想让这套系统更聪明有几个方向可以深入。这些不是必须的但每一个都能带来明显的体验提升。6.1 记忆的自动合并与去重用久了你会发现同一个事实被反复记录只是措辞不同。比如数据库用 PostgreSQL可能存了五遍。这些冗余不仅浪费上下文还会让召回结果显得杂乱。解决办法是定期做记忆合并。写一个脚本把同类型、同项目、标签重叠度高的记忆找出来让 Claude 判断是否重复重复的合并成一条保留信息最全的版本。建议每个月跑一次保持记忆库的整洁。6.2 引入向量检索的时机与方式什么时候该上向量检索我的经验是当你发现关键词检索开始频繁漏召回时。具体信号是你明明记得存过某条信息但用各种关键词都搜不出来。这时候说明语义鸿沟已经超过了关键词能覆盖的范围。引入方式建议渐进先加一个向量索引作为补充召回时关键词和向量各取 top-K合并去重。不要一上来就用向量完全替代关键词两者互补的效果最好。嵌入模型的选择上中文场景建议用专门优化过中文的模型通用模型在中文短文本上的表现往往不理想。6.3 让记忆系统自己反思更进阶的做法是让记忆系统具备反思能力定期回顾最近的记忆发现矛盾比如两条决策互相冲突、发现过时比如某个待办长期未动、发现模式比如用户反复提到某个痛点主动生成洞察条目。这个方向很有意思但要注意别过度设计。反思产生的洞察如果质量不高反而会污染记忆库。建议先小范围试人工审核一段时间确认产出有价值再放开。7. 我实际用下来的几点体会最后聊点实在的。这套东西我用了一段时间最大的感受是记忆系统的价值不在于记住多少而在于该记的记对了该忘的忘掉了。一开始我追求大而全恨不得把每次对话都存下来结果系统又慢又乱。后来做减法只存四类核心信息反而好用得多。另一个体会是手动阶段不能省。我见过太多人想一步到位做全自动最后卡在调试上放弃。手动写入和召回虽然麻烦但它让你对什么值得记有真实的体感这个体感是设计自动化策略的基础。等你手动跑了一两个月闭着眼睛都知道哪些信息该存、怎么存再去写自动化脚本成功率会高很多。还有一点别把记忆系统当成万能药。它解决的是跨会话上下文连续性这一个问题解决不了模型本身的能力边界。有些任务就是需要长上下文窗口记忆系统只是缓解不是根治。认清它的定位才不会对它有不切实际的期待。如果你正准备动手我的建议是从最小的闭环开始一个 Markdown 文件、一个写入提示词、一个召回脚本先跑起来。跑通之后再考虑分类型、加索引、上向量。这个领域没有标准答案适合你工作流的就是最好的。