Agent 的上下文压缩技术:Summary、Sliding Window、RAG 检索——哪种方式损失最少信息

我把一个 Agent 挂在 GitHub 仓库上帮我分类 issue,跑了一周,效果一直不错。直到有一天,它在一个用户明确说过“我是免费用户,不考虑付费功能”的 issue 下面,兴冲冲地给对方推荐了付费方案。

AI technology illustration

我查日志才发现,它在第 3 轮对话时就知道了这个信息。但它的上下文窗口在第 28 轮时满了,系统把前 27 轮压成了一段摘要。摘要里提到了很多东西——唯独漏掉了这句话。

这个场景做 Agent 的人应该都见过。跑久了,上下文必然溢出。Sliding Window、Summary、RAG 是三种最常见的应对方案,但大多数选型讨论只停留在“哪个更省 token”。

我后来想明白一件事:上下文压缩的本质是选择性遗忘。这三种方案不是三种压缩算法,而是三种截然不同的遗忘方式。它们损失信息的类型完全不同,所以“哪种损失最少”这个问题的答案,比表面看起来复杂得多。

Sliding Window:最诚实的失忆

滑动窗口的意思很朴素:只保留最近的 N 个 token,之前的直接删掉。

我最早觉得这是最笨的方案。后来发现,很多场景下它的效果反而最稳——因为 Agent 的大部分任务是短周期的:写一段代码、调用几个工具、回答一个客服问题,生命周期都在窗口范围内。对这类任务,历史本来就是噪声。

但它的代价是结构性的:窗口之外不是变得模糊,而是被物理删除。第一轮对话里的关键约束,第 6 轮之后就彻底不存在了。你的 Agent 不是记性差,它是失忆。

还有一个很隐蔽的问题:截断通常不会刚好停在语义边界上。窗口砍到句子中间,Agent 只收到半句话——残缺信息比没有信息更危险,因为模型会忍不住脑补缺失的那一半。

位置因素也在拖后腿。Lost in the Middle 这篇论文发现,模型对长上下文两端的感知最强,对中间部分的信息最弱。也就是说,即使信息留在窗口里,只要它落在中间位置,模型也可能视而不见。窗口越大,信息落到中间区域的概率也就越大。

Summary:信息没丢,但被重写了

摘要的思路完全不同:不删原文,而是用 LLM 把历史重新表达成一段更短的文本。

这里有个被低估的细节:摘要不是从原文里挑句子,而是模型重新生成的。这带来两种误差。

第一种是抽象必然丢细节。精确的数字、具体的措辞、事件发生的顺序——这些在摘要里最先消失。你的 Agent 记住的是“用户提到过预算问题”,但预算具体是多少,它不记得了。

第二种更隐蔽:摘要生成过程本身会幻觉。模型在概括时,遇到原文里模糊的地方,会下意识地填上一个概率最高的说法——而这个说法可能是原文根本没有的。我见过一个真实案例:Agent 把“用户可能采用 Elasticsearch”概括成了“用户确定采用 Elasticsearch”,后续所有决策全部跑偏。

更麻烦的是级联。如果每 20 轮压缩一次,很快你就在做“摘要的摘要的摘要”。每一次抽象都会损失一层细节、叠加一层幻觉。轮数足够多之后,保留下来的框架可能还是对的,但支撑框架的证据全部变成了模型的想象。

不过 Summary 有一个别人没有的优势:去噪。摘要把无关的闲聊、重复的讨论、过时的信息都滤掉了。对长期任务,提炼后的摘要反而比原文更容易让 Agent 稳定决策。它损失的是保真度,换来的是信噪比。

RAG:我以为它是无损的,直到踩了坑

你可能会说:那 RAG 呢?所有历史原文都存进外部存储,用到时再检索回来,总该无损了吧。

我最早也是这么以为的,甚至觉得它是三种方案里唯一“正确”的。直到自己实现了一遍,才发现事情没那么简单。

RAG 的信息损失不在存储阶段,而在检索阶段。它有三个环节会丢信息:

  1. 索引切块:长文档被切成 chunk 嵌入向量库。切块是人为的边界,一段完整的事实可能被一分为二,任何一半单独看都没有意义。
  2. 召回盲区:向量检索本质是“语义相似度匹配”。但时间顺序、数值范围、逻辑推导链这类信息,相似度根本描述不了。Agent 问“后来怎么样了”,检索回来的可能是最早的那轮讨论。
  3. 排序截断:召回结果按相似度排序后只取前 K 个。如果第 K+1 个结果恰好是关键信息,它不会出现在上下文里,Agent 甚至不会意识到自己漏了东西。

所以 RAG 的遗忘方式跟前两种都不一样:它不丢失过去,也不丢失细节,它丢失的是连接。对话的上下文由无数隐式连接构成——这句话呼应五轮前的决定,那个参数的取值是在某次讨论中定的。切块之后这些线全断了。RAG 捞回来的是碎片,但碎片之间的关联,它看不见。

三种方式到底损失了什么:一张对比表

维度 Sliding Window Summary RAG
时间跨度 仅窗口内 全历史(浓缩后) 全历史(原文保存)
保真度 窗口内 100%,窗口外 0 框架保真,细节丢失 取决于检索召回率
主要丢什么 过去的一切 精确细节与事件顺序 碎片之间的连接
幻觉风险 低,不生成内容 高,摘要即生成 中,检索错误被当成事实
实现成本 最低 中,压缩消耗 token 最高,索引、召回、更新
典型场景 短周期工具调用 跨天长期任务 事实型知识查询

我现在的方案:三层记忆,而不是三选一

回到开头的 GitHub 场景。后来我怎么修的?我让三种技术各管一段:

  • 最近 15 轮对话:滑动窗口,保证 Agent 对正在做的事有完整上下文。
  • 15 轮之前的历史:滚动摘要,每完成一轮就更新一次,保留任务进展和关键倾向。
  • 明确的关键事实(用户身份、技术约束、任务目标):每轮结束时由 Agent 自己提取,写入向量库。

这个思路不是我先想出来的。MemGPT 论文把 Agent 的内存分页,重要信息换入窗口、不重要的换出到外部存储,本质是同一套逻辑。Anthropic 在 context engineering 的工程建议里也推荐了类似的分层记忆策略。

这套方案的关键不在压缩技术本身,而在一个容易被忽略的问题:谁来决定什么值得保留。让 Agent 在每轮主动标记重要信息,比事后纠结用哪种压缩算法有效得多。压缩永远是被动的补救,标记才是主动的抗遗忘。

顺带提一句,LLMLingua 这类专门做 prompt 压缩的研究也证明了一件事:语言里的冗余远比我们想的多。压缩的潜力是存在的,但冗余被压掉之后,剩下的那点信息密度反而更考验模型的提取能力。

几个常见的问题

长上下文模型出现了,还需要压缩吗?

需要。Gemini、Claude 把窗口做到了百万级,解决的是“装得下”的问题,不是“找得到”的问题。上下文越长,模型对中间内容的感知越弱,信息丢失的机制只是从显式删除转移到了注意力分配。窗口变大可以推迟压缩,但不能取消压缩。

压缩之后,信息还能恢复吗?

Summary 和 Sliding Window 不可恢复,RAG 的原文还在。这也是 RAG 适合审计和合规场景的原因——它有追溯能力,另外两种没有。

直接用现成的 Agent 记忆框架不行吗?

现成框架的记忆策略是通用设计,不会为你的任务场景优化。自定义三层结构不复杂,但你能控制每一步的取舍。通用框架把取舍藏起来了,出问题时反而更难排查。

所以,哪一种损失最少?

如果以 token 为度量单位,RAG 理论上是无损的——原文还在存储里。但如果以 Agent 的实际表现为准,RAG 的检索噪声可能比 Summary 的抽象偏差更致命。

我的判断是:这个问题本身问错了方向。正确的问法是,你允许 Agent 忘记什么

  • 任务短、要求快:Sliding Window,省事且稳定。
  • 任务以周为单位:Summary 做滚动存档,接受细节的丢失。
  • 任务依赖具体事实(API 参数、用户资料、文档条目):RAG 做安全网。
  • 大多数真实 Agent:三者组合,分别管短期、中期、长期。

最后说一句可能得罪人的话:如果你的 Agent 频繁因为上下文压缩而出错,问题往往不是压缩方案选得不对,而是你从来没告诉过它什么不能忘。压缩技术只能决定遗忘的方式,决定不了遗忘的优先级——那个开关,在你手里。

原创文章,作者:guanweilu,如若转载,请注明出处:https://guanweilu.cn/article/375.html

(0)
上一篇 4天前
下一篇 4天前

相关推荐