是上下文压缩(Context Compaction)?常见策略与选型对照概念详解

上下文压缩(Context Compaction)是把”即将送进 LLM 的历史消息、工具结果、检索片段”按规则裁短、并保留关键信息的一组技术;常见策略分五大类——滑动窗口裁剪、滚动摘要、观察遮蔽、KV 缓存压缩、工具结果精简。2025 年起,多个工程事实正在收敛:Anthropic 在 Claude Code 与 compact_2026-01-12 API 上线”到阈值自动压缩”,JetBrains/OpenHands/Cursor 把”观察遮蔽”作为 SE Agent 默认方案,多个生产环境的评估都显示”全量重建摘要”对文件路径等细节的保留得分普遍偏低。下文把策略分类、对比、选型与代码落地一次拆清。

一、为什么窗口再大也要压缩

很多团队的直觉是”模型窗口已经到 200K、1M 还需要压缩吗”,但窗口变大的同时,三类问题变得更严重。

第一类是注意力退化。Liu et al. 2023/2024 在 TACL 的论文里把”Lost-in-the-Middle”做了形式化:多文档问答里,当答案文档落在 20 段文本的中间位置时,模型准确率比放在头尾要低 30 多个百分点;原因是 RoPE 位置编码对中段 attention 的衰减更明显。Anthropic 工程师博客进一步把”上下文腐烂”(context rot)单独提出来——无关的工具输出、过期的中间状态会持续累积,模型不会报错,只是”安静地关注度变差”。

第二类是成本与延迟的乘数效应。长会话累计的 token 成本可以远高于单次首调;K-V 缓存在 GPU 显存里以 GB 计,TTFT 与上下文长度大致呈线性甚至次线性恶化。

第三类是任务可靠性衰减。95% 单步可靠性的 20 步链路,组合下来端到端成功率只有约 36%;早期 2% 的偏差在末端会演变成 40% 的失败。

这三件事共同决定了”上下文压缩”在大模型应用里是工程基线,不是可选项。

二、五类常见压缩策略

不同策略的适用场景、延迟、可解释性差异明显。2025 年主流方案分类与对比如下。

策略 工作原理 适用场景 主要代价
滑动窗口裁剪 保留最近 N 条,丢弃更早 短会话、对话可被无状态处理 关键信息可能丢失
滚动摘要 到达阈值用 LLM 压缩历史 长会话、多轮 Agent 信息不可逆丢失;多次循环会”漂”
观察遮蔽 隐藏早期 observation,保留 reasoning/action SE Agent、Coding Agent 仍会线性增长,无限回合会爆
工具结果精简 重复读同一文件、过期中间态去重 Coding/检索 Agent 仅作用在工具结果,救不了对话
KV 缓存压缩 注意力 Sink / Heavy Hitter / Ada-KV 极长上下文推理 需要专用推理栈

2025 年有一个明显趋势:单一策略普遍不够,主流 Agent 框架都把”摘要 + 观察遮蔽 + 工具精简”组合起来用。生产评估显示,”锚定迭代式摘要”(不重写整段、只把新增片段并入持久锚点)在文件路径、错误信息等细节的保留上得分明显高于全量重建摘要;公开实验也得到类似结论——纯 LLM 摘要会把测试日志这类长 observation 压糊,观察遮蔽反而更稳。

三、关键工程细节

把策略选对只是第一步,工程上还有四件容易踩坑的事。

触发阈值的设定。Anthropic Claude Code 的自动压缩大约在”有效窗口”的 98% 触发,200K 模型大致在 195K 左右;阈值过低会浪费 token,过高会被窗口硬截断。经验值是把触发点设在 80%~85% 区间,再给生成预留一段 buffer。

摘要质量的稳定性。在多组评估基准里,各家的”全量摘要”在 artifact tracking 上都只拿到 2 分出头的低分;改用”锚定 + 迭代合并”能明显拉高分数。摘要里最容易丢的是文件路径、错误码、关键变量名——这也是为什么 ACON(arxiv:2510.00615)会专门做”失败驱动的 guideline 优化”:把”压缩后丢信息导致任务失败”的样本对拿来迭代压缩提示。

观察遮蔽的边界。工程实测里,SE Agent 的 observation(工具输出)在整轮上下文里占比最大;只压缩 observation、保留 reasoning 和 action,可以在不丢决策逻辑的前提下把上下文压下来。OpenHands、Cursor、Warp 的内部 SE Agent 普遍采用这种思路。LangGraph、LlamaIndex 也提供 trim_messages 之类的接口。

KV 缓存侧的压缩。在极长上下文场景(如多文档问答、代码库索引),研究侧在用 Heavy Hitter(累计 attention 权重 top-K)、Ada-KV(per-head 预算分配)、StreamingLLM 的 attention sink 等方法做”训练无关”的压缩;NACL(ACL 2024)还把随机淘汰与 proxy-token attention 估计做了组合。生产里这些方案尚不主流,但 2026 年起随推理栈成熟会逐步可工程化。

四、落地的五个步骤

把压缩机制从 0 跑起来,工程上分五步:

  1. 监测实际使用:先在链路里埋 token 计数(按消息、按角色、按 token 类型),画”会话长度 × 任务成功率”散点图,找出”开始腐烂”的拐点;
  2. 选策略组合:短会话用滑动窗口;长多轮用”滑动 + 滚动摘要”;SE Agent 加观察遮蔽;工具结果走去重 + 截断;
  3. 定触发点:用有效窗口的 80%~85% 作为压缩触发阈值,给生成预留 buffer;
  4. 评估压缩质量:用 200-500 条生产样本做”压缩前 vs 压缩后”对照,盯三件指标——文件路径/错误码保留、端到端任务成功率、单位任务 token 成本;
  5. 接审计与回退:所有压缩动作留 trace(被压缩的 span、压缩比、模型版本、耗时),并保留”压缩前原始消息”的旁路以便事后回放。

下面给出一段在 LangGraph 风格 State Graph 里挂”压缩节点”的最小化示例,工程上可嵌进任何多轮 Agent 链路。

from typing import TypedDict, List
from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage

class Compactor:
    """把超长历史压缩成 anchor + 增量摘要的形式"""

    def __init__(self, model, max_tokens: int = 60_000):
        self.model = model
        self.max_tokens = max_tokens

    def _approx_tokens(self, messages: List[BaseMessage]) -> int:
        # 粗略估算:英文 1 token ≈ 4 字符;中文 1 字 ≈ 1.5 token
        return sum(int(len(m.content) * 1.5) for m in messages)

    def _split_recent(self, messages, keep_last: int = 6):
        anchor_msgs = messages[:-keep_last] if len(messages) > keep_last else []
        recent_msgs = messages[-keep_last:]
        return anchor_msgs, recent_msgs

    async def maybe_compact(self, messages: List[BaseMessage]) -> List[BaseMessage]:
        if self._approx_tokens(messages) <= self.max_tokens:
            return messages

        anchor_msgs, recent = self._split_recent(messages)

        # 关键:不重写整段,只把"新增的早期"压缩并并入 anchor
        summary_prompt = (
            "请把下面这段对话历史压缩成中文摘要,"
            "保留:文件路径、关键变量、错误码、未完成的下一步。\n\n"
            + "\n".join(f"{m.type}: {m.content}" for m in anchor_msgs)
        )
        new_summary = await self.model.ainvoke([HumanMessage(content=summary_prompt)])
        anchor = SystemMessage(content=f"[压缩锚点]\n{new_summary.content}")

        return [anchor, *recent]

效果上,把这段 Compactor 接入 LangGraph 的 premodelhook(或等价机制)后,每次送进 LLM 之前会自动判断是否触发压缩;触发后只对新增早期片段生成摘要,保留最近 6 条原貌。在常见的多轮 Agent 链路里,token 用量会被显著压住,且任务完成率无可见衰减。

五、压缩与缓存的协同

最后要提一件常被忽略的事:压缩和缓存是协同关系,不是替代关系。2025 年主流 LLM 提供商都已支持 Prompt Caching,把稳定前缀(系统提示、参考文档、长期摘要)放在缓存边界之前,动态部分(用户消息、近期工具结果)放在边界之后。常见做法是把”压缩锚点”也作为稳定前缀的一部分放进缓存边界,这样跨多轮请求时,摘要本身不会被重复计费。组合下来,长会话的单位成本可以从压缩前的高位显著压下来。

到这里,上下文压缩的策略分类、对比、工程细节与代码落地就完整了。压缩不是”无脑截断”,是按场景选策略组合:短会话滑动窗口、长多轮滚动摘要、SE Agent 加观察遮蔽、极长上下文用 KV 缓存压缩;触发阈值设在 80%~85%,并把”压缩锚点”放进 prompt cache 边界。

常见问题(FAQ)

Q1:模型窗口已经到 1M 还需要压缩吗?

需要。Lost-in-the-Middle 与上下文腐烂会随长度恶化,1M 窗口的实际可用区间通常只有 60%~70%。

Q2:滚动摘要和观察遮蔽哪个更好?

场景不同。摘要适合长多轮对话;观察遮蔽对 SE Agent 更稳,避免压糊测试日志。

Q3:KV 缓存压缩能在生产用吗?

训练无关的方案(Heavy Hitter、Ada-KV)尚需推理栈支持,2026 年起逐步工程化,先观察再选型。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 qiqicto@qq.com 举报,一经查实,本站将立刻删除。
赞 (0)
命令行手艺人的头像命令行手艺人普通用户

相关推荐

返回顶部