跳到主要内容

上下文压缩失真:你的摘要中间件在悄悄丢失什么

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的智能体在第三轮对话时明确说过"绝对不要使用 eval()"。到了第三十轮,它调用了 eval()。你的保险处理系统规定"未经有效身份验证,不得批准理赔"。经过十五个压缩周期后,它批准了一笔。这些不是模型失败——是压缩失败。智能体的推理本身没有问题,是摘要中间件把那条唯一关键的约束丢掉了。

上下文压缩如今已成为长时运行智能体系统的标准基础设施。当对话历史增长到超出上下文窗口时,你就会进行压缩——把旧的轮次汇总成摘要,进行修剪、分块或精炼。问题在于,现代摘要器并不是随机破坏信息,而是可预测地沿着特定的断裂线破坏信息,而大多数团队只在生产环境中才发现这些断裂线。

为什么摘要是有损变换,而非蒸馏

"摘要"这个说法会诱导一种错误类比:你从一个较长的东西变成一个较短但包含相同内容的东西。而实践中,LLM 摘要器并不是在压缩——它们是在改写。它们从源内容生成语义上合理的文本,使用模型认为突出重要的内容。而模型认为重要的内容,是针对通用流畅性优化的,并不针对你的特定下游任务需要恢复的内容。

这造成了一个关键的不对称性:摘要器不知道未来的查询会问什么。摘要过程优先处理高频提及的内容和显著实体——频繁出现的话题、占用较多空间的概念。罕见但关键的信息会被压制,因为它在隐式显著性信号上得分很低。

多轮摘要使这个问题更加复杂。把10轮对话压缩成摘要,再把那个摘要在十几轮后压缩成另一个摘要,你不是在运行一次有损变换——而是在运行一系列级联的有损变换。精确度会降解为近似值。"恰好512条记录"变成"大约500条记录",再变成"数百条记录"。否定表达不只是降解——它们会反转。"用户偏好Python,但Rust是备选"变成"用户偏好Python",再变成"用户了解Python"。三个周期后,约束在语义上已经完全反转。

基于Transformer的摘要器的位置偏差使情况更糟。上下文开头的内容获得更多的注意力权重。埋在长对话中间的信息——最可能包含任务早期建立的详细约束的部分——获得最少的权重,最先被丢弃。

什么会最先被丢弃

对生产智能体轨迹和压缩基准测试的研究,一致指出相同的类别是摘要的第一批牺牲品:

否定表达和约束。 这类内容天生是稀疏的——"永远不要在没有备份的情况下删除"这样的约束,可能在漫长的会话中只出现一次。摘要器对低频内容赋予低显著性。结果是:约束要么被完全丢弃,要么被改写成失去强制性含义的版本。"身份验证很重要"和"未经验证身份,不得继续操作"不是一回事。前者是建议,后者是硬性停止。

条件依赖关系。 "如果API返回429,以指数退避最多重试5次,然后上报"需要三个事实以正确的关系存活下来。摘要器可能保留了所有三个事实——但丢失了绑定它们的条件结构。智能体随后把它们当作独立建议处理,而不是有序的决策树。

精确数值。 近似化是数字的默认损失模式。阈值、限制和计数特别脆弱:"每批最多100条记录"在操作上与"批次应合理大小"不同,但后者往往是摘要产生的结果。在受速率限制或配额敏感的系统中,这个问题会立即显现。

顺序和因果关系。 任务执行顺序被压平成无序的步骤集合。如果"步骤3需要步骤2先完成"在原始指令中是隐含的,那么这个依赖关系很少能在压缩后存活。智能体会在实践中以艰难的方式重新发现它。

工具输出归因。 当智能体查询数据库并获得特定结果集时,该结果会被记录在上下文中。摘要后,它变成"智能体检索了客户记录"。哪些记录?什么时候?查询是什么?这些元数据——将观察与来源连接起来的证据链——消失了。在下一轮中,智能体可能会捏造细节,不是通常意义上的幻觉,而是因为基准事实已从其上下文中被移除。

拒绝历史。 "用户因为延迟问题拒绝了方案A"是一个复合事实:拒绝、被拒绝的选项,以及原因。摘要器经常保留拒绝但丢弃原因,或保留选项名称但丢失它被拒绝的事实。任何一个错误都会把智能体引回同一个死胡同。

65%问题

对生产的影响是显著的。对企业AI智能体失败的分析发现,大约65%可归因于上下文漂移和记忆丢失——而不是原始上下文耗尽。团队用光上下文窗口的频率低于用光准确上下文窗口的频率。智能体还有token可用,但这些token包含了导致其偏离的降级信息。

在多轮任务基准测试中,智能体在单轮查询上达到约58%的成功率,在多轮任务上降至35%。添加朴素压缩有所改善——但引入了一个新的失败模式:智能体在完成目标之前遗忘了早期会话的需求。改进是真实的,但不完整。关键在于,失败模式从"上下文耗尽"转变为"上下文错误",后者更难检测,因为智能体会自信地继续运行。

单独的上下文丢失在长时程任务轨迹的结构化分析中,占被追踪智能体失败的3.33%。但这低估了实际贡献,因为上下文质量降级会以下游失败的形式出现——错误的API调用、约束违反、重复工作——这些被归因于模型错误,而不是记忆错误。

什么必须逐字保留

如果你正在构建或部署上下文压缩,某些类别的信息需要固定在摘要处理之外:

带有否定表达的显式约束。 任何包含"不"、"永远不要"、"不得"或"必须不"的陈述,都应被视为支撑性信息,直到被证明不再需要。保留一个过期约束的代价很低。丢弃一个活跃约束的代价是灾难性的。将这些内容固定到压缩永远不会触及的专用部分。

数值阈值和精确数量。 将每个精确数字——计数、限制、百分比、持续时间——提取到结构化参数存储中。不要让散文摘要接触这些值。规定"最多100条"的规则应以 max_records: 100 的形式保留,而不是可能被释义掉的自然语言。

目标陈述及其细化版本。 原始任务定义,以及会话过程中对它的每次修订,都应作为有序链条保留。不是摘要。不是合并成单一陈述。如果用户在第8轮修订了目标,在第21轮又修订了一次,你需要知道第21轮的版本取代了第8轮的——以及原因。

拒绝记录。 将拒绝存储为结构化元组:(被拒绝选项, 原因, 轮次编号)。这些内容小且保留成本低,能防止智能体在没有被拒绝原因的情况下重新提出已被否决的方案。

工具输出归因。 来自外部工具的每条观察都应携带来源标签:哪个工具、什么查询、什么时间戳。当该观察在后续被引用时,智能体应该能追溯到来源,而不是捏造信息。

评估你的压缩器是否失效

标准的压缩评估指标——ROUGE分数、BERTScore、嵌入相似度——无法告诉你实际需要知道的内容。一个摘要可以在所有这些指标上得高分,同时删除了防止生产事故的那一条约束。词汇重叠和语义相似度指标针对散文质量优化,而不是操作保真度。

基于探针的评估更可靠。压缩后,询问智能体需要它保留了关键信息才能回答的具体问题:

  • "最大批量大小是多少?"(测试数值保留)
  • "你可以删除这条记录吗?"(测试否定/约束保留)
  • "我们之前为什么拒绝了方案A?"(测试拒绝历史)
  • "你到目前为止编辑了哪些文件?"(测试工具输出归因)
  • "计划中的下一步是什么?"(测试顺序和因果关系)

如果智能体在压缩后正确回答了这些问题,说明你的压缩器保留了重要信息。如果它用捏造或降级的信息回答——即使其散文流畅自信——你就有了压缩失真问题。这些探针问题上的任务成功率,是比任何相似度指标更好的压缩质量代理指标。

往返测试是最严格的版本:以完整上下文运行多轮任务直至完成,然后以压缩后的上下文重播同一任务,测量压缩版本产生相同决策的频率。差异会精确揭示哪些信息丢失导致了哪些下游错误。

有效的生产模式

在生产中取得最佳效果的团队,已经不再将压缩视为对所有上下文均匀应用的单一操作。一致优于滚动摘要的模式是结构化混合:

稳定语义层保存目标陈述、约束、参数和拒绝历史。该部分永不被压缩。它在会话过程中会略微增长,但相对于总上下文来说很小,而其中的信息是不可替代的。

结构化长期记忆保存过去交互的压缩表示——但以原子事实(主语-关系-宾语三元组)而不是散文摘要的形式。原子事实保留了散文摘要会丢失的精度,并且在智能体需要恢复特定细节时可以独立搜索。

高保真短期缓冲区不压缩地保存最近几轮对话。最近的上下文始终与当前步骤最相关,对其进行压缩会引入最直接的操作错误风险。

结果是积极压缩仅适用于中间层——不太可能被直接引用但可能提供一般上下文的旧交互。所有关键内容要么被固定,要么被结构化。基于此架构构建的框架已证明能在token成本降低80-90%的同时,任务准确性得到可衡量的提升,因为它们压缩的是正确的内容,并保护其余部分。

你正在做出的设计选择

每次你对智能体上下文运行摘要处理时,你都在隐含地选择哪些信息值得保留。问题在于,通用LLM摘要器做出的隐含选择,并不是针对你的特定任务、你的特定约束,或你系统中的特定失败模式优化的。

明确这个选择——决定什么被固定、什么被结构化、什么被压缩——才是真正的设计工作。滚动摘要不是中性操作,它是一系列关于你的智能体被允许记住什么的编辑决策。问题是这些决策是经过设计还是默认产生的。

已经转向结构化上下文管理的团队不仅报告了更好的准确性,还报告了更好的可调试性:当智能体出错时,你可以查看结构化记忆,精确看到它拥有和缺失的信息。这比试图逆向工程七个周期前滚动摘要器扔掉了什么,是一个好得多的调试界面。

上下文压缩是必要的。不考虑哪些信息必须逐字保留的上下文压缩,是一个随每次会话轮次复利增加的风险。

Let's stay in touch and Follow me for more thoughts and updates