如果你每天要和对话式 AI 打交道大概率遇到过这种让人抓狂的场景早上开了一个会话把项目背景讲得清清楚楚AI 也给了很漂亮的方案下午开个新窗口想接着弄它一脸茫然完全不记得上午聊了什么。你只能把代码重新贴一遍、需求重新讲一遍、偏好重新强调一遍偶尔还要跟它确认我们上午不是聊过这个吗。我第一次看到 claude-mem 这个项目名的时候立刻被戳中了。mem 显然是 memory 的缩写项目想解决的就是这个AI 聊完就忘的问题。它不是给模型加一个更大的上下文窗口而是在会话之外搭一层独立的长期记忆。简单说就是对话结束后自动把值得记住的信息抽出来存好下次开新会话时再把相关记忆塞回去。这样 AI 不用每次从零开始你也不用把同样的话说上好几遍。这篇文章我会从实际落地的角度出发拆解这类记忆系统的完整设计思路、核心环节的实做法、部署时的关键参数以及我反复折腾后踩到的坑。不管你是经常用 AI 写代码的开发者还是拿它梳理研究思路、创作内容的人这套思路都能直接用得上。我会尽量少讲虚的多给可以直接抄的配置和代码片段。1. 先搞清楚 claude-mem 到底在解决什么问题1.1 AI 的上下文不是真正的记忆先说一个很多人没意识到的点对话框本身是有上下文的模型也真的记得当前这个会话里发生过什么。但这只是临时的、局部的会话一旦关闭或者窗口超出长度这些东西就什么都没了。更重要的是每次新开会话模型都不会记得你这个人是谁、你喜欢什么、你之前的项目进展到哪一步。我举个例子。我前段时间在做一个图像处理 Demo第一天让 AI 帮我设计了模块划分它提议用某种管线架构我还特意说了后续扩展性比性能重要。第二天新开一个会话想让它基于这个架构补一个功能模块结果它完全不记得甚至在回答里默认我不在乎扩展性给了另一套高并发优先的思路。你必须重新把架构贴一遍再把它说过的话原样说给它听它才能回到正确的思路上。这就是问题所在上下文只在一次会话内有效无法跨会话沉淀。而 claude-mem 这类项目本质上就是把会话内的临时上下文升级成会话外的持久记忆。它不改变模型本身的记忆能力而是把记忆放到一个外部系统里管理该取的时候取回来。1.2 它是怎么做到跨会话记住的我梳理 claude-mem 的设计思路时发现它其实是一条很标准的流水线核心是四个环节提取在对话过程中或者对话结束后把值得长期记住的信息从对话里剥离出来。存储把提取出来的信息写进一个独立于会话的存储层。检索新会话开始时根据当前聊的话题把相关记忆捞出来。注入把捞出来的记忆组装成 system prompt 的一部分让模型带着记忆回答问题。这四个环节听着简单但每环都有不少细节。比如提取不是简单地把整段对话存下来而是要让模型判断什么值得记、什么不值得记。你随口说的一句今天天气不错肯定不用记但我用的是某语言的某个版本我偏好函数式写法这种就要记。检索也不是随便抽几条而是要保证捞出来的记忆跟当前话题高度相关同时又不至于把记忆库里的垃圾也一起倒进 prompt。1.3 落地之后的变化是质变级的很多人会觉得这套东西是不是太工程化了普通用户用得上吗我实际用下来发现它带来的变化非常直接。我挑几个典型的场景说。开发者场景你让 AI 帮你调试某个模块它记住了你的技术栈、目录结构、编码偏好。下次新会话直接说继续优化那个模块它不会问你哪个模块代码贴一下而是直接给出符合风格的修改建议。研究者场景你连续几天在研究某个文献综述AI 记住了你已经筛过哪些方向、放弃过哪些思路、最终倾向哪个路线。新会话里它不会重新建议你已经排除的方案。内容创作者场景AI 能延续你之前的文风和结构偏好不用每篇文章都重新交代我要口语化一点喜欢短段落多用具体例子。前后对比最明显的是重复沟通成本。过去一个新会话可能要花 5 分钟交代背景有了记忆系统之后这个成本几乎降为零。你会感觉 AI 从一个聪明但健忘的助手变成了一个熟悉你的聪明助手。2. 方案选型为什么简单的喂历史记录行不通2.1 上下文窗口和成本的双重压力有人可能会说既然要让它记住干脆把之前所有对话内容都塞回去不就行了听起来简单但实际不可行。拿一次稍微深入的会话来说假设聊了 200 条消息每条平均 300 token全部回放就是 60,000 token。这在成本上非常夸张而且模型面对超长上下文时注意力会分散它反而会忽略真正关键的信息。更麻烦的是会话之间往往有交叉你昨天的对话里可能有今天不需要的细节全部塞回去等于把噪音也带回来了。所以结论很明确记忆必须在存储之前做一次提纯只保留高价值的信息而不是原样搬运对话记录。2.2 三种常见记忆策略的对比我梳理了市面上常见的几种做法各有取舍。策略实现方式优点缺点全量回放把历史消息全部放入 prompt最简单信息不丢token 成本高超长后模型犯糊涂对话摘要让模型给每段对话写摘要下次带着摘要聊压缩效果好省 token摘要丢细节且摘要质量不稳定外部记忆库提取关键信息多轮滚动记录按需检索记忆密度高成本可控需要设计与工程落地门槛稍高claude-mem 走的是第三种。它不在每次对话里把所有东西都塞进去而是维护一个持续更新的记忆库只在需要的时候取一小部分。这个思路跟人脑很像你不会在上学前把一辈子的事情全回忆一遍而是遇到什么问题就想起相关的那部分经验。2.3 我最终认可的混合架构纯向量检索其实也有问题。向量检索擅长模糊匹配却不擅长精确查询。比如你想查用户上次说的技术栈版本号如果靠 embedding 相似度去捞结果可能很不稳定。所以我更推荐混合的方式结构化的记忆比如事实、偏好、任务状态用表格存储和查询语义化的内容比如结论、思路、讨论背景用向量检索。这个组合既能精确命中也能模糊匹配覆盖了大多数使用场景。claude-mem 这个名字虽然只提到 Claude但它的记忆架构完全可以套用到任何对话模型上这也是为什么我会花时间研究它。3. 从零落地一套带记忆的 AI 工作流部署与配置实录3.1 环境准备与依赖清单我先说清楚我是在本地跑通的最小可行版本没有依赖云服务。运行环境是 Python 3.10需要一个能算 embedding 的模型本地轻量模型就够用以及一个支持持久化的数据库文件。我实际使用的是 SQLite 加本地 embedding 模型这套组合的好处是零部署成本、完全离线、数据不出机器。依赖清单大致长这样anthropic0.31.0 sentence-transformers3.0.1 sqlalchemy2.0.30 numpy1.26.4anthropic是用来跟模型对话的 SDKsentence-transformers负责生成文本向量sqlalchemy是数据库 ORM。没有特殊原因别贪多依赖越少越好维护。3.2 存储层设计一张表存事实一张表存摘要存储是记忆系统最容易被人忽略、但最值得花心思的部分。我建议至少建两张表一张偏向结构化记忆一张偏向对话摘要。我用的表结构大致如下CREATE TABLE memories ( id INTEGER PRIMARY KEY AUTOINCREMENT, memory_type TEXT NOT NULL, -- fact / preference / task / conclusion content TEXT NOT NULL, importance INTEGER DEFAULT 5, -- 1 到 10重要性评分 embedding BLOB, -- 向量用于语义检索 source_session TEXT, -- 来源会话标识 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE dialogue_summaries ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL, summary TEXT NOT NULL, start_time TIMESTAMP, end_time TIMESTAMP, embedding BLOB );memory_type很关键。不同类型的记忆检索时的权重应该不一样任务状态类的记忆在新会话里应该优先出现偏好类的记忆每次都可以带上而对话摘要则适合在跨天、跨周的回顾性场景里使用。3.3 把记忆接入对话一个最小可运行的示例存储层准备好之后核心就是怎么把记忆塞进每次对话里。我写了一段非常简化的流程代码展示骨架逻辑import anthropic from sentence_transformers import SentenceTransformer model SentenceTransformer(paraphrase-multilingual-MiniLM-L12-v2) client anthropic.Anthropic() # 注入你自己的 API 密钥 def build_memory_prompt(user_input: str, top_k3): # 1. 把用户最新输入转成向量 query_vec model.encode(user_input).tolist() # 2. 在 memory 表里做相似度检索向量检索需自行实现或借助插件 memories search_similar(query_vec, top_ktop_k) # 3. 组装成 system prompt memory_block \n.join(f- [{m.memory_type}] {m.content} for m in memories) system_prompt ( 你是用户的长期协作者。以下是与本次任务相关的历史记忆 请自然融入回答但不要逐字复述给用户看。\n f记忆内容\n{memory_block} ) return system_prompt def ask_ai(user_input: str): system_prompt build_memory_prompt(user_input) response client.messages.create( modelclaude-3-5-sonnet-20241022, max_tokens1024, systemsystem_prompt, messages[{role: user, content: user_input}], ) return response.content[0].text这只是一个示意。实际项目中search_similar需要用到向量数据库或者自己实现余弦相似度计算提取环节也需要额外的模型调用。但整体骨架就是先检索记忆再组装 prompt再发请求。把你的业务逻辑往这个骨架里填就行。3.4 三组关键参数直接决定体验我调参调了挺久最影响体验的是下面三组参数。给一组我实测下来比较顺手的默认值参数作用我推荐的取值说明提取频率多久触发一次对话总结 记忆提取每 5 轮对话提炼一次太频繁会割裂对话太稀疏会丢信息检索返回条数 top_k每次注入多少条记忆3 到 5 条条数越多记忆越全但 token 成本上升相关性阈值低于多少分的记忆不注入0.75低于这个值宁可不注入避免误导还有一个容易被忽略的细节max_memory_len即单条记忆的最大长度。我建议限制在 200 字以内。记忆不是原文而是浓缩后的要点。过长的记忆条目在注入时既浪费 token又容易让模型抓不住重点。4. 记忆链路四个核心环节的详细拆解4.1 提取环节教会 AI 什么该记、什么不该记提取是整个系统中技术含量最高的一环因为它直接决定了记忆库的质量。我最早犯的错是让它总结对话重点结果它把流水账也记进去了什么用户今天提到了一个 bug用户表示会再想想这种没营养的内容全存了进去污染了后面所有检索结果。后来我把提取指令改成了结构化输出效果立刻不一样。我的做法是在对话进行到一定轮次时额外调用一次模型给它明确的任务请从以下对话中提取值得长期记住的信息分类输出。 分类说明 - fact明确的事实性陈述例如技术栈、版本号、项目架构、时间节点 - preference用户明确表达的偏好例如我更喜欢简洁写法我不用某个框架 - task正在进行中的任务状态例如当前正在重构登录模块下一步是做权限 - conclusion双方讨论出的结论例如最终确定采用事件驱动架构 要求 1. 只输出值得跨会话记住的信息日常寒暄、临时讨论不要输出 2. 每条不超过 200 字 3. 按 JSON 格式输出它输出的 JSON 大致长这样{ memories: [ {type: fact, content: 项目使用某框架当前版本 2.1, importance: 8}, {type: preference, content: 用户偏好函数式风格避免 class 写法, importance: 9}, {type: task, content: 正在重构登录模块下一步处理权限校验, importance: 7} ], should_update: [] }拿到 JSON 之后再入库。这样的好处是提取结果可以被程序直接解析不需要靠正则去猜而且分类明确检索时就能按类型加权。4.2 存储环节去重、更新与重要性评分存储听起来简单其实最难的是去重和更新。同一个话题聊过三次每次提取出的结论可能措辞不同如果不去重记忆库里会堆满重复内容。检索的时候捞出来五条其中三条说的是同一件事这就很浪费。我的做法是入库前先做一次语义相似度查重。把新提取的内容也转成向量和同类记忆做余弦相似度比较。如果大于 0.9就认为是同一条记忆的变体不新增记录而是更新原记录的updated_at并把内容合并成更精炼的版本。重要性评分也很有讲究。我的规则是用户直接强调的比如这个很重要一定要记住评分加两分。重复出现的主题自动加分因为反复提到的大概率是关键内容。对当前进行中的任务直接相关的记忆评分临时提高任务结束后降权。重要性评分会直接影响检索结果。高重要度的记忆在 top_k 排序里拥有更高优先级这样即使冷门知识被提及也不会被频繁刷屏的临时信息压下去。4.3 检索环节按相关性取回而不是全部搬回家检索的目标是捞得准、捞得少。我实践下来比较好用的流程是三步第一步把用户最新一条消息转成向量。这个向量代表当前需要什么样的记忆。 第二步在记忆库里做向量相似度计算得到一批候选。 第三步用额外的规则做精排任务类记忆优先、重要度加权、相关性低于阈值的直接丢弃。我简化后的检索伪代码是这样的def search_similar(query_vec, top_k3, threshold0.75): results [] for mem in all_memories(): score cosine_similarity(query_vec, mem.embedding) if score threshold: results.append((score mem.importance * 0.01, mem)) results.sort(reverseTrue) return [mem for _, mem in results[:top_k]]score importance * 0.01这个写法是个小技巧核心目的是让重要性在排序里起到一个破平局的作用而不是压过相关性本身。如果直接把重要度加进去很容易出现一条 10 分高重要度的老记忆压过 0.9 相关度的当前热点的尴尬情况。4.4 注入环节如何避免模型复述记忆而不是使用记忆经历过的人都懂这个痛点你辛辛苦苦把记忆喂进去了结果模型在回答开头来了句根据你的历史记忆你之前提到过……然后复述了一遍记忆内容真正有用的回答却很少。这就是注入方式不对。我后来的 prompt 写法是这样的你是用户的长期协作者。以下信息中部分来自之前的对话。请在回答时自然使用这些信息但不要提及根据记忆根据历史记录这类字眼直接给出结果。关键就一句话要求它用记忆而不是复述记忆。相当于你给下属一堆参考资料但是要求他直接给出方案而不是把资料念一遍。加了这句话之后输出立刻自然了很多。另外注入位置也有讲究。记忆应该放在 system prompt 里而不是 user message 里。放在 user message 里模型会觉得这是用户当前发的一段内容容易混淆当前输入和历史信息的边界。放在 system prompt 里则更接近长期配置模型更容易把它当作背景知识来使用。4.5 记忆维护不清理的代价是系统逐渐变傻记忆库如果不做维护时间一长就会积累大量过时或者低价值的信息。这个现象我称之为记忆污染模型检索到的每条记忆可能都没错但它们组合在一起却给了模型一个过时的、混乱的背景。我定的维护周期是每周跑一次离线清理删除importance低于 4 且 30 天未更新的记忆。超过 60 天未被任何检索命中的记忆降为候选归档不再参与默认检索。同类记忆累计超过 20 条时触发一次记忆合并把多条相近内容压缩成一条综合性的记录。这也是我想提醒的不要以为记忆库是只存不减的。人脑记太多东西都会遗忘AI 的记忆库更需要一套遗忘机制。合理的遗忘才能保证重要的记忆不被噪音淹没。5. 实战中踩过的坑与问题排查实录这套系统我前后跑了近两个月踩过的坑不少。我把最典型的几个整理成表同时也聊聊排查过程。现象可能原因排查方向与解决办法模型总是引用过时信息记忆库缺少时间维度的校验给记忆加上created_at检索时过滤掉明显过时的记忆或在 prompt 里注明时间注入的记忆和当前话题完全无关相关性阈值设置太低把阈值从 0.6 调整到 0.75 以上检查 embedding 模型是否适配prompt 越来越长成本飙升top_k 设置过大把返回条数限制在 3 到 5 条同时压缩单条记忆字数记忆库里充满重复内容缺少语义查重入库前加相似度比对大于 0.9 直接走更新逻辑模型回答变得答非所问记忆注入的权重过高降低记忆注入的可信度描述改为以下信息仅供参考多条记忆相互矛盾没有处理记忆冲突同主题记忆记录时保留时间戳检索时优先返回最新一条5.1 记忆污染是最隐蔽的坑有一次我把top_k设成 10结果每次新对话模型都会把我一个月前随手提到的一个小众框架当成背景知识反复提及而这个框架其实早就被我排在项目外面了。排查了半天才发现那条记忆的向量和很多技术类问题都存在中等相似度相关性阈值 0.65 拦不住它。后来我把阈值提高到了 0.75并且把该记忆的importance做了一次降权问题立刻消失。这也是我要强调的宁可少注入也不要注入可疑的记忆。一条不相关的记忆对回答质量的破坏远远大于一条相关记忆带来的增益。5.2 多会话场景下的记忆冲突另一个让我头疼的问题是多个会话各自提取记忆结果对同一个主题产生了矛盾记录。比如会话 A 里你说我打算用某个方案会话 B 里你说还是算了改用另一个方案两条记忆都进了库。检索时如果两条都被捞出来模型就会困惑。我的解决办法是给每条记忆加上source_session和updated_at在检索时对同主题记忆做时间优先处理同一关键词下只保留最新一条作为高置信记忆。这个逻辑用 SQL 很好实现只需要在检索时按主题分组取每组最新记录。5.3 成本控制记忆系统也可能成为吞 token 大户最后提醒一下成本。很多人觉得记忆系统能省 token确实它省下了重复交代背景的开销但提取和总结本身也要消耗 token。如果你每轮对话都触发一次提取成本不降反升。我实测下来比较合理的方案是每 5 轮对话触发一次轻量级提取。每次会话结束时做一次完整总结和记忆更新。检索结果只取 3 条。偶尔信息不够再补一次二次检索。这个策略下记忆系统带来的 token 开销大约占整体对话流的 8% 到 12%但省下的重复说明成本远大于这个值。你可以根据自己对话的长度和频率调整这个比例。6. 缓慢沉淀之后的一点个人体会做这套记忆系统的过程让我对一个点特别有感触AI 对话体验的瓶颈很多时候不在模型本身而在于你有没有给它一个可以记住你的环境。claude-mem 这种思路真正改变的不是模型的能力而是你和 AI 之间的协作关系——从一个陌生人变成一个熟悉彼此的搭档。我在实际使用中还有一个很小的技巧想分享每过一两周把记忆库里的内容导出来读一遍。你会惊讶地发现它记录的东西有些你自己都快忘了有些又显得很琐碎。这个过程能反过来帮你校准提取指令告诉系统哪些该记、哪些不该记。记忆库需要被审视它和人的记忆一样如果不定期整理就会慢慢变成一屋子没有索引的杂物。如果你现在还没有给 AI 加记忆我的建议是不要一步到位搞复杂的架构。先做最简单的一版一个 SQLite 文件、一次提取调用、一个检索函数跑通最小闭环之后再去加分类、加权重、加自动清理。先把记忆跑起来比什么都重要。
阅读完成 · 觉得有帮助?