长任务 Agent 的轨迹通常包含:
- 多轮 reasoning;
- 工具调用和工具返回;
- 中间搜索结果;
- 已经失败或过期的假设;
- 局部结论和待验证事实。
这些内容持续累积后会产生两个问题:
-
上下文窗口溢出
轨迹最终超过模型上下文窗口,系统必须截断、压缩或停止。
-
context rot
论文强调的重点不是单纯 token 不够,而是旧的、错误的、低价值的上下文会锚定后续生成。模型在干净上下文里能解决的问题,喂回自己早期错误推理后反而可能失败。
现有系统通常使用固定规则压缩:
| 策略 | 触发方式 | 问题 |
|---|---|---|
| Reactive compaction | 快到上下文上限时压缩 | 太晚,污染上下文已经影响了很多步 |
| Periodic compaction | 每隔固定 token/turn 压缩 | 不看任务状态,可能在推导中间、搜索中间压掉关键内容 |
手动 /compact |
用户决定 | 把识别 context rot 的负担交给用户 |
论文的核心判断是:什么时候压缩,取决于轨迹结构,而不只是 token 数。
SELFCOMPACT 是一个训练无关的 scaffold,不改模型权重。它由两个推理时元素组成:
-
压缩工具
模型可以触发一个 summarizer,把当前累计轨迹压成摘要,然后系统用摘要替换旧轨迹,后续从摘要继续。
-
rubric 判定
系统定期向同一个模型追加一个轻量判断 prompt,让模型输出
COMPRESS或CONTINUE。rubric 明确告诉模型什么情况下可以压缩、什么情况下不能压缩。
论文的关键结论是:工具和 rubric 必须同时存在。
- 只有工具:不同模型行为不稳定,有的乱压,有的不压。
- 只有 rubric:只能判断,不能改变上下文。
- 工具 + rubric:在合适的 closed reasoning unit 后压缩,避免在 mid-derivation 或 stuck 状态压缩。
论文 Algorithm 1 可以简化为:
C = original_prompt
for each generation step:
y = model(C)
C = C + y
if y is final answer:
return y
if reach probe interval:
C_probe = C + rubric_prompt
decision = model(C_probe) # COMPRESS or CONTINUE
if decision == COMPRESS:
C_sum = C + summarizer_prompt
summary = model(C_sum)
C = original_prompt + summary
else:
discard rubric prompt and decision
continue with original C
几个实现要点:
- rubric probe 是追加到现有上下文上的,不替换上下文;
CONTINUE时,rubric prompt 和判定结果会被移除,不污染真实轨迹;COMPRESS时,summarizer 输出摘要,旧轨迹被摘要替换;- rubric judge 和 summarizer 都使用同一个模型,不引入外部 verifier;
- 通过追加 prompt 复用已有 KV cache,避免每次判定都重新 prefill 整个长轨迹。
论文不是用一个泛化口号式 prompt,而是针对任务类型设计 rubric。
数学任务在每个 round 边界检查三个问题:
| 问题 | 含义 |
|---|---|
Q1 ANSWER |
最新 round 是否给出了明确 final answer,比如 \boxed{} |
Q2 STUCK |
最近 2 个 round 是否没有新增非平凡事实 |
Q3 HAS-NEXT |
是否能写出明确下一步,例如 case split、substitution、lemma |
触发规则:
COMPRESS iff Q1 = Y or (Q2 = Y and Q3 = Y)
直觉:
- 已经有答案时,压缩可以锁定结果,后续验证或改进。
- 卡住但有明确下一步时,压缩可以丢掉无效循环,保留下一步方向。
- 如果还在活跃推导中,不能压缩。
Agentic search 的 rubric 更严格,要求四个门同时满足:
| 条件 | 含义 |
|---|---|
C1 CLOSED-UNIT |
最近消息是完整工具调用结果或完整子分析,不是半截思路 |
C2 SUMMARIZABLE |
关键信息可以压成 3-5 条带引用事实 |
C3 PROGRESS |
自上次压缩后确实有新事实或新子问题 |
N1 STUCK |
是否卡住,如果最近 4 次搜索中至少 3 次没有新 URL 或新事实,则视为 stuck |
触发规则:
COMPRESS iff C1 = Y and C2 = Y and C3 = Y and N1 = N
这组条件体现了论文的主要工程思想:
- 压缩应该发生在“阶段结束后”;
- 需要保留的内容必须能被摘要可靠表达;
- 没有新进展就不要反复压缩;
- 卡住时压缩可能掩盖问题,不能把 dead ends 总结成看似有用的状态。
论文里的 summarizer 不是普通闲聊摘要,而是 continuation summary:摘要要替代完整历史,让模型继续完成任务。
数学 summarizer 要求:
- 保留关键洞察、重要计算、推理路径;
- 删除重复文本、失败尝试和无意义重复;
- 如果找到了 final answer,必须保留;
- 如果答案可能错误或未验证,需要标注仍需验证;
- 输出未完成部分需要继续做什么。
搜索 summarizer 要求:
- 只提取对回答原问题直接有用的信息;
- 不做超出对话内容的推断;
- 不保留不确定或无法确认的信息;
- 把多轮搜索里的确定事实合成为可继续研究的状态。
这和固定阈值摘要的区别在于:SELFCOMPACT 先判断“现在是否适合压缩”,再调用 summarizer;不是 summarizer 自己承担所有风险。
论文覆盖 6 个 benchmark、7 个模型,分为两类任务。
模型:
- Qwen3-4B-Instruct-2507
- Qwen3-30B-A3B-Instruct-2507
- Qwen3.5-4B
- Qwen3.5-9B
Benchmark:
- IMO-Answerbench
- HMMT Nov 2025
- HMMT Feb 2026
对比方法:
| 方法 | 说明 |
|---|---|
| No Compaction | 单次 16k token 预算,不压缩 |
| Fixed Interval Summary | 每 16,384 generated tokens 后强制摘要 |
| SELFCOMPACT | 根据 rubric 判断是否摘要 |
设置:
- 每题生成 16 个样本;
- temperature 1.0,top-p 0.7;
- summarizer 输出硬截断 512 tokens;
- fixed interval 的 token 预算和 SELFCOMPACT 匹配,避免因为 token 更多而不公平。
模型:
- GLM-4.7-Flash
- MiniMax-M2.5
- MiMo-V2-Flash
Benchmark:
- BrowseComp
- BrowseComp-Plus
- DeepSearchQA
对比方法:
| 方法 | 说明 |
|---|---|
| No Compaction | 不做上下文管理,直到窗口或工具调用上限 |
| Fixed-interval summary | prompt 达到 30% context window 后摘要 |
| Delete-all | 达到 30% 后删除全部历史 |
| Keep-last-N | 达到 30% 后只保留最后 3 turn |
| SELFCOMPACT | rubric 判定后摘要 |
搜索任务还加了工程 gate:
- 至少第 3 轮后才允许检查;
- prompt 至少 40,000 tokens;
- 最多摘要 1 次;
- 距离上次 probe 至少 2 轮;
- 达到 30% context window 时有 backstop 强制压缩。
论文 Table 1 的总体结论:
- 在 12 个模型/benchmark 组合中,SELFCOMPACT 在 11 个组合上最好;
- 对 thinking-disabled 的 Qwen3.5 系列提升尤其明显;
- Qwen3.5-9B 上相对 No Compaction 的提升达到:
- IMO-Answerbench:+16.4
- HMMT Nov:+10.0
- HMMT Feb:+18.1
平均准确率可以概括为:
| 模型 | No Compaction | Fixed Interval | SELFCOMPACT |
|---|---|---|---|
| Qwen3-4B-Instruct | 38.7 | 41.5 | 45.1 |
| Qwen3-30B-A3B-Instruct | 50.6 | 54.9 | 56.4 |
| Qwen3.5-9B | 32.5 | 40.1 | 47.3 |
| Qwen3.5-4B | 21.9 | 30.7 | 33.8 |
重要的是,Fixed Interval 并非无效,它通常比 No Compaction 好;但它会在错误时机压缩,留下进一步提升空间。
论文还做了 oracle 分析:如果固定间隔摘要在“当前答案已经正确”时跳过压缩,IMO-Answerbench 上 Qwen3-4B-Instruct 可以从 41.4 提升到 52.9。这说明固定间隔压缩确实经常破坏已经正确的状态。
论文 Table 4 的结论:
- SELFCOMPACT 在三个模型上 overall accuracy 都最高;
- BrowseComp-Plus 上相对 No Compaction 的提升:
- GLM-4.7-Flash:+8.5
- MiniMax-M2.5:+9.2
- MiMo-V2-Flash:+5.3
- 成本反而低于 No Compaction,因为摘要后后续 prompt 变短。
Overall 结果:
| 模型 | No Compaction | Fixed Interval | SELFCOMPACT |
|---|---|---|---|
| GLM-4.7-Flash | 36.6 / $0.13 | 41.5 / $0.05 | 46.4 / $0.07 |
| MiniMax-M2.5 | 54.6 / $0.19 | 59.3 / $0.06 | 63.9 / $0.08 |
| MiMo-V2-Flash | 48.9 / $0.25 | 54.7 / $0.14 | 59.2 / $0.13 |
这里有一个细节:SELFCOMPACT 不一定总比 Fixed Interval 更便宜,但通常在准确率上更强,并且相对 No Compaction 有明显成本下降。
论文 Figure 2 显示:
- Fixed Interval 的触发点固定在 30% context window;
- SELFCOMPACT 的触发点分布更靠左,也更分散;
- 这说明很多情况下,模型在到达 30% 阈值之前已经完成了一个可压缩阶段。
这支持论文主张:固定阈值通常太晚,已经让 stale tokens 多污染了若干步。
论文 Figure 3 用 No Compaction 的输出 token 数作为难度 proxy,把题目分成 5 个 quantile。
结果:
- 简单题上,各策略差距不大;
- 最难的两个区间,SELFCOMPACT 比固定阈值高 5-20 个百分点;
- 越需要长搜索、越容易累积错误上下文,rubric-gated 压缩越有价值。
论文做了去掉 rubric 的消融,让模型自己决定是否摘要。
| 任务 | Fixed Interval | SELFCOMPACT w/o rubrics | SELFCOMPACT |
|---|---|---|---|
| GLM search avg | 41.5 | 41.0 | 46.4 |
| Qwen3-4B IMO | 41.4 | 40.9 | 45.5 |
结论很直接:收益不是来自“能压缩”本身,而是来自 rubric 对压缩时机的约束。
SELFCOMPACT 每次 probe 最多增加两个 LLM call:
- rubric probe;
- 如果判定为
COMPRESS,再调用 summarizer。
论文认为这个额外成本可控,原因是:
- probe 和 summarizer 都是追加到已有 prefix 上,能复用 KV cache;
- rubric 只生成很短的判定;
- 真正的收益来自压缩后每个后续调用的 prompt 都变短。
论文给出的经验压缩比:
50k-100k trajectory -> 1k-3k summary
也就是 20-80 倍缩短。只要后续还有多轮调用,摘要成本很容易被摊销。
论文附录 E 展示了 3 个 BrowseComp-Plus case,重点不是“压缩是否发生”,而是“压缩发生在什么状态”。
Fixed Interval:
- 每次 30% 阈值触发摘要;
- 摘要反复保留同一批错误候选;
- Agent 一直被错误 shortlist 锚定,最终猜错。
SELFCOMPACT:
- rubric 在没有 closed unit 时继续;
- 等到约 118k tokens 后做一次压缩;
- 摘要保留约束而不是错误候选列表;
- Agent 跳出旧候选,找到 David Coverdale 和 Whitesnake。
Fixed Interval:
- 早期误把 classical piece 线索引到 Rachmaninoff;
- 每次摘要都把错误 lead 带下去;
- 最后没有测试 Arabic artist。
SELFCOMPACT:
- 先继续搜索,直到修正为 Albinoni's Adagio;
- 在 corrected lead 后压缩;
- 后续定位 Majida El Roumi。
Fixed Interval:
- 搜索 goal-minute fingerprint 无果;
- 摘要不断重放同一批无效搜索日志;
- 没有测试 Tottenham vs Chelsea。
SELFCOMPACT:
- 允许继续探索直到找到正确 match;
- match 找到后压缩;
- 后续验证 attendance、进球和助攻,得到 Raheem Sterling。
这些 case 说明:不合时机的摘要会把错误路径固化;合时机的摘要可以把阶段性事实固化,并让模型从无效循环中脱离。
PR #1938 把 SELFCOMPACT 的思想接到 AgentScope 的上下文压缩逻辑里。改动集中在三个文件:
| 文件 | 改动 |
|---|---|
src/agentscope/agent/_agent.py |
在压缩流程中加入 self-compaction 判定 |
src/agentscope/agent/_config.py |
增加 self-compaction 配置和结构化输出 schema |
tests/compress_context_test.py |
增加默认关闭、提前压缩、跳过、失败容错等测试 |
ContextConfig 新增 4 个字段:
| 字段 | 默认值 | 作用 |
|---|---|---|
self_compact_enabled |
False |
是否启用模型驱动的提前压缩 |
self_compact_probe_interval |
1 |
每 N 个 reasoning iteration 检查一次 |
self_compact_min_iters |
1 |
低于该 iteration 不检查 |
self_compact_rubric_prompt |
通用默认 prompt | 让模型判断 COMPRESS / CONTINUE |
默认关闭是合理的:它不改变现有用户的固定阈值压缩行为。
PR 增加了 SELF_COMPACT_DECISION_SCHEMA:
{
"type": "object",
"properties": {
"decision": {
"type": "string",
"enum": ["COMPRESS", "CONTINUE"],
},
"reason": {
"type": "string",
},
},
"required": ["decision", "reason"],
"additionalProperties": False,
}也就是说,AgentScope 没有让模型自由输出文本再解析,而是走 generate_structured_output,降低判定解析失败概率。
PR 的默认 prompt 是通用型:
- 如果旧对话包含已经完成的工作、工具结果或中间推理,并且摘要能保留进展、降低干扰或上下文成本,则
COMPRESS; - 如果近期细节仍需逐字保留、历史太少、压缩会丢失下一步所需信息,则
CONTINUE; - 输出
COMPRESS或CONTINUE。
这和论文实现有明显差异:
| 维度 | 论文 | AgentScope PR |
|---|---|---|
| rubric 类型 | 数学/搜索任务特定 | 通用 rubric |
| 输出条件 | 多个显式条件,例如 C1/C2/C3/N1 | 单一自然语言判断 |
| 证据要求 | 要求引用轨迹证据 | 默认 prompt 没有强制证据结构 |
| 触发单位 | token 或工具调用边界 | cur_iter reasoning iteration |
| backstop | 搜索任务有 30% 强制 backstop | 保留原有 token threshold 机制 |
AgentScope PR 更像是把论文思想做成通用框架入口,而不是复刻论文实验 scaffold。
原本 _compress_context_impl 只看 token 阈值:
estimated_tokens >= trigger_ratio * context_size
PR 后逻辑变为:
exceeds_threshold = estimated_tokens >= threshold
if not exceeds_threshold
and self_compact_enabled
and state.context exists:
self_compact_requested = await _should_self_compact(...)
if not exceeds_threshold and not self_compact_requested:
return
继续执行原有压缩流程
也就是说:
- 超过阈值:仍然按原逻辑压缩;
- 未超过阈值:如果 self-compact rubric 判定
COMPRESS,可以提前压缩; - rubric 判定
CONTINUE:不压缩。
新增方法的逻辑:
cur_iter = self.state.cur_iter or 0
if cur_iter < self_compact_min_iters:
return False
if cur_iter % self_compact_probe_interval != 0:
return False
if rubric_prompt is empty:
return False
rubric_messages = messages + [UserMsg(content=rubric_prompt)]
res = model.generate_structured_output(
messages=rubric_messages,
structured_model=SELF_COMPACT_DECISION_SCHEMA,
)
return res.content["decision"].upper() == "COMPRESS"
这和论文一致的地方:
- 在推理中追加 rubric prompt;
- 用模型自己判断;
- 输出二元决策;
- 未超过固定 token 阈值时也可以提前压缩。
不完全一致的地方:
- 论文的
CONTINUE会从真实轨迹中移除 probe;PR 里rubric_messages是新 list,不写回state.context,等价于不污染轨迹; - 论文强调 KV cache 复用;PR 层面只是调用模型 API,是否复用取决于底层模型服务;
- 论文的 summarizer prompt 是任务特定的;PR 复用 AgentScope 既有 summary schema 和压缩流程。
PR 对失败处理比较谨慎。
rubric 失败:
如果当前未超过 token 阈值,只是可选提前压缩失败,则记录 warning 并跳过压缩。
summary 失败:
如果是 self_compact_requested 且未超过 token 阈值,则保留原始上下文。
这个设计很重要:self-compaction 是优化,不应因为可选判断失败中断正常回复。
但如果已经超过 token 阈值,仍走原有压缩异常处理,因为这时压缩是 overflow 防护,不是可选优化。
PR 增加的测试覆盖了几个关键行为:
| 测试 | 目的 |
|---|---|
test_self_compact_disabled_by_default |
默认关闭,不额外调用 rubric |
test_self_compact_can_trigger_early_compression |
未到 token 阈值也能提前压缩 |
test_self_compact_continue_skips_early_compression |
判定 CONTINUE 时跳过 |
test_self_compact_probe_interval |
遵守 probe interval |
test_self_compact_rubric_failure_skips_early_compression |
rubric 异常不影响正常上下文 |
test_self_compact_summary_failure_keeps_context |
可选提前压缩的 summary 失败时保留原文 |
这些测试主要验证控制流和容错,没有验证压缩质量。
-
兼容现有行为
默认关闭,且超过 token 阈值时仍使用原压缩逻辑。
-
实现面很小
没有引入新 memory subsystem,只是在现有
_compress_context_impl前增加一个可选 early trigger。 -
失败开放
低于阈值时的 self-compaction 是 best effort。rubric 或 summary 失败不会破坏会话。
-
结构化输出
用 schema 约束
COMPRESS/CONTINUE,比正则解析自然语言稳。 -
可配置
用户可以调整 probe interval、最小 iteration 和 rubric prompt。
-
默认 rubric 比论文弱
论文实验中 rubric 要求具体条件和轨迹证据,尤其搜索任务要求 C1/C2/C3/N1。PR 默认 prompt 是通用判断,没有强制引用证据,因此可能更容易过早或过晚压缩。
-
没有任务特定 summarizer
论文里数学和搜索的 summarizer 目标不同。PR 复用通用上下文压缩流程,效果取决于 AgentScope 现有 summary schema 是否足够表达任务状态。
-
probe 粒度不同
论文数学任务按 round/token 边界,搜索任务按工具调用边界。PR 用
cur_iter,更通用,但未必等价于“closed unit”。 -
没有显式 cost/KV cache 优化保证
论文的成本优势依赖 KV cache 复用。PR 在 Agent 层追加消息调用模型,但底层 provider 是否复用 cache 不由这段代码保证。
-
没有质量评测
PR 测试验证功能,不验证在真实 benchmark 上是否提升 accuracy/cost。
如果后续要把 AgentScope 实现做得更接近论文,可以考虑:
-
提供 rubric presets
例如:
self_compact_rubric_type="general"self_compact_rubric_type="math"self_compact_rubric_type="search"self_compact_rubric_type="coding"
-
要求 evidence-based structured output
不是只输出
decision/reason,而是让模型填:{ "closed_unit": {"answer": "Y", "evidence": "..."}, "summarizable": {"answer": "Y", "facts": [...]}, "progress": {"answer": "Y", "evidence": "..."}, "stuck": {"answer": "N", "evidence": "..."}, "decision": "COMPRESS" } -
区分压缩类型
数学任务可能需要
preserve-answer,搜索任务需要cite-able facts,代码任务需要files changed / commands run / failing tests / next edit。 -
把 probe 边界绑定到工具循环
对 ReAct Agent 来说,工具返回后、assistant 完成子分析后,通常比裸
cur_iter更接近 closed unit。 -
记录 self-compaction 事件
建议记录:
- probe token count;
- decision;
- reason;
- summary token count;
- compressed message count;
- 是否低于 threshold 提前压缩。
这样才能分析实际触发分布和效果。
SELFCOMPACT 的关键贡献不是“摘要上下文”,而是把压缩时机从固定 token 阈值改成由模型根据轨迹状态判断,并用 rubric 把这个判断约束成可验证的条件。
论文实验说明:
- 固定压缩通常比不压缩好,但会在错误时机破坏关键状态;
- rubric-gated compaction 在数学和搜索任务上都优于固定间隔;
- rubric 是必要组件,去掉后收益基本消失;
- 成本下降来自摘要后后续 prompt 大幅缩短,而 probe 本身较便宜;
- 难题和长搜索任务收益最大。
AgentScope PR #1938 是一个轻量、兼容的工程落地版本:默认关闭,在未达到 token 阈值时允许模型通过通用 rubric 提前触发既有压缩流程。它抓住了论文最重要的方向,但没有完整复刻论文中的任务特定 rubric、evidence gate、summarizer prompt 和实验 cost 优化。因此可以把它理解为 SELFCOMPACT-inspired early trigger,而不是论文算法的严格实现。