1. 大模型上下文压缩到底在解决什么问题
第一次接触“上下文压缩”这个概念,很多人会误以为是把用户的输入做摘要,或者把长文档切块丢进向量库。实际上,大模型语境下的上下文压缩,核心要解决的是一个非常具体的工程矛盾:模型能记住的内容长度是有限的,但实际任务需要处理的信息量往往远超这个限制。
你可以把大模型的上下文窗口想象成一张固定大小的办公桌。模型每次处理请求时,所有相关信息都必须摊在这张桌子上——系统提示词、历史对话、检索到的文档、工具调用的返回结果、当前用户输入,全部算在内。桌子就这么大,东西放多了要么放不下,要么把重要的东西挤到地上。上下文压缩要做的,就是在不丢失关键信息的前提下,让这张桌子能容纳更多有效内容。
这个问题在Agent场景下尤其突出。一个典型的Agent任务可能包含十几轮工具调用,每轮调用返回的结果少则几百token,多则几千token。如果不做任何处理,几轮下来上下文窗口就被撑满了。我实测过一个代码分析类的Agent,连续调用五次文件读取工具后,上下文就消耗了将近六万token,而这还只是任务的前半段。
注意:上下文窗口的计量单位是token,不是字符。中文大约1个token对应1.5到2个汉字,英文大约1个token对应4个字符。估算时不要用字符数直接换算,否则会严重低估实际消耗。
上下文压缩的目标不是“让上下文变短”这么简单,它要同时满足三个条件:第一,压缩后的内容仍然能支撑模型做出正确决策;第二,压缩过程本身不能消耗过多资源;第三,压缩后的信息要能被模型正确理解,不能因为压缩导致语义断裂。这三个条件互相制约,这也是为什么上下文压缩至今没有出现一个“万能方案”的原因。
从工程视角看,上下文压缩属于“上下文工程”的一个子领域。上下文工程关注的是如何组织、管理和优化模型接收到的全部信息,而压缩只是其中一种手段。与之并列的还有上下文检索、上下文排序、上下文缓存等策略。理解这个定位很重要,因为很多人在遇到上下文溢出问题时,第一反应就是“压缩”,但实际上有时候更好的做法是“检索”——只把真正相关的信息放进上下文,而不是把所有信息压缩后塞进去。
2. 上下文压缩的主流技术路线拆解
2.1 基于摘要的压缩:让模型自己“记笔记”
摘要压缩是最直观的思路:把一段较长的上下文交给模型,让它生成一个更短的版本,然后用这个短版本替代原文。这种做法在对话历史管理中用得最多。比如一个客服Agent,前二十轮对话的详细内容可能不再需要逐字保留,只需要保留“用户反馈了什么问题、已经尝试了哪些方案、当前状态是什么”这几个关键点。
具体实现时,通常会在上下文使用量达到某个阈值(比如窗口容量的70%)时触发摘要操作。触发后,把最早的一部分对话内容提取出来,调用模型生成摘要,然后用摘要替换掉原始对话。这样既释放了空间,又保留了核心信息。
但摘要压缩有一个容易被忽视的坑:摘要是有损的,而且损失什么信息是不可控的。模型在生成摘要时,可能会丢掉它认为不重要但后续任务恰好需要的信息。我遇到过一种情况:Agent在摘要时把用户提到的“不要使用某个特定库”这个约束条件丢掉了,导致后续生成的代码引入了这个库,最终返工。
实操心得:做摘要压缩时,不要只让模型“总结一下”,而是给它一个明确的结构化模板,比如“保留以下信息:用户目标、已确认的约束条件、已尝试的方案及结果、待解决的问题”。这样能大幅降低关键信息丢失的概率。
2.2 基于截断的压缩:简单但需要策略
截断是最简单的压缩方式——直接丢掉一部分上下文。但“丢哪部分”是有讲究的。最常见的策略是保留系统提示词和最近几轮对话,丢掉中间的历史内容。这种做法实现成本极低,不需要额外调用模型,但风险也很明显:如果被丢掉的部分包含关键信息,模型就会“失忆”。
改进版的截断策略会做优先级排序。比如把上下文分成几个层级:系统提示词永远保留,当前任务相关的工具返回结果优先保留,历史对话按时间倒序保留,检索到的文档按相关性得分保留。当需要截断时,从优先级最低的部分开始丢。
这种策略在工程上很实用,因为它不需要额外的模型调用,延迟几乎为零。但它的效果高度依赖于优先级排序的准确性。如果排序逻辑写得不好,可能会丢掉重要信息而保留了无关内容。
2.3 基于向量检索的压缩:只取最相关的
向量检索的思路是:不把全部上下文都塞进窗口,而是把历史信息存入向量数据库,每次只检索出与当前问题最相关的若干条记录放入上下文。这种做法本质上不是“压缩”已有上下文,而是“按需加载”上下文。
在Agent场景中,这种方案特别适合处理工具调用返回的大量数据。比如一个数据分析Agent,每次查询数据库返回的结果可能有几千行,但当前步骤只需要其中某几列的数据。与其把整个结果集放进上下文,不如把它存入外部存储,只在上下文中保留一个引用标识,需要时再检索。
这种方案的关键在于检索质量。如果检索不到真正相关的内容,模型就会缺少必要信息。所以通常需要配合较好的embedding模型和检索策略,比如混合检索(关键词加语义)、重排序等。
2.4 基于模型原生能力的压缩:利用注意力机制的特性
一些较新的模型架构在设计时就考虑了长上下文的处理效率。比如通过稀疏注意力、滑动窗口注意力等机制,让模型在处理长序列时自动“关注”重要部分,忽略次要部分。这种压缩是模型内部完成的,对开发者透明。
但从工程角度看,不能完全依赖模型的原生能力。因为模型内部的注意力压缩是不可控的,你无法精确知道它关注了什么、忽略了多少。在实际项目中,通常还是需要在应用层做显式的上下文管理,模型原生能力只是多了一层保障。
3. Agent场景下的上下文压缩实操方案
3.1 分层上下文管理架构
在Agent项目中,我一般采用分层的方式来管理上下文。整个上下文分成四个层级:
- 固定层:系统提示词、工具定义、输出格式约束。这部分内容不变,永远保留。
- 任务层:当前任务的描述、目标、约束条件。任务不变时保留,任务切换时更新。
- 工作层:最近几轮的工具调用记录和模型推理过程。这是变化最频繁的部分,也是压缩的主要对象。
- 归档层:较早的历史信息,经过摘要或索引后存储,按需检索。
压缩主要发生在工作层向归档层转移的过程中。当工作层的token量超过预设阈值时,把最早的一部分内容做摘要后移入归档层,同时从工作层中移除原文。
这种分层架构的好处是职责清晰:固定层和任务层几乎不参与压缩,保证了核心指令的稳定性;工作层和归档层之间的流动有明确的触发条件和处理流程,便于调试和优化。
3.2 压缩触发的阈值计算
阈值设置直接影响压缩效果和任务质量。设得太高,上下文经常溢出;设得太低,频繁压缩导致信息损失累积。
我的经验值是:当上下文使用量达到窗口容量的65%到75%时触发压缩。留出25%到35%的余量,是为了给后续的模型输出和工具返回结果留空间。如果压缩后紧接着就有大量新信息涌入,余量不够就会再次触发压缩,形成“压缩-溢出-再压缩”的循环。
具体计算时,需要先估算当前上下文的token量。可以用模型对应的tokenizer做精确计算,也可以用近似估算。对于中文内容,一个粗略的估算是:汉字数乘以1.5,加上英文单词数乘以1.3,再加上标点符号和特殊字符的数量。这个估算不够精确,但用于触发判断足够了。
注意:不同模型的tokenizer不一样,同一个文本在不同模型下的token数可能差20%以上。如果项目需要切换模型,阈值要重新校准。
3.3 摘要压缩的提示词设计
摘要压缩的效果很大程度上取决于提示词的质量。一个经过多次迭代的摘要提示词模板大致是这样的:
你是一个上下文压缩助手。请将以下对话历史压缩为结构化摘要。 压缩要求: 1. 保留用户的核心目标和意图 2. 保留所有已确认的约束条件和限制 3. 保留已尝试的方案及其结果(成功或失败) 4. 保留当前待解决的问题 5. 保留涉及的具体参数、文件名、变量名等技术细节 6. 删除寒暄、重复确认、无关的中间推理过程 输出格式: - 用户目标:[一句话描述] - 约束条件:[列表] - 已尝试方案:[方案名 + 结果] - 待解决问题:[列表] - 关键技术细节:[列表] 对话历史: {context}这个模板的关键在于:它明确告诉模型“保留什么”和“删除什么”,而不是让模型自由发挥。实测下来,使用结构化模板后,关键信息丢失率从大约15%降到了3%以下。
3.4 工具返回结果的压缩策略
Agent场景中,工具返回结果往往是上下文膨胀的主要来源。一个搜索工具可能返回十条结果,每条包含标题、摘要、链接;一个代码分析工具可能返回整个文件的AST结构。这些内容全部放进上下文,很快就会撑满窗口。
我的处理策略是:工具返回结果先经过一层“过滤-提取-格式化”处理,再放入上下文。具体来说:
- 过滤:去掉明显无关的结果,比如搜索工具返回的低相关性条目。
- 提取:只保留当前步骤需要的字段。比如代码分析只需要函数名和参数列表,不需要完整的函数体。
- 格式化:用紧凑的格式呈现,减少冗余字符。比如用表格代替嵌套的JSON结构。
经过这三步处理,工具返回结果的token量通常能压缩到原来的20%到40%,而且信息密度更高,模型理解起来反而更准确。
4. 上下文压缩的常见问题与排查技巧
4.1 压缩后模型“失忆”怎么办
这是最常见的问题。压缩后模型忘记了之前确认过的关键信息,导致重复提问或做出错误决策。
排查思路:先检查摘要提示词是否覆盖了所有关键信息类型。如果摘要模板里没有要求保留“约束条件”,模型很可能就不会保留。其次检查压缩触发时机,如果压缩发生在关键信息刚产生不久,可能摘要还没充分捕捉到就触发了。
解决方法是:在摘要生成后,增加一步“关键信息校验”。把摘要和原始上下文一起交给模型,让它检查“摘要是否遗漏了任何影响任务执行的信息”。如果发现遗漏,就补充进去。这一步会增加一次模型调用,但对于关键任务来说值得。
4.2 压缩本身消耗太多token怎么办
摘要压缩需要调用模型,而模型调用本身也消耗token。如果压缩频率太高,压缩消耗的token可能比节省的还多。
优化方向有两个:一是降低压缩频率,把阈值调高一些,让每次压缩处理更多的内容;二是用更小的模型来做摘要。摘要任务对模型能力的要求不高,用一个小模型(比如7B参数级别)就能做得不错,成本远低于用大模型做摘要。
我实测过用不同规模模型做摘要的效果:在结构化模板的约束下,7B模型和70B模型的摘要质量差距不到5%,但成本差了将近二十倍。所以摘要这种“体力活”,没必要用大模型。
4.3 多轮压缩导致信息逐层丢失
如果上下文经历了多次压缩,每次压缩都损失一点信息,累积下来可能损失严重。这就像反复复印同一份文件,每复印一次清晰度就下降一点。
应对策略是:尽量从原始内容生成摘要,而不是从摘要生成摘要。也就是说,归档层保留原始内容(或原始内容的索引),每次需要压缩时,从原始内容重新生成摘要,而不是在已有摘要的基础上再压缩。这样虽然存储成本高一些,但信息损失是单层的,不会累积。
如果存储成本不允许保留全部原始内容,至少保留最近两层的原始内容,更早的可以只保留摘要。
4.4 压缩后上下文语义不连贯
有时候压缩后的上下文虽然保留了关键信息,但读起来支离破碎,模型理解起来反而更费劲。这通常是因为摘要生成时没有考虑上下文的连贯性。
改进方法是:在摘要提示词中增加“保持叙述连贯性”的要求,让模型用完整的句子而不是碎片化的关键词来组织摘要。另外,可以在摘要中保留一些过渡性的语句,比如“在确认了X之后,接下来尝试了Y”,这样模型能更好地理解信息之间的逻辑关系。
4.5 常见问题速查表
| 问题现象 | 可能原因 | 排查方向 | 解决措施 |
|---|---|---|---|
| 压缩后模型重复提问 | 摘要丢失了已确认信息 | 检查摘要模板是否覆盖该信息类型 | 补充模板字段,增加校验步骤 |
| 压缩频率过高 | 阈值设置过低 | 统计压缩触发间隔 | 调高阈值至70%左右 |
| 压缩成本超过节省 | 摘要模型太大 | 对比压缩前后token消耗 | 换用小模型做摘要 |
| 多轮压缩后信息严重缺失 | 摘要的摘要导致累积损失 | 检查归档层是否保留原文 | 从原文重新生成摘要 |
| 压缩后模型理解困难 | 摘要碎片化,缺乏连贯性 | 阅读摘要文本是否通顺 | 要求模型用完整句子输出 |
5. 上下文压缩的边界与取舍
5.1 什么情况下不该压缩
上下文压缩不是万能的。有些情况下,压缩带来的信息损失可能超过它节省的空间价值。
比如,当任务本身高度依赖精确的原文信息时——法律文书分析、代码审查、精确的数据核对——压缩可能导致关键细节丢失,这时候更好的策略是分块处理,把长文档切成多个片段,每次只处理一个片段,而不是压缩后一次性处理。
再比如,当上下文窗口本身足够大时(比如128K甚至更大),对于大多数任务来说,直接放入完整上下文可能比压缩更简单可靠。压缩应该是在窗口不够用时的“最后手段”,而不是默认操作。
5.2 压缩与检索的配合
在实际项目中,压缩和检索往往是配合使用的。检索负责从外部知识库中找出相关内容放入上下文,压缩负责管理上下文内部的空间分配。两者结合,才能实现“在有限窗口内处理无限信息”的目标。
一个典型的配合模式是:先用检索找出与当前问题最相关的若干文档片段,放入上下文;当上下文接近满时,对较早的文档片段做摘要压缩;如果摘要后仍然不够,就把摘要移入归档层,需要时再检索回来。
这种模式下,检索和压缩形成互补:检索解决“信息从哪来”的问题,压缩解决“信息放不下”的问题。
5.3 压缩策略的评估指标
怎么判断一个压缩策略好不好?我通常看三个指标:
- 信息保留率:压缩后,关键信息(任务目标、约束条件、技术细节)的保留比例。可以通过人工标注或模型校验来评估。
- 压缩比:压缩后token量与压缩前token量的比值。比值越低,压缩效果越好,但信息损失风险也越大。
- 任务成功率:使用压缩策略后,Agent任务的成功率与不压缩时的对比。这是最终指标,前面两个指标都是为它服务的。
在实际调优时,我会先固定压缩比(比如目标压缩到30%),然后优化信息保留率;等保留率稳定后,再逐步降低压缩比,观察任务成功率的变化。找到那个“压缩比最低且任务成功率不下降”的平衡点。
实操心得:不要追求极致的压缩比。把压缩比从30%降到20%,可能只多节省了10%的空间,但信息保留率可能从95%降到80%,任务成功率下降明显。压缩的收益是线性的,但信息损失的代价可能是指数级的。
6. 从工程视角看上下文压缩的未来演进
6.1 模型原生压缩能力的增强
现在已经有模型开始内置上下文压缩能力。比如通过可学习的压缩token,把长序列压缩成少量向量表示,模型在处理时直接使用这些压缩表示。这种方式对开发者透明,不需要额外的压缩逻辑。
但这种原生压缩目前还不太可控,你无法精确知道模型压缩了什么、保留了什么。在需要精确控制的场景下,还是得靠应用层的显式压缩。
6.2 压缩与推理的融合
另一个趋势是把压缩和推理过程融合起来。不是先压缩再推理,而是在推理过程中动态决定哪些信息需要保留、哪些可以丢弃。这需要模型具备“元认知”能力——知道自己需要什么信息,不需要什么信息。
目前这种能力还比较初级,但已经有一些研究在探索。比如让模型在推理时输出“我需要记住X”或“Y可以忘记了”这样的标记,然后由外部系统根据标记来管理上下文。
6.3 对开发者的实际影响
不管技术怎么演进,有一点是确定的:上下文管理会越来越成为Agent开发的核心能力。模型能力越强,能处理的任务越复杂,对上下文管理的要求就越高。压缩只是其中一环,完整的上下文工程还包括检索、排序、缓存、隔离等多个方面。
对于正在做Agent项目的开发者来说,我的建议是:不要等到上下文溢出了才去想压缩方案,而是在架构设计阶段就把上下文管理作为一个独立模块来规划。定义好上下文的生命周期、压缩触发条件、信息保留优先级,这样后续的调优才有章可循。
我在实际项目中的体会是,上下文压缩做得好的Agent,和做得不好的Agent,任务成功率差距可能达到30%以上。这个差距不是模型能力带来的,而是工程能力带来的。模型选型固然重要,但上下文管理才是决定Agent能不能真正跑通复杂任务的关键因素。