144、流式长文本记忆:向量+摘要+窗口
那阵子线上服务老是报错,一看日志全是Context length exceeded,用户聊到第20轮,历史记录硬塞进提示词,直接撑爆了上下文窗口。当时第一反应是上个滑动窗口,把最老的对话丢掉,保留最近的几轮。改完果然不报错了,但用户回头就骂——模型把他半小时前报过的车牌号忘了,整个客服对话断片。这就是典型的长文本记忆问题:窗口太短丢细节,窗口太长放不下,摘要会丢精确信息,向量检索又容易召回一堆无关片段。后来我把这三样揉在一起,才算是把流式长文本记忆这口锅端稳了。
先说说窗口。滑动窗口是最朴素的方案,本质就是“只保留最近N条消息”。工程上好实现,内存占用固定,推理时token数可控。但它的致命伤是“硬遗忘”——不管老信息重不重要,一旦滑出窗口就彻底消失。我试过把窗口调大,能缓解,但对话一长还是炸,而且大窗口会让模型注意力分散,回答质量反而下降。更气人的是,用户经常在聊了十几轮之后突然问“我一开始说的那个地址还记得吗”,这时候窗口里早就没影了。
后来我加了摘要线程。思路是:当窗口快满时,把窗口里最老的一半消息喂给小模型,生成一段“历史摘要”,存起来。之后每次对话,都把摘要加在窗口前面,相当于给模型一个“压缩过的过去”。这样确实能留住大方向,比如用户想要什么、聊过什么主题。但摘要有个大坑——它是损失压缩。具体数值、名字、条款细节,摘要模型一偷懒就给你省了。有次用户问“我上次说的预算上限是三万还是五万”,摘要里只写了“讨论了预算”,等于没写。
就在这两个方案来回折腾的时候,我意识到它们其实是互补的。窗口负责“近期精确”,摘要负责“远期概览”,但还缺一个“远期精确”的通道。这时候向量检索就派上用场了。思路很直