资讯详情

为AI助手构建跨会话长期记忆:架构设计与工程实践

📅 2026/10/9 6:44:19 | 华诺云谱 👁 阅读
为AI助手构建跨会话长期记忆:架构设计与工程实践
1. 记忆缺失会话式AI助手最大的体验裂缝过去大半年我一直把Claude当作日常主力AI助手在用——写代码、梳理思路、起草文档、研究技术方案。用得越深入越能感受到一个难以忽视的痛点它没有跨会话记忆。今天刚讨论完的项目背景明天新建对话后又要重新解释一遍上周确定的技术选型结论这周再问它就变成了陌生的初次见面。这种体验带来的烦躁感非常真实就像你反复向同一个人做自我介绍而对方每次都表现得彬彬有礼又毫无印象。这个问题的根源在于Claude本身的设计。每次API调用或每次对话会话本质上都是独立的上下文执行单元。对话窗口内的上下文再多、再长关掉窗口的那一刻就烟消云散。底层的大模型参数是固定的它不会因为你昨天用过就记住昨天说了什么。虽然有限长度的上下文窗口号称能覆盖几十万token但对话一旦跨越多个会话信息就断层了。这不仅是Claude的问题也是所有主流会话式AI产品共同的架构特性。我做了一个叫做 claude-mem 的小项目核心目标就是给Claude补上这层缺失的长期记忆。实现思路并不神秘构建一个独立于Claude本身的记忆层在每次对话结束后自动提取值得沉淀的信息存入本地持久化存储中下次开启新对话时再把相关记忆注入到系统提示或首轮用户消息中让Claude同时拥有本次对话的上下文和跨会话的长期记忆两个层次的信息源。这个方案解决的核心问题是让AI助手从一个只有工作记忆的存在变成一个拥有长期记忆的协作伙伴。它适用于任何深度使用Claude的场景——个人知识库管理、长期项目跟进、写作素材积累、持续性的技术研究等。如果你只是偶尔问几个一次性问题这个工具的意义不大但如果你像我一样每天和Claude打交道超过两小时记忆层带来的体验提升是质的飞跃。我把整个项目从设计到落地踩过的坑都整理了出来下面从架构选择、核心实现、参数调优到真实使用中的意外情况逐一展开。2. 先想清楚记忆长什么样分层记忆架构与存储选型动手写代码之前最需要想明白的不是用哪个向量数据库而是记忆本身应该分几层、每层存什么、以什么格式存。我最初的想法非常简单粗暴把每轮对话全文保存下来下次把所有历史记录一股脑塞进上下文。很快我就发现这个方案根本走不通——对话记录会指数级膨胀塞满上下文窗口的代价极高而且绝大部分内容对当前问题毫无帮助。我最终采用的方案是把记忆拆成三个层级第一层原子记忆事实碎片这一层保存的是明确的、可独立引用的事实条目比如用户的项目叫claude-mem目标是给Claude加长期记忆用户偏好使用Python编写CLI工具数据库选型用的是SQLite vector extension。每个条目是一段简短的自然语言陈述附带时间戳、来源会话ID和标签。这一层为的是快速检索和高精度命中。第二层会话摘要上下文压缩每次对话结束之后对完整对话做一次结构化摘要控制在几百字以内记录这次对话的目标、达成的结论、遗留的未解决问题。这一层是为了让Claude在未来的新对话中能够快速回忆起之前聊过什么而不需要逐条翻看事实碎片。摘要本身也是可检索的每份摘要同样带时间戳和关键词。第三层项目档案长期演变记录当围绕同一个主题的对话累积到一定数量后将多份摘要和原子记忆合并、归纳形成一个相对稳定的项目级档案。比如claude-mem项目下会有它的定位、架构决策、技术栈、遇到的坑、下一步计划等条目。这层档案更新频率最低但价值最高它代表着跨长期对话的知识沉淀而不是简单的信息累积。三层记忆的读写策略完全不同原子记忆频繁写入、频繁读取必须毫秒级响应会话摘要每次对话结束后写入下次对话开始前读取项目档案则每次对话结束后都要检查是否有需要更新的结论但只在涉及该项目时才读取。从存储角度说这套设计天然适合混合存储方案。关于具体存储选型我试验过三种方案放在一起对比如下方案优点缺点最终结论Elasticsearch检索功能成熟、分布式、支持全文和向量混合检索太重本地跑起来资源占太多配置复杂不适合个人项目Qdrant独立向量库性能好向量检索体验顺畅需要单独部署一个服务数据备份迁移略麻烦可用但偏重SQLite sqlite-vec 扩展零部署、单文件、支持向量检索和结构化查询高并发能力弱但个人场景完全够用最终选择我最终选了 SQLite sqlite-vec理由很朴素个人场景的数据量级通常在几十万条以内一次查询最多涉及几十个向量计算SQLite完全扛得住。单文件的特性让备份变成复制粘贴一个文件不用管什么docker容器、环境变量、端口映射。而且记忆本来就是高度结构化的数据用SQL表达事实筛选、标签匹配、时间范围过滤比纯向量库方便得多。提示向量检索是记忆工具的核心依赖但永远不要只依赖向量检索。记忆查询必须走结构化条件过滤 向量相似度排序的混合检索路线纯向量检索在事实型记忆上的准确率容易翻车。架构中最关键的一个设计决策是记忆层不直接改动Claude的内部机制。我不去逆向或修改Claude的对话逻辑而是作为外部服务在对话前后做摘取注入。这样做的好处显而易见——Claude升级、接口变化、API调整都不会影响记忆层的稳定性我用的是官方支持的接口不存在兼容性崩溃的风险。3. 记忆落库与提取的工程实现从对话记录到可检索记忆架构想清楚后真正的工程实现从一条内部消息的流转链路开始。Claude的API本身不支持主动回调所以我设计了一个中间层模式所有对话请求先经过我自己写的一个代理脚本对话完成后脚本自动执行记忆提取流程。如果你用的ChatGPT用法类似也完全可以参考这套逻辑。整个流程分四步会话记录收集、记忆提取、语义编码、写入存储。下面每一步都有关键细节要说明。3.1 会话记录收集别等API返回后再开始处理Claude的API本身会返回整个对话的历史消息数组这是最直接的会话数据来源。但这里有一个隐藏问题API返回的消息包含全部token内容如果对话很长直接交给提取步骤去处理会消耗非常多的额外token成本翻倍甚至更高。我的做法是在对话尚未结束时就对消息流做滑动窗口摘要。具体说每当检测到积累的消息超过一定阈值比如8000 token就对最老的那一批消息做一次增量摘要把摘要当作一条特殊消息插回历史中原始消息标记为已归档。这样最终拿到API返回结果时历史里已经有压缩好的摘要后续提取步骤的入力数据量可以压缩到原来的三分之一或更少。这个设计的代价是增加了摘要的层级摘要的摘要会损失部分微观细节。但好处是成本可控、处理速度快。实际项目跑下来我宁可接受摘要颗粒度稍粗也不愿意每次对话结束后花几千token再做全量提炼。成本问题在没有预算限制的玩具项目里无所谓一旦放到真实使用中它是决定工具能不能长期跑下去的关键。配套一个关键实现——所有会话记录按固定格式落盘后我开始对它们做结构化信息提取。这一步我用Claude自身的模型来执行为它设计了一个稳定的提取prompt你是一个记忆提取引擎。阅读下面这段对话记录提取以下类型的记忆条目 1. 用户明确表达过的偏好、习惯、选择取向 2. 项目中确定的技术决策及原因 3. 被反复提到的事物或概念 4. 尚未完成的待办事项或悬而未决的问题 5. 可复用的方法论、流程、模板 要求 - 每条记忆用一句完整自然语言表述不超过40字 - 事实型记忆严禁推测只提取对话中明确出现的信息 - 每条记忆输出一个标签列表标签必须用小写英文 - 若对话内容过少或过杂允许只输出一条摘要不强求填满 - 以JSON数组格式输出这个prompt经历了至少五轮迭代。最初版本过于开放导致提取出来的条目质量参差后来我加了逐条计数约束反而让模型把注意力集中在真正重要的内容上。限制条件确实会降低覆盖面但换来的是精度对记忆系统来说精度比召回率重要一个数量级。3.2 向量化与写入策略不要全量重写向量库提取出的每条记忆需要变成向量才能支持语义检索。我实验了几个embedding模型具体参数最终调试结果后面会单开一节讲。这里先说一个实际踩到的大坑向量化后的写入不能只做append。我最初的设计是每次提取完直接插入数据库就完事。用了一周后发现问题记忆库里出现大量互相矛盾或者重复覆盖的条目。比如周一记录用户决定使用SQLite周五实际迁移到了Qdrant但周一的那条记忆还留在库里。检索时Claude同时看到两条冲突的记忆轻则困惑重则给出完全反方向的回答。最终我采用了一种记忆去重与冲突消解策略插入新记忆前先对相同标签簇下的既有记忆做一遍相似度比对如果新记忆与旧记忆语义相似度超过0.85则不插入视作重复如果新记忆明显更新带更新的时间戳、以决定改为不再等措辞开头则旧记忆标记为deprecated新记忆覆盖其位置。这个策略靠一套简单的规则加上向量相似度判断实现没有动用复杂的图数据库或逻辑推理系统效果完全够用。写入时的另一个细节是分批写入。一次性把所有向量插入SQLite会导致单次写入耗时变长而记忆提取过程本来就占用token如果再拖慢整体响应用户体验就很难受了。我现在单批写入控制在64条以内用事务包住实测单次延迟能控制在几十毫秒级别。3.3 读取注入新会话开始时做检索增强读侧的逻辑比写侧单纯一些但要考虑更细的上下文适配问题。每次新会话开始前记忆层需要回答三个问题这次对话大概与哪些主题相关记忆库里哪些信息应该被带进上下文带多少条不会挤占用户正常任务的空间我的实现方式是先用用户的首条消息做一次向量查询取回最高相似度的若干条候选记忆同时结合当前日期和项目名做结构化筛选召回最近活跃的项目档案。合并后的候选集再做一次重排序按时间衰减 相关度 重要度三个维度打分取前8条作为注入内容。这里有个值得注意的边界硬性限制注入条数是必要的。刚开始我试图把所有高相关记忆全部注入结果Claude的回应变得异常冗长甚至反客为主频繁提及根据你的历史记录明显干扰了自然对话。后来我把上限定为8条每条控制在40字以内整体注入内容不超过400token效果立刻正常了许多。经过这几个步骤完整的数据链路是这样闭合的对话结束——提取记忆——向量化——冲突处理后入库新对话开始——首条消息向量化——混合检索——打分排序——注入上下文——Claude带着记忆回答用户。4. 模型与参数调优embedding选型、向量维度、阈值设定的实测对比claude-mem这类工具的检索质量百分之八十由向量化环节决定。模型选错了后面调什么参数都只是微调方向性错误无法通过技巧弥补。4.1 开源embedding模型实测对比我先后在本地和云端测试了三个embedding模型分别是text-embedding-3-small、bge-m3和gte-small。模型向量维度检索精度自建30条测试集单次编码延迟适用结论text-embedding-3-small15360.81约80ms云端精度最高但有网络依赖和数据外发问题bge-m310240.78约40ms本地CPU性能均衡支持多语言离线可用gte-small3840.72约20ms本地CPU速度快适合对精度要求不高的场景我最终选择bge-m3作为主模型。理由有三个一是它的多语言支持非常关键我的记忆条目里中英混杂很常见早期用单语模型时经常出现中文query召回不到中文记忆的情况二是它支持本地推理记忆这类高度私密的数据长期放在第三方embedding服务上总让人觉得不踏实三是向量维度1024适中SQLite存储和计算的压力都可接受。注意如果选用本地模型务必确认运行环境的内存足够。bge-m3默认按FP32加载大约需要2GB左右内存机器配置普通的建议用量化版本精度损失可接受。4.2 检索相关的三个关键参数调试过程中以下三个参数的设置直接影响了记忆召回的准确率相似度阈值。我最初设为0.7结果大量无关记忆被当成相关召回注入后Claude的回复变得莫名其妙。后来参考测试集调参把阈值定在0.82准确率明显提升。调参的思路很简单取一批已知相关的记忆对和一批已知无关的记忆对算两者相似度分布的交叉点阈值就定在交叉点附近。Top-K条数。前面提过注入上限设为8条检索端我是取了前20条再做重排这样做是为了保证候选集足够丰富同时让最终的注入集合更精准。如果直接取前8条容易漏掉虽排名靠后但实际很重要的时间衰减记忆。时间衰减系数。记忆的价值会随时间变化。比如用户上周明确说过数据库用SQLite这周很可能已经改成了其他方案。我在重排打分中加入时间衰减因子半衰期定为14天超过14天的记忆相似度得分乘以0.5超过28天乘以0.25。这个策略让新近记忆在重排中自动获得更高优先级有效缓解了记忆污染问题。我对衰减系数的调整有个快速验证方法在后面会讲到。4.3 记忆提取的模型选择用Claude自己还是用更小的模型记忆提取质量与使用的模型能力直接相关。开始时我用Claude的Haiku模型来执行提取prompt因为成本低、速度快但提取条目的完整度和准确性明显不如用Claude主模型。主模型提取的内容更精炼、标签质量更好错误推断更少。综合算了一笔账主模型提取1000token对话大约消耗200token的额外输出按实际使用量级折算成本增加约5%。但这5%换来的是记忆质量的大幅提升。我的建议是提取任务用当前可用的最强模型不要省这个钱。记忆是工具的核心资产提取质量差会让整个记忆库快速腐化后续检索、注入全跟着受害。把对话摘要和条目提取分开执行摘要用廉价模型粗加工条目提取用强模型精加工是性价比最高的组合。过程中还有一个反复困扰我的问题记忆提取任务的输出格式稳定性。最初直接用JSON输出时经常出现格式错误尤其是标签字段里夹带中文或特殊符号。后来我在prompt里明确约束标签只允许由a到z的英文字母和下划线组成不允许数字开头并且额外用了一段代码来兜底解析当模型输出的JSON解析失败时尝试清洗非法字符、修复缺失的括号再解析仍失败则该条记忆丢弃并记录日志避免一个坏条目让整个写入流程崩溃。5. 实战中反复踩到的坑记忆污染、上下文膨胀与多项目混淆这一节内容全部来自真实使用过程中踩过的坑每一个都花了我不少时间排查和修复。如果有人要自己实现类似工具希望这些经验能帮你绕开重复劳动。5.1 记忆污染AI乱说导致的幻觉记忆记忆工具最危险的失败模式不是漏记而是记了不该记的东西。我在测试阶段发现某些对话中Claude会在上下文不充分时推测用户意图如果我把这类推测产物当成事实存进记忆库就会出现孤儿记忆——没有任何事实基础全靠模型脑补。典型的例子用户说我想给项目加一个缓存层Claude回答好的我会在项目中引入Redis作为缓存方案。如果提取器把项目中引入Redis记成事实条目那么后续对话中每当涉及该项目Claude都会默认缓存方案是Redis哪怕用户后来决定用别的方案——这就是记忆污染的开始。解决措施分了两层提取层加入事实性筛选约束要求模型只提取对话里出现过且用户明确认可的内容对于模型建议、假设性讨论单独打上proposal标签不进入事实记忆库查询层加入了来源标记注入上下文时明确标注每条记忆的来源会话和时间让Claude能判断哪条更可信。5.2 攻破上下文膨胀记忆注入量不是越多越好刚开始我天真地认为记忆注入越多Claude的表现越好毕竟它知道的更多。实际上完全相反。系统里同时注入几十条记忆Claude的注意力会被大量历史信息分散最新对话中被讨论的核心问题反而被冲淡。有一次我在关于代码重构的对话中注入了大量上个项目的归档记录Claude的回答通篇都在引用旧项目的技术方案令人哭笑不得。我用一个非常直观的方式验证了注入条数与回复质量的关系。准备同一组技术问题在注入0条、4条、8条、16条、32条记忆的情况下分别测试结果如下注入条数回答准确率回答与当前问题相关性主观体验00.75高有遗忘但回答直接40.84高对比优势明显80.88高最佳状态160.82中开始扯远320.71低上下文污染严重结论非常清晰8条是一个甜点区间超过之后边际效应递减并转为负面。最终我把注入上限设为硬编码8条后续如果要做增强优先考虑让Claude在回复时主动追问缺失信息而不是塞更多记忆。5.3 多项目混淆记忆必须带项目作用域另一个让我头疼的问题是多项目并发使用时的记忆串线。我有三四个长期项目同时在跑如果所有项目的记忆都混在一个库里面检索时经常出现项目A的记忆被注入到项目B的对话中。比如在讨论Python后端项目时Claude突然提起根据之前的记录你决定用Rust重写核心模块——这明显是另一个项目的记忆串过来误导了。解决思路是在每条记忆入库时强制附加project字段检索时先按project做硬过滤只在本项目记忆池内做向量相似度查询。同时我预设了一个默认project值未指定项目时的对话统一归入DEFAULT避免遗漏。这个改动让记忆准确率上升了一大截因为过滤掉了大量跨项目干扰项。但这里也有一个取舍有些记忆是跨项目通用的比如用户偏向使用类型安全的语言用户习惯代码里加详细注释这些属于个人偏好而非项目属性。我从标签体系上做了区分preference标签的记忆不限定项目decision标签的记忆严格限定项目。目前这个区分策略运行良好暂时无需再调整。5.4 长会话的累积误差与折叠策略一次超长会话超过1万条消息带来的问题不在存储而在摘要折叠。折叠摘要的摘要会丢失越来越多的细节时间长了记忆库里的信息颗粒度变粗甚至出现与原始事实冲突的表述。我专门设了一条折叠审计流程每次执行二次折叠时把新摘要和旧摘要做一次语义比对如果发现关键实体项目名、技术名、人名发生了替换或丢失触发告警并把原始消息继续归档保留原文。这条审计规则无法百分百还原所有细节但它保证了最关键的实体信息尽量不丢。对于高价值的超长会话我额外设置了一条原文不可丢弃规则一旦会话中包含用户手动标记的重点内容例如以[记忆]前缀开头的消息这部分原文跳过折叠过程直接单独存档并建立向量索引。这是给重要的原始信息一个免折叠保险。6. 效果验证与更远一步的扩展工具做到能跑之后我做的第一件事不是立刻投入日常使用而是花了半天时间构建了一套验证流程确保每个环节的质量可度量、可回归。否则凭感觉调参很容易陷入改一个参数仿佛更好过几天又觉得更差的循环。6.1 我用的验证方法从测试集建构到盲评我整理了一组约30条跨项目的真实记忆作为测试集每条包含原始对话片段、期望提取出的记忆条目、期望召回时的查询语句。围绕这个测试集我建立了两个指标提取准确率提取出的条目与期望条目的一致性和检索召回率给定查询能召回相关记忆的比例。提取准确率通过跑prompt后与期望条目做语义比对得出通常稳定在0.75到0.85之间。检索召回率则用每一条查询去检索记忆库检查期望记忆是否出现在Top20。除了量化指标还需要人工盲评。我会随机挑几组对话分别运行旧版本配置和新版本配置将各自生成的记忆注入结果打乱顺序后展示给一个不了解实验目的的对照者只看哪个输出让你觉得更像一个了解自己的老助手。这个方法很主观但效率极高能快速发现量化指标无法反映的语感问题。6.2 从claude-mem到通用记忆服务的扩展思路工具做完给Claude用之后我自然而然地想到一个问题这套记忆层能不能泛化到其他AI工具上毕竟市面上常用的AI助手都有类似的记忆缺失问题。我的做法是把记忆读写接口抽成了标准REST API共有三个核心端点插入记忆、检索相关记忆、更新项目档案。目前已经接入了几个常用的命令行AI工具和自建的本地知识库问答系统接入方式就是改一下请求发送逻辑在对话前后各加一次HTTP调用。这套通用化改造给了我一个额外的视角AI工具本身的差异并没有想象中那么大它们真正缺的是统一的记忆编排层。谁能先把跨工具的长期记忆底座做扎实谁就能在后续所有AI交互中获得明显更连贯的体验。这也是我在claude-mem项目完成之后下一步要继续探索的方向——把记忆服务做成一个常驻本地、对多个AI应用透明的后台能力。6.3 持续运行的小技巧备份、监控与自愈项目跑了一段时间后一些运维层面的细节也逐渐浮出水面。备份策略。SQLite单文件备份简单我直接用cron定时把数据库文件复制到另一个磁盘目录保留最近7天的版本。恢复流程就是停服务、替换文件、重启实测从发现异常到恢复完成不到一分钟这个省心的体验是当初选SQLite时没想到的巨大福利。监控指标。我在脚本里埋了几个关键指标每次对话的平均记忆写入条数、每次检索的平均耗时、注入context的token总量、相似度阈值命中比例的分布。每周扫一眼这些数字能及时察觉检索质量是否劣化。比如连续几天写入条数明显偏少说明提取prompt可能出问题了检索平均耗时常态性超高可能是索引碎片化需要重建。自愈机制。当数据库中的孤儿记忆比例超过5%时触发一次自动清理任务把长期未被查询命中的记忆移动到冷存储区。这个机制在早期帮我清掉了很多从旧prompt版本遗留下来的低质量条目让记忆库保持在一个比较健康的状态。如果你也想在自己的工作流中搭一套类似的记忆层我希望这个项目里的取舍能帮你少踩一些坑。最核心的几条心得是记忆条目的质量红线不能放松宁可漏记不可乱记注入量必须克制8条是经验上限项目作用域要从第一天就带上否则后期数据混乱的治理成本远高于一开始设计时的成本。记忆层的价值积累是复利式的坚持用得越久它的准确度和贴合度就越高。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑