长程 agent 迟早会撞上上下文墙。业界的常规做法是到了墙边就做一次摘要、然后在新窗口里继续——但摘要本身从来没有被训练过。CompactionRL 把摘要 token 也塞进 RL 的损失里,和执行动作共享同一个任务奖励。
一句话:当上下文预算耗尽时生成的那段摘要,不是预处理,而是一个决定后续所有动作成败的策略行为——所以它必须被 RL 训练,而不是被当作外部工具调用。
SWE-bench、Terminal-Bench 这类任务的形态是:反复"推理 → 调工具 → 看环境反馈 → 改计划"。ReAct 风格的做法是把完整交互历史一路拼进 prompt,于是上下文长度随轨迹单调增长。工具输出、中间推理、报错信息、半成品补丁堆在一起,很容易在任务完成之前就把窗口撑爆。
把窗口做长不是答案:一方面成本高,另一方面长序列上的有效信息利用率本身会退化(论文引了 LongBench / RULER 那条线)。所以长程 agent 的 RL 训练必须在固定上下文预算下跑通。
上下文压缩(context compaction)是自然的解法:历史快撑满时,把之前的交互摘要成一个短状态,agent 从"摘要 + 一小段最近历史"继续。但此前的用法基本都是推理期启发式或外部记忆操作。论文指出,在 RL 训练里压缩的地位要更根本:
一旦摘要替换了原始历史,它就决定了后续所有动作能看到什么信息。任务成败不只取决于执行策略,也取决于压缩策略。既然是策略,就该被优化。
论文先用一个干净的对照说服你"摘要很关键":执行 agent 固定为 GLM-4.7-Flash,只替换负责写摘要的模型。
| 摘要模型(执行模型固定为 GLM-4.7-Flash) | SWE-Verified Pass@1 | 平均压缩次数 / trace |
|---|---|---|
| Qwen3.5-27B | 55.5 | 1.010 |
| GLM-4.7-Flash(自己给自己写摘要) | 50.5 | 1.075 |
| Qwen3-30B-A3B | 49.0 | 1.126 |
6.5 个点的差距,全部来自"谁来写这段摘要"。而且好的摘要还顺带减少了压缩触发次数——信息保留得好,后续就不需要反复重新探索、把窗口重新撑爆。一份丢掉了关键文件路径、报错信息、失败命令或半成品补丁的摘要,会让后面每一个动作都失效,哪怕执行策略本身很强。
结论很直接:压缩是一个性能关键的决策过程,不是被动的预处理步骤。那就把它一起训。
把交互历史记为 h_t = (s, u, z_1, ..., z_t),其中 s 是 system prompt,u 是用户指令,z_i = (a_i, o_i) 是"助手响应 + 环境观测"对。z_i 被当作原子步——工具调用和它的反馈绝不会被压缩切开。
设 C 为上下文预算,压缩在剩余预算低于阈值 T_comp 时触发:
触发后,把一段固定的摘要指令 q_sum 追加到当前历史后,从当前策略里采样一段摘要:
q_sum 要求模型保留继续任务所需的信息:原始目标、已完成的动作、重要观测、未解决的错误、当前状态、以及合理的下一步。然后重建上下文:
即 system prompt + 含摘要的固定续写模板 + 最近 k 步原样保留(塞不下时再减小 k)。这个设计的分工很清楚:长程信息靠摘要压缩,近端环境状态保持逐字精确——因为 agent 下一步动作往往直接依赖上一条工具输出的确切内容。
一条带压缩的完整 rollout 被自然切成一串生成 token 段:
关键点:摘要器不是外部模块,摘要 token 由同一个可训练策略采样,并被计入 RL 目标。每条 rollout 拿到一个由任务正确性决定的终局奖励 R(τ),这个奖励分配给该 rollout 的所有可训练段。
论文不引入单独的"摘要质量奖励"。理由:人工设计的摘要指标(覆盖率、压缩比、ROUGE 之类)未必反映"哪些细节对解题真正有用"。与其猜,不如让终局任务奖励直接告诉摘要器什么该留。
GRPO 这类组相对方法的做法是:对每个 prompt 采一组 G 条完整 rollout,用组内奖励归一化来估计 advantage。压缩把这个假设打碎了:
Σ_g K_g 个段(K_g 是第 g 条的段数)。由于同一 rollout 的所有段共享同一个终局奖励,压缩次数多的 rollout 会在组统计里被重复计入更多次,从而获得不成比例的权重。所以 CompactionRL 选择 PPO + 显式 critic:基于价值函数的 advantage 估计不依赖固定大小的奖励组,天然支持数量可变的压缩段——甚至支持一个 prompt 只采一条 rollout(实验里 group size 就是 1)。
这和近期 VC-PPO、VAPO 的结论是一条线上的:critic-free 方法在可验证奖励的短任务上很好用,但长程信用分配上 critic 依然有不可替代的价值。CompactionRL 给出了一个更强的理由——在压缩设定下,组相对基线不是"效果差一点",而是结构上无法构造。
轨迹长度和摘要长度差异极大(执行段可能几千 token,摘要段两千出头)。论文用 token 级损失而非序列级损失。设 M 为一个 batch 中所有被优化的助手 token 位置:
归一化分母是 token 数而不是样本数。如果按段平均,压缩事件更多的 rollout 就会贡献更大的梯度权重——哪怕两条 rollout 拿的是同一个任务奖励。token 级归一化消除了这个 segment-count 偏置,让每个可训练 token 权重相等。
这是全文最精巧的一处。每个段被独立优化,意味着朴素的段级 GAE 会把共享的终局奖励放在每一段的末尾。对早期段来说,任务结果看起来比实际"近"得多——于是那些发生在任务完成很久之前的动作和摘要被过度加分。
段 σ_s 内的局部 GAE 照常算:
然后令 N_{>s} = Σ_{j>s} n_j 为该 rollout 中段 σ_s 之后生成的可训练 token 总数,施加一个轨迹位置修正:
为什么这样就对了?如果终局奖励出现在每个独立优化段的最后一个 token 上,那么修正后 token (s,i) 处的奖励项折扣是
——这正好等于它在拼接后的完整压缩轨迹里到终局的真实距离。一行乘法,把被压缩切断的时序信用重新接了起来。
slime 异步 RL 框架。λ = 1 − 1/(αl),α = 1.5(l 为响应长度);单条助手响应 ≤ 10,240 token;剩余预算 < 10,240 时触发压缩;每条 rollout 最多 3 次压缩。Single (×1):关闭压缩,只有一个 Peak Length 窗口的预算。
Compacted (×4):允许最多 3 次压缩,有效预算 = 4 × Peak Length,但峰值工作上下文不变。
这正是论文要卖的点:不加长最大窗口,只延长可用视界。
| 模型 | 峰值长度 | SWE-V ×1 | SWE-V ×4 | TB2.0 ×1 | TB2.0 ×4 |
|---|---|---|---|---|---|
| 公开报告 / 参考基线(脚手架可能不同,仅供参考) | |||||
| GPT-5 mini (2025-08-07) | 400k | 72.0 | – | 31.9 | – |
| Qwen3-Coder-480B-A35B-Instruct | 256k | 66.5 | – | 23.9 | – |
| gpt-oss-120b | 128k | 62.0 | – | 18.7 | – |
| Qwen3-Coder-30B-A3B-Instruct | 256k | 51.9 | – | 14.6 | – |
| Qwen3.5-35B-A3B | 64k | – | 58.0 | – | 27.0 |
| Terminus-KIRA 脚手架 · 30B 规模 | |||||
| GLM-4.7-Flash (30B-A3B) | 64k | 47.5 | 50.5 | 14.6 | 13.4 |
| + RL(不含压缩) | 64k | 50.0 | 48.0 | 16.9 | 12.4 |
| + CompactionRL | 64k | 43.7 | 56.0 | 16.9 | 20.2 |
| Terminus-KIRA 脚手架 · 106B 规模 | |||||
| GLM-4.5-Air (106B-A30B) | 80k | 57.8 | 59.8 | 17.9 | 21.4 |
| + RL(不含压缩) | 80k | 58.3 | 62.5 | 20.2 | 23.6 |
| + CompactionRL | 80k | 57.3 | 66.8 | 21.4 | 24.5 |
Pass@1 (%)。注:本文所有结果(含 Qwen3.5-35B-A3B)的 SWE-bench Verified 都在随机 200 条子集上评测,公开基线则是全集,不能直接横比。
Terminal-Bench 2.0 的条长按 2× 放大以便观察。
三条可以带走的读数:
这张表额外加了一列 Long:用两倍大的非压缩窗口(30B 用 128k,106B 用 160k)作为"假装上下文足够长"的强参照。
| 系统 | 训练预算 | 摘要入损失 | SWE ×1 | SWE ×4 | SWE Long | TB ×1 | TB ×4 | TB Long |
|---|---|---|---|---|---|---|---|---|
| 30B:×1/×4 用 64k 峰值,Long 用 128k | ||||||||
| GLM-4.7-Flash | – | – | 47.5 | 50.5 | 53.5 | 14.6 | 13.4 | 16.9 |
| + RL(不含压缩)-64k | 64k | ✗ | 50.0 | 48.0 | 48.5 | 16.9 | 12.4 | 12.4 |
| + RL(不含压缩)-128k | 128k | ✗ | 48.3 | 52.5 | 59.0 | 11.8 | 23.6 | 14.6 |
| + CompactionRL(不训摘要) | 64k×4 | ✗ | 52.5 | 54.5 | 50.2 | 9.0 | 12.4 | 11.2 |
| + CompactionRL | 64k×4 | ✓ | 43.7 | 56.0 | 49.0 | 16.9 | 20.2 | 16.9 |
| 106B:×1/×4 用 80k 峰值,Long 用 160k | ||||||||
| GLM-4.5-Air | – | – | 57.8 | 59.8 | 59.5 | 17.9 | 21.4 | 20.8 |
| + RL(不含压缩)-80k | 80k | ✗ | 58.3 | 62.5 | 61.8 | 20.2 | 23.6 | 21.1 |
| + RL(不含压缩)-160k | 160k | ✗ | 63.0 | 64.5 | 64.0 | 20.8 | 23.0 | 23.6 |
| + CompactionRL(不训摘要) | 80k×4 | ✗ | 54.5 | 64.5 | 61.6 | 17.6 | 21.5 | 20.2 |
| + CompactionRL | 80k×4 | ✓ | 57.3 | 66.8 | 62.1 | 21.4 | 24.5 | 22.5 |
两点:
| 系统(GLM-4.5-Air-SFT,80k×4 评测) | SWE-bench Verified | Terminal-Bench 2.0 |
|---|---|---|
| GLM-4.5-Air | 59.8 | 21.4 |
| + CompactionRL | 66.8 | 24.5 |
| − 去掉 token 级损失归一化 | 60.0 −6.8 | 21.3 −3.2 |
| − 去掉跨轨迹 GAE | 63.0 −3.8 | 22.5 −2.0 |
去掉 token 级损失归一化后,成绩几乎完全掉回基座水平(66.8 → 60.0,基座 59.8)——也就是说压缩训练的全部收益都被 segment-count 偏置吃掉了。这个结论有点反直觉:跨轨迹 GAE 是论文里数学上更漂亮的那个部件,但真正致命的是更朴素的那个损失权重问题。
| 系统 | 压缩次数 / trace | 工具调用 / trace | 触发压缩任务上的 Pass@1 |
|---|---|---|---|
| GLM-4.5-Air-SFT | 0.47 | 83.4 | 35.4 |
| RL-80k(不含压缩) | 0.21 | 48.2 | 29.0 |
| RL-160k(不含压缩) | 0.26 | 63.5 | 45.9 |
| CompactionRL(不训摘要) | 0.58 | 90.8 | 42.4 |
| CompactionRL | 0.36 | 60.7 | 47.7 |
这张表比主表更有信息量。CompactionRL 的压缩次数(0.36)和工具调用数(60.7)都比基座和"不训摘要"变体低,但比不含压缩的 RL 高。也就是说:
SUPO 把摘要式上下文管理引入多轮 RL 并与工具使用联合优化;ReSum 用周期性外部摘要工具 + 分段轨迹训练摘要条件化 agent;Context-Folding 把上下文管理建模成可 RL 训练的 branch-and-fold 技能。CompactionRL 的差异点在于:面向长程编码 agent,把执行段与压缩段放在同一个 PPO 目标下联合训练,并明确处理了压缩带来的损失权重与跨段信用分配问题。
另外值得注意:本文 group size = 1 的设定,和单轨迹异步优化(SAO)那条线是同一个方向上的两种解法——前者靠 critic,后者靠改进的重要性采样与价值模型工程。两篇都在说同一件事:长程 agentic RL 里,"组"这个结构越来越难维持了。