上下文压缩改变了你的模型真正看到的内容
当你的 API 成本飙升,有人建议“直接压缩上下文”时,这个方案听起来很简洁:输入更少的 token,支付更低的费用,获得同等的输出。LLMLingua 的基准测试显示,在数学推理上实现了 20 倍的压缩,而准确率仅下降了 1.5%。这听起来怎么会不好呢?
问题在于,这些基准测试衡量的是压缩后的上下文在干净、精心策划的测试集上的得分。它们没有衡量当你的智能体悄悄丢弃三轮对话前给出的约束、将代词解析到错误的实体,或者因为原始工具输出被总结掉而胡编乱造一个确切的文件路径时会发生什么。上下文压缩不仅仅是减少 token —— 它改变了模型实际看到的内容。而原始上下文与压缩版本之间的差距,正是你的系统注定会失败的地方。
Token 剪枝如何决定保留哪些内容
提示词压缩工具的主流家族 —— LLMLingua、LLMLingua-2 及其衍生产品 —— 使用一个小语言模型来判断哪些 token 携带信息。核心直觉是:如果一个小模型发现一个 token 在给定前文的情况下是完全可预测的,那么该 token 在信息上就是冗余的,可以丢弃。那些令小模型感到惊讶的 token(高自信息得分)则会被保留。
LLMLingua-1(2023 年)在提示词上运行 GPT-2 或 LLaMA-7B 等因果小语言模型,计算每个 token 的困惑度(perplexity)。其预算控制器为不同的提示词部分分配不同的压缩率 —— 指令获得 10–20% 的压缩,少样本示例获得 60–80%,而查询本身则进行最小程度的修剪。这种结构是合理的:并非所有提示词文本都具有同等的权重。
LLMLingua-2(2024 年)将问题重新定义为二元 token 分类,而不是困惑度排序。它使用双向编码器(3.55 亿参数的 XLM-RoBERTa-large),在为每个 token 评分时可以从两个方向看到完整的上下文 —— 修复了因果模型只能看到左侧上下文的根本缺陷。训练信号来自 GPT-4 生成的具有严格约束的压缩文本:仅删除词汇(不重写)、保持顺序、不添加新内容。结果是,该模型的速度比 LLMLingua-1 快 3–6 倍,内存占用更少,并且在同等压缩率下的问答基准测试中得分显著更高。
标题数据确实令人印象深刻。LLMLingua-2 在 5 倍压缩下实现了 GSM8K 数学推理 79% 的精确匹配(未压缩基准为 78.85%)。它在 14 倍压缩下保留了思维链推理,准确率下降不到 2%。对于具有多文档检索的 RAG 工作流,LongLLMLingua 变体增加了问题感知压缩 —— 通过与查询的联合困惑度对检索到的段落进行排序,而不是均匀压缩 —— 并报告在 4 倍压缩下,多文档问答任务的性能提升了 21 个点。
这些都是实实在在的收益。但基准测试衡量的是格式良好的检索文档下的干净、事实 性问答。它们没有暴露在生产环境中出现的失效模式。
基准测试无法捕捉的三种失效模式
丢失的指代链
Token 剪枝对共指关系(coreference)是不敏感的。当“身份验证服务”(the authentication service)这样的名词短语出现在早期,随后反复提及“它”(it)和“该服务”(the service)时,剪枝器会认为这些后来的代词在信息上是廉价的 —— 小模型可以在给定周围上下文的情况下高度自信地预测它们。代词被保留了。而作为先行词的名词短语(仅引入一次并在后来的处理中携带较低的熵质量)可能会被剪掉。
随后的下游模型会遇到“它无法连接”,却找不到可恢复的指代对象。在建立讨论实体的前期上下文的多智能体或多步骤流水线中,这种故障会默默产生看起来完全连贯的错误答案。模型不会标记不确定性 —— 它会将代词解析为幸存上下文中最为显著的任何实体。
丢失的约束引用
按照通用的文本训练的小语言模型的标准,系统提示词早期陈述的行为约束和权限具有较低的困惑度。“不要使用 库 X”、“用户处于免费计划中”、“输出必须是有效的 JSON” —— 这些模式在经过指令微调的数据中很常见,因此小语言模型发现它们是可预测的。在激进的压缩率(8 倍及以上)下,早期的约束声明是首批被剪枝的候选对象。
于是下游模型在没有约束的情况下运行。在面向客户的智能体中,这可能意味着向免费用户展示付费层级的功能。在智能体编码工作流中,这可能意味着导入被禁用的依赖项。输出是连贯且自信的,因为模型根本不知道规则的存在。
在上下文迭代压缩的多轮会话中,这尤其危险。原始系统提示词中存在的约束可能会在第一次压缩中幸存,但随着对话历史的增长,在随后的压缩中会被逐渐削减。
工具输出幻觉
当 Agent 的工具结果被总结而非逐字保留时,摘要模型会引入虚构的细节。文件路径变得模糊。行号发生偏移。错误代码被泛化。API 响应字段被合并或丢弃。
这与基准 QA 任务中的准确度损失有本质区别。QA 基准测试检查的是压缩后的上下文是否支持正确的逻辑事实。它并不测试精确值——字符串、标识符、结构化数据——是否在压缩后完整存续。研究评估长运行 Agent 的压缩策略时发现,过程产物追踪(artifact tracking,即了解修改了哪些文件、哪些测试通过了、发生了哪些错误)在所有压缩方法中始终是最薄弱的维度,无论使用抽取式剪枝(extractive pruning)还是抽象式摘要(abstractive summarization),得分仅为 2.19–2.45(满分 5.0)。
抽象式摘要(使用 LLM 重写和冷缩而非剪枝 Token)会让情况变得更糟。它能产生流畅的输出,但会用摘要模型的内部知识替换源事实。每一次压缩过程都会积累微小的扭曲,并在长对话环节中不断复合。
在发布前验证压缩效果
捕捉由压缩引起的性能下降需要一套验证方法论,用于测试标准 NLP 指标会忽略的维度:
约束保留测试(Constraint retention testing):在被测提示词中加入行为约束——关于输出格式、特性标志(feature flags)、权限的明确规则。压缩后,测量模型是否违反了给定的约束。这能直接捕捉到“约束丢失”的失败模式。
共指压力测试(Coreference stress tests):构建在早期引入重要实体并在后续通过代词引用的提示词。压缩后,探测模型是否能正确解析引用。排列测试(变换实体出现的位置)可以揭示位置敏感性。如果一个系统在“身份验证服务”出现在第一句时能给出正确答案,而在出现在第三句时给出错误答案,那么它表现出的是位置脆弱性而非鲁棒性。
逐字数值保留(Verbatim value preservation):对于 Agent 工作流,注入包含精确值的工具输出——文件路径、数字、API 响应、错误代码。压缩后,向模型查询这些精确值。与未压缩的基准进行对比。精确值上的任何偏差都信号化了该压缩方法不适用于该工作流。
影子部署(Shadow deployment):在完全切换之前,针对一部分真实生产查询并行运行压缩和未压缩的上下文。比较任务完成率,而不仅仅是输出质量得分。测量重新获取(re-fetch)的频率——Agent 有多频繁地需要重新读取文件或重新查询已查询过的工具,仅仅是因为相关信息被压缩掉了?
最后一个指标至关重要,因为有一个反直觉的发现:显而易见的优化目标——单次请求 Token 数——其实是错误的目标。对长运行编码 Agent 的研究发现,强制重新获取的激进压缩虽然降低了单次请求成本,但却增加了完成任务的总 Token 消耗。正确的衡量指标是“成功完成任务所消耗的 Token 数”。
设置压缩预算
压缩预算是对提示词各部分压缩程度的明确分配,并带有当压缩过头时触发的准确度约束。
按部分类型划分的一个实用起点:
- 包含约束或权限的系统提示词:最高 0–15% 压缩。这些是承重结构。逐字保留它们的成本远低于违反约束的成本。
- 少样本示例(Few-shot examples):通常 60–80% 压缩是安全的。示例携带的结构化信息(格式、推理模式)在激进剪枝后仍能存续。
- RAG 检索文档:对于格式良好的事实文档,进行 3–5 倍压缩。只有经过仔细验证后才可达到 8 倍。
- 已解决话题的对话历史:对于不包含未解析引用的轮次,进行 50–70% 压缩。对最近的 2–3 轮不做压缩。
- 包含精确值的工具输出:不要总结。如果需要减小体积,宁可截断整个工具响应也不要进行压缩——逐字保留重要的响应,丢弃不重要的。
动态预算分配优于静态预算。不顾查询复杂度而设置固定比例的预算,既会在简单查询上 造成浪费,又会在复杂查询上造成损害。关于预算感知推理的研究发现,根据查询复杂度进行动态分配可以在准确度损失小于 5% 的情况下,实现平均 68% 的 Token 削减;而静态低预算反而会增加 Token 使用量(当预算过于受限时,模型会为了规避风险而生成冗长的确定性推理)。
KV 缓存压缩:不同的层面
Token 剪枝作用于推理前的文本。KV 缓存压缩作用于注意力机制内部,在向前传递过程中剔除存储的键值对(key-value pairs)。它们通过不同的机制解决相关问题,失败模式也不同。
SnapKV (2024) 在不进行微调的情况下,为每个注意力头选择重要的键值位置。在 Qwen-7B 上实现 8 倍 KV 缓存压缩时,它实现了 3.6 倍的生成加速和 8.2 倍的内存占用降低,使得单张 80GB GPU 能够支持 380K Token 的上下文。ChunkKV 将此扩展到语义块而非单个 Token,从而保留了 Token 级剪枝会粉碎的语言结构。
KV 缓存压缩不会像抽象式摘要那样产生幻觉——它并没有重写文本。但它确实会产生位置和注意力模式的伪影。当注意力头看不到完整的 KV 历史时,它们会赋予幸存位置更高的权重,这会放大“迷失在中间(lost in the middle)”效应:幸存缓存开头和结尾附近的内容,相对于从中间被剔除的内容,会获得不成比例的过度关注。
何时避免压缩
鉴于这些失 效模式,最明确的指导原则是关于何时应该避开:
多步推理链:当中间步骤通过内容相互引用(如“如上文计算所示”、“使用第 2 步的结果”)时,压缩会破坏引用链。模型会丢失其推理思路。
安全与访问控制上下文:任何包含访问策略、权限检查或身份验证状态的提示词都应被视为包含约束,并应进行最小限度的压缩。权限的静默失效比事实错误更难检测。
会话初期:此时上下文仍然很小。运行压缩器的开销超过了节省 Token 带来的收益。只有当上下文真正接近限制或产生实质性成本时,才应应用压缩。
对逐字准确度敏感的工作流:任何涉及代码、结构化数据、错误消息、API 响应或数值的内容,采用逐字精简(即完整保留某些轮次,彻底丢弃其他轮次)的效果要好于对所有轮次进行部分压缩。
长程 Agent 的实用架构
在长期的 Agent 会话中,能够维持稳定的结构是将可压缩上下文与不可压缩上下文分开:
- 固定部分(从不压缩):系统提示词、活跃约束、当前任务说明
- 结构化账本(仅追加,从不总结):构件修改日志、带有精确值的工具调用结果、已做出的决定
- 可压缩历史:常规对话轮次、已解决的子任务、已完成的探索
- 检索到的上下文(基于问题感知的压缩):来自检索的文档和段落,相对于当前查询进行压缩
核心洞 察是,并非所有上下文在本质上都是相同的。约束和精确值是起“承重”作用的,而对话历史则不然。一个统一处理这些内容的压缩系统,必然会在承重部分失效,而仅能正确处理其余部分。
对前沿模型(GPT-4.1、Claude Opus、Gemini 2.5)的研究发现,编程 Agent 在运行超过 35 分钟后,准确率会出现可衡量的下降——这并非因为上下文窗口已耗尽,而是因为迭代压缩中产生的复合噪声,以及随着相关信息移向不断增长的窗口中部而积累的“上下文腐化”。将承重内容固定在压缩预算之外的结构化记忆,正是防止这种性能下降的关键。
压缩能为你带来真实的成本和延迟改进。但这些收益源于压缩了正确的东西。失效模式是可预测的,验证方法是可行的,预算分配框架也并不复杂——它只需要你在开始修剪之前,了解提示词中哪些部分是起承重作用的。
