当对话历史超出上下文窗口时,有哪些上下文压缩策略?各自的优缺点是什么?

魏远标 Lv7

参考答案

上下文溢出是 Agent 系统里最头疼的工程问题之一。Agent 跑个复杂任务,几十轮循环下来,对话历史、工具调用记录、中间结果一堆,200K 的窗口也能给撑满。

主流的压缩策略有 4 种,各有取舍:

1)滑动窗口截断,最简单粗暴,只留最近 N 轮对话,更早的直接丢掉。实现零成本,效果可预测。但问题也很明显,用户在第 2 轮提的核心需求到了第 20 轮可能已经被丢了,Agent 直接”失忆”忘记任务目标。适合每轮相对独立的闲聊场景,不适合需要长程依赖的复杂任务。

2)摘要压缩,用 LLM 把早期对话浓缩成一段精简摘要,替代完整历史。能保住关键信息的同时把 token 数砍掉 80% 以上。代价是每次摘要要多一次 LLM 调用,增加 1 到 3 秒延迟和额外成本,而且摘要质量不稳定,关键细节一旦在摘要中丢了,后面的推理就可能跑偏。

3)递进式摘要,是摘要压缩的升级版。不是攒到快溢出了再一口气摘要,每隔 5 轮就做一次小范围摘要,摘要结果作为后续上下文的一部分。随着对话继续,早期的摘要会被进一步压缩。信息衰减是渐进的,比一刀切平滑很多。

4)选择性保留,根据信息的重要性分级决定保留还是丢弃。系统提示词、用户原始需求、关键决策节点这些高优内容始终保留,中间的工具调用细节和过渡性推理过程可以丢弃或压缩。实现上需要一套重要性评分机制,可以用规则,也可以用模型打分。

扩展知识

生产系统怎么做:混合分层压缩

实际线上跑的 Agent 系统不会只靠一种策略,通常是分层组合。一个经过验证的方案是:

系统提示词和用户的核心需求,永远不压缩,始终放在上下文的最前面。最近 5 轮对话完整保留,保证 Agent 对当前任务状态有清晰认知。5 到 15 轮前的对话做摘要压缩,保留关键结论和决策。15 轮之前的内容丢弃,或者只留一句话级别的极简摘要。

这样越近的信息越完整,越远的信息越压缩,系统级的关键信息始终在。整个策略实现起来也不复杂,一个定时检查上下文长度的 hook,快到窗口上限的 80% 就触发压缩流程。

工具调用结果的压缩是重点中的重点

在 Agent 场景下,上下文膨胀的大头不是用户消息,是工具调用的返回结果。一次数据库查询可能返回 3000 个 token 的原始数据,一次网页搜索结果可能有 5000 token,Agent 跑 10 轮调了 8 次工具,光工具结果就占掉 3 万多 token。

针对工具结果的压缩有个很实用的技巧:工具返回结果被 Agent 用过一次之后,也就是模型已经基于这个结果做了推理和决策,就可以把完整结果替换成一个简短摘要。比如原来 2000 token 的查询结果,替换成”[工具结果摘要:查询返回 300 条记录,最高销量产品为 XX,总销售额 1200 万]”,只占 50 个 token。压缩率 97%,但后续推理需要的关键信息都在。

外部化存储:用长期记忆扩展短期记忆

还有一种思路是把上下文内容转移到外部存储,需要的时候再检索回来。

做法是:上下文快满时,把较早的对话内容向量化后存进向量数据库,上下文中只保留最近的对话。每一轮新的推理开始前,根据当前问题去向量库里检索可能相关的历史信息,检索到的内容临时加载回上下文。

理论上这种方式能支持无限长的对话,Mem0、Zep 这些开源项目就是做这个的。

但实际用起来有两个坑:一是检索召回率不稳定,真正需要的信息可能检索不到;二是每轮多一次向量检索,增加 200 到 500 毫秒的延迟。适合那种需要跨天、跨会话保持记忆的场景,比如个人助理类产品。

预防优于治疗

最好的上下文管理不是溢出了才压缩,是从一开始就控住增长。精简系统提示词,不要长篇大论;工具定义按需加载,当前任务用不到的工具别塞进上下文;工具返回结果在入上下文之前就做一次预处理,去掉冗余字段和重复信息。

这些预防措施做到位,很多时候根本不用触发压缩。

面试官追问

提问:摘要压缩的时候,怎么保证摘要不会丢掉关键信息?

回答:核心是在摘要的 Prompt 里明确告诉模型哪些信息必须保留。一般会给一个摘要模板,要求模型保留用户的原始目标、已完成的步骤、未完成的任务、关键的数据和结论。然后可以做一个验证步骤,摘要生成后用另一个 Prompt 检查”原始对话中的关键信息是否在摘要中都能找到”,如果缺失就补上。实测下来,有明确模板的摘要比直接让模型”总结一下”质量高很多。

提问:递进式摘要和一次性摘要相比,成本是不是更高?什么时候该用哪种?

回答:递进式摘要确实调用次数更多,但每次调用处理的文本量小,单次成本低,总成本不一定比一次性摘要高多少。关键区别在于信息保真度,递进式摘要每次只压缩一小段,丢失的信息更少更可控。如果任务对早期信息的依赖不强,比如客服对话,滑动窗口加一次性摘要就够了。如果是那种需要跑 30 轮以上的复杂任务,每一步决策都可能依赖前面的结果,递进式摘要明显更稳。

提问:上下文窗口越来越大,现在还需要做压缩吗?

回答:窗口大了不代表不需要压缩。首先是成本问题,128K 的输入一次调用就是好几美元,Agent 跑 10 轮就是几十美元,没有哪个商业产品撑得住。其次是性能问题,上下文越长模型的推理速度越慢,首 token 延迟可能从 1 秒涨到 10 秒。最后是质量问题,研究表明模型在超长上下文中容易出现”迷失在中间”的现象,中间位置的信息被忽略的概率明显更高。所以即使窗口够大,压缩依然是刚需,只是触发阈值可以设得更宽松一些。

提问:向量化存储方案中,检索召回不准怎么办?

回答:单靠向量相似度检索确实不够靠谱,可以加两层保险。第一层是混合检索,向量检索加关键词检索结合,用 RRF 融合排序,这样语义相关的和字面匹配的都能召回。第二层是给每条存储的记忆打上结构化标签,比如”任务目标””工具调用结果””用户偏好”,检索时可以先按标签过滤再做相似度排序,精度能提升不少。