大模型长期记忆新方案Engram:从上下文缓存到记忆痕迹
最近某大模型团队挂出了一篇名为Engram的新论文。我心里咯噔一下终于有人认真做记忆了。现在各家都在拼上下文窗口动不动就是百万token起步可真正用到对话场景里模型该忘的还是忘用户三天前说过的偏好你第四天再去问它它一脸茫然。Engram这个标题出自神经科学里的“记忆痕迹”论文要解决的正是这个非常琐碎、却又极其值钱的问题模型能不能像人一样把经历过的对话沉淀成长期记忆在关键时刻重新“想”起来。如果你在做智能客服、AI助手、写作工具或者正在被上下文爆炸和丢细节折磨这篇非常值得读。我会把论文核心思路拆开揉碎了讲顺带把复现时候踩过的坑也一起整理出来。1. 论文在解决什么问题大模型的“记性”差在哪儿1.1 长上下文不等于长期记忆很长一段时间里大家觉得模型记性不好是窗口不够大所以拼命往上加窗口。窗口加到几十万、上百万看似能塞下整本书、整段聊天记录但实际用起来并不是那么回事。第一注意力计算是平方复杂度窗口越大每生成一个token的代价越大推理延迟肉眼可见地上升第二信息过载之后模型反而会被大量无关细节淹没。这就像你把最近一个月聊天的截图全部打印出来堆在桌子上地球人都知道里面一定有线索但你根本翻不动也不知道哪一页重要。上下文窗口本质上是把原始文本全部堆在模型面前让模型临时读一遍。它不是记忆只是“这次对话的临时草稿纸”。对话结束窗口一关什么都不会留下。这就是大模型记性差的第一个根源模型没有主动沉淀信息的结构只有“重读上下文”的机制。1.2 现有记忆方案各有各的别扭行业内也不是没想过办法常见的路线有三条。一是RAG把外部文档切块、建索引回答的时候检索出相关的片段拼进提示词。问题是RAG只能查“显式存在”的文本它检索不到“用户偏好喝茶不喜欢加奶”这种藏在对话里的隐性结论除非你另外花钱做信息抽取。二是KV Cache把计算过的缓存保存下来省得重复算注意力。它确实减少了重复计算但这是底层加速方案不是记忆系统缓存里的内容还是逐字逐句的原文没办法筛选和压缩。三是微调把知识写进权重这倒是能长期保存但成本高、周期长今天聊的内容明天就要生效微调根本不现实。简单说RAG是带索引的档案馆KV Cache是临时便签微调是刻石碑而Engram想做的是一个可以随写随读、随读随更新的移动硬盘。2. Engram的核心设计思路给模型装一块会自我维护的“记忆皮层”2.1 从神经科学借来的“记忆痕迹”到底是什么Engram这个词最早是心理学里的概念说的是记忆会在大脑中留下一种物理痕迹每一次回忆都会重新激活这条痕迹。注意它不是原封不动地回放而是根据当前需要把记忆“重建”出来。论文团队把这个思想搬到了大模型上模型不需要存原始对话只需要存经过压缩的、可被重新激活的向量痕迹。这跟人回忆昨天吃了什么很像——你不会把整段吃饭的视频存在脑子里你只会存几个关键片段比如餐厅灯光、朋友的脸、最后一道甜品的味道。需要回忆的时候这些痕迹会被重新组合成一个“记忆画面”。Engram的思路就是这个记忆不是文档库而是可变的、可被重新激活的向量状态。2.2 记忆写入不是全文存档而是“痕迹化”压缩Engram的写入过程分三步先让一个编码器把当前输入变成语义向量然后经过一个重要度评分再通过一个可微门控决定要不要写进记忆库。这里最关键的是“可微门控”。传统缓存是规则式的比如“超过阈值就存”很僵硬而Engram的门控是模型可以学习的它能够根据实时反馈自动学到什么样的信息值得保存。比如用户明确说“以后别给我推辣的”这句话的语义向量加上实体“辣”和否定词重要性评分就会偏高而一句毫无信息量的“嗯嗯”就会被评为低价值直接被过滤掉。这样记忆库不会被垃圾填满留下的都是以后用得上的信息。这一点和RAG有本质区别RAG保存的是原文切片Engram保存的是“语义痕迹”。2.3 记忆读取用当前问题去“踩”记忆痕迹读取阶段系统会把当前问题向量和记忆库里所有痕迹做匹配选取最相关的TopK条然后不是直接把原文拼接在上下文里而是把这些痕迹向量做加权融合再作为额外的条件信息参与生成。这里有个很妙的点痕迹并不是一条条单独存在它们像地板上的足迹你的问题就像脚步踩上去相应位置的痕迹会发光、加权。为了实现这个效果Engram用了双通道打分第一通道是语义相似度第二通道是时序和寿命信息。一条三天前的重要记忆和一条三小时前的高频记忆它们的分数算法是不同。旧的但重要的记忆不能因为时间就彻底消失高频访问的记忆又应该得到额外加成。论文中的处理方式是给每条记忆维护一个“可激活强度”类似于生物记忆里那个经典的遗忘曲线访问得越多强度越强时间间隔越久自动衰减。2.4 与现有技术的关系和差异把Engram和现有方法放在一起对比会更容易理解。下表是我个人的理解不代表论文原文方案长期性动态更新显存/存储开销推理速度影响可解释性适合场景RAG好需要重新建索引中中检索延迟高知识库问答KV Cache短仅当前会话动态高低复用缓存低长上下文本推理微调最好很慢高训练成本无影响低固定风格/技能Engram好实时写入中低向量库中少量检索融合中高多轮对话、个性化助手从定位上说Engram更像是给主模型外挂了一个“可拆卸的长期记忆模块”它不干扰主模型的权重也不会因为一次对话就把模型改傻。这种模块化的设计在工程上非常友好你可以把记忆库单独部署、单独备份甚至给不同用户分配不同的记忆库。3. 关键模块拆解与实现要点3.1 记忆编码器怎么选你以为是小事其实是命门整个Engram的链路中编码器直接决定写入什么语义空间也就决定了检索上限。我在实际实验中发现最省事的做法是直接用主模型某个中间层的输出当记忆向量把文本输入主模型取倒数第二层的hidden state作为表示。这么做的好处是不用额外维护一套独立的embedding模型天然保证记忆向量和主模型的语义空间一致。如果你非要复用开源的embedding模型也不是不行但必须解决对齐问题embedding模型训练目标和主模型不一致检索出来的结果经常是“看着挺近用起来不对”。我试过用通用embedding模型存记忆再用另一个生成模型读取结果检索分数很高生成时却完全用不上。原因就是两个模型的向量空间根本不在一个坐标系里。所以我的建议是先试主模型中间层输出维度不需要太大768到1024就够了。向量不是越大越好太大反而容易过拟合那些细枝末节的差异。3.2 写入门控怎么判断一句废话该不该记门控网络是Engram里最有“学习味”的组件。它接收记忆向量的基础上再拼接几个手工特征比如句子含实体数量、句子的情感强度、句子是不是疑问句、是不是用户明确指令等。然后经过一个单层MLP输出0到1的保留分数。分数超过阈值的才写入记忆库。为什么需要这个门控如果什么都不管把所有句子都编码存进去最后记忆库全是“哈哈哈”“好的”“嗯嗯”真到检索的时候每个向量都差不多等于没有记忆。门控就是过滤器它的目标不是存得多而是存得准。这个打分网络训练起来也比较有意思简单粗暴的做法是先按规则生成一批伪标签比如抽取训练集里那些包含人称、喜好、时间、地点的高实体密度句子作为正样本再用对比损失做一轮初始化。更进一步可以用后续问答中“这条记忆是否被成功命中”作为弱反馈信号用强化学习的方式在线更新门控。但工程上不要一上来就上强化学习先跑通离线规则版再慢慢迭代。3.3 遗忘机制为什么不能简单用LRU淘汰大多数缓存系统用的是LRU也就是最近最少使用满了就把最久没碰过的挤掉。但记忆和缓存不是一回事。一个用户三年前提过小时候最喜欢吃妈妈做的番茄面这个信息可能很长时间都没被访问过但一旦聊到童年它就是决定推荐方向的关键记忆直接LRU淘汰会非常可惜。Engram的遗忘机制靠的是“记忆强度”。每一条记忆有一个初始强度写入时由重要性评分决定每次被成功检索到一次强度就加一点增量同时每条记忆会随时间做指数衰减。最终强度可以用这个公式近似描述strength initial_importance * (1 visit_count * boost) * decay^(days_since_write)decay是一个接近1但小于1的系数比如0.98。当强度低于一个淘汰阈值时这条记忆并不会立刻被删除而是先进入“弱可激活”状态只有极其相关的问题才能匹配到它如果连续很长一段时间内一直被忽略才真正从记忆库里清理掉。这个设计比较像人脑的遗忘和再巩固过程而不是电脑的setInterval清除。我在复现时重点调这个decay系数发现它对跨话题的对话一致性影响极大。decay太大会导致记忆过度衰减用户昨天说过的话第二天就想不起来decay太小又会让久远且不相关的记忆一直霸占检索结果形成干扰。3.4 读取融合记忆是拼进上下文还是改变注意力读取到TopK条记忆以后要怎么让主模型用上它论文里可以有两种实现方式。第一种最简单是把加权融合后的记忆痕迹变成一个特殊的prefix token拼在输入序列最前面和其他token一起走主模型。这样做的好处是通用任何主模型都能接不用改内部结构。第二种是更进一步把记忆向量的Key/Value直接注入主模型的self-attention层相当于让模型在注意力计算时天然就看到这些记忆。第二种效果可能更直接但工程实现复杂需要动主模型代码。从论文的实验看至少公开思路里面prefix方式更容易复现也更容易解释。在读取时机上我强烈建议只在“每一轮回答前”做一次记忆检索不要放到每个token生成时都做。如果每个token都做推理延迟会翻好几倍而对话场景里一轮对话开始之前拿到记忆条件已经足够用了。4. 从论文到工程我在本地复现Engram踩过的坑4.1 最小可跑的复现结构如果你也想自己试先不要追求完整复现论文实验搭一个最小闭环就够了。我本地用的结构是这样的一个7B量级的开源基础模型作为主模型一个编码器直接用主模型的中间层输出一个记忆库用简单的向量列表加SQLite做持久化门控网络先用规则初始化。流程是用户输入进入编码器得到query向量去记忆库检索TopK同时把当前输入过一遍门控决定要不要写入记忆然后query向量、TopK记忆向量、当前输入一起交给主模型生成回答。这个最小闭环大概只需要几百行代码不需要训练主模型只训练门控和一个可选的融合映射层。如果你手里有Chat格式的多轮对话数据效果会更好可以让门控先学到哪些用户语句应该入记忆库。4.2 参数配置参考参数其实是复现Engram最容易翻车的地方。我整理了一份个人推荐的初始值参数推荐值说明记忆库容量128小场景先不用太大越大越难调检索记忆向量维度768用主模型中间层输出时保持一致TopK读取数5太少容易漏太多容易引入噪音写入阈值0.6先以高精度为主宁缺毋滥初始重要性权重0.8新记忆写入时的基础强度衰减系数0.98跨天场景建议0.98~0.99访问增益0.1每次被检索命中后强度的增量这些参数不是绝对的但它们是很好的起点。在跑测试集的时候你可以构造一个“藏偏好”实验第一轮聊天里让用户随口说“我讨厌香菜和折耳根”然后后面连续聊十轮完全无关的话题最后突然问“晚上带你去吃火锅你戒掉什么”看看模型能不能答出来。这个测试比标准NLP指标直观得多能快速暴露出写入、检索、遗忘三个环节的问题。4.3 复现时的四个大坑第一个坑是写入太激进。一开始我把阈值设得很低结果什么句子都进记忆库没过多久库就满了检索时十有八九返回的都是“哈哈笑死”之类的高频无意义向量。解决办法是把阈值抬高并且在小样本上先统计一遍重要性分数的分布找到分界点。第二个坑是记忆串味。在多轮对话里用户会不断切换话题如果记忆库不做领域隔离最早聊的是吃什么后来聊的是写代码检索时出来两条记忆混在一起模型生成的结果两不沾。第三个坑是显存暴涨。把记忆编码器和主模型同时加载以后显存直接翻倍。后来我把编码器与主模型共享底层参数并且用低比特加载显存问题才算按住。第四个坑是模型过度“背书”。有些时候检索到的记忆确实很匹配但模型像被喷了固化剂一样非要把那句话原样复述一遍而不是基于记忆做灵活推理。后来我把记忆融合权重调低让它更像“线索”而不是“强制条件”输出才自然起来。5. 常见问题与排查技巧实录5.1 记忆总是检索不到先别急着骂模型如果检索出来的记忆排名很高但模型回答时完全没体现先去看融合层的权重是不是太低了记忆根本没有传进主模型。如果检索分数普遍都很低任何一条都没过阈值大概率是向量空间没对齐。这里有个检查技巧把你写进去的原始文本重新编码然后再用同样的编码器查一次理论上自相似度应该接近1。如果连自相似度都不高那就是编码器的问题换个中间层再试。另外所有向量都做L2归一化是标配不归一化会出现某个记忆向量模长特别大永远霸占TopK的情况。5.2 记忆串台和混淆怎么办如果你在做多用户多场景的AI助手这个问题一定躲不掉。解决办法是在记忆库结构上增加命名空间每个用户、每个业务场景一个独立分区。写入的时候先判断当前会话属于哪个域读取的时候只检索当前域的记忆。如果两个场景偶尔交叉可以让检索模块在打分前增加一个域匹配分数域不同就罚分。不要指望模型自己能天然区分“这是A客户的偏好不能用到B客户身上”至少在现阶段不行。给记忆库加显式的场景标签是最便宜也最有效的手段。5.3 推理延迟涨得厉害怎么压下去多了编码和检索延迟增加是必然的。我在本地的低配环境上每轮回答增加大约30到80毫秒看起来不夸张但高并发服务里这个增量会被放大。建议做三件事第一把记忆写入放到离线异步队列线上只做读取和融合第二读取频率改为“每轮回答之前只检索一次”不要每个token都检索第三记忆库如果容量上限是几千条完全可以用暴力内积检索如果到了几十万条再引入近似最近邻索引。这里要记住一个原则Engram是记忆模块不是搜索系统不要为了检索性能把架构搞复杂。5.4 调参速查表最后我把最常见的问题、可能的原因和调整方向整理成了表方便你卡壳的时候直接对号入座。现象可能原因调整方向检索分数普遍很低编码器语义空间不对齐换主模型中间层输出向量归一化记忆命中后输出无关融合权重太低或TopK太小提高TopK稍微调高融合权重记忆库很快堆满写入阈值过低、门控没生效提高阈值检查门控输出分布回答前后不一致衰减系数太大旧记忆被过早弱化调低衰减系数提高数值比如从0.98调成0.99记忆串台缺少会话/场景隔离按用户、按场景建立记忆分区显存占用过高编码器重复加载、精度过高共享主模型参数使用低比特推理模型喜欢复述记忆原文记忆被当成硬约束降低融合权重或把记忆从prefix改成软提示我个人在实际操作中的体会是Engram这个方向的最大价值不是那套复杂公式而是它逼你去区分“缓存”和“记忆”。过去我们习惯于把所有信息堆进上下文让模型自己找重点而Engram的思路是提前帮模型筛好重点再让模型在生成时把它当线索用。这就像同样是翻阅档案你让实习生自己翻完整个档案室还是直接把关键的几卷放到他桌上效果完全不一样。这篇论文的工程细节还没有到开箱即用的程度门控怎么训练、记忆遗忘曲线怎么定论文里都留了不少口子。但如果你正在做需要长期跟踪用户状态的产品这个方向值得砸时间下去。先把最小闭环跑通再慢慢调你会发现模型记住的那些小细节比它偶尔说出一句漂亮的话更打动人。