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

我查日志才发现,它在第 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 的信息损失不在存储阶段,而在检索阶段。它有三个环节会丢信息:
- 索引切块:长文档被切成 chunk 嵌入向量库。切块是人为的边界,一段完整的事实可能被一分为二,任何一半单独看都没有意义。
- 召回盲区:向量检索本质是“语义相似度匹配”。但时间顺序、数值范围、逻辑推导链这类信息,相似度根本描述不了。Agent 问“后来怎么样了”,检索回来的可能是最早的那轮讨论。
- 排序截断:召回结果按相似度排序后只取前 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