Appearance
Context 什么时候该压缩、什么不能丢:Compaction、Trigger 与 Fidelity
前置:Tool 如何撑爆 Context:Definition Cost 与 Result Management
核心问题:Context 快满时,哪些内容可以压缩、哪些事实绝不能丢,怎样证明 compaction 没把任务语义悄悄改掉?
在 70% 先清理旧 Tool Result,85% 才做结构化 compaction;进入新里程碑时也可主动 checkpoint/reset。用户要求“绝不提交代码”应存入 protected constraints;即使历史压缩多次也必须保持,不能因 summary 漂移丢失。
Context Compaction
Compaction 不是“把聊天摘要一下”,而是把已经消费过的 working context 转成下一轮仍能继续工作的更小状态表示。
至少要保留:当前目标/约束、已完成进度、关键失败、尚未解决的问题,以及可重新读取的 artifact/tool-result reference。大量旧对话措辞、重复日志和已失效中间推理可以丢掉。
判断是否成功的标准不是“token 变少了”,而是 compaction 后 Agent 继续执行时不会忘记重要事实或把已经失败的路径重新走一遍。
Compaction Trigger Policy
不要等到 Provider 报 context overflow 才开始压缩。更好的 trigger 是提前观察:
text
token high-water mark
+ turn 数持续增长
+ tool result 快速膨胀
+ 任务阶段切换例如 128K window 不应该用到 127K 才 compaction,因为还要给下一轮 Tool schema、retrieval 和模型输出留空间。
触发也不能过早:每几轮都做有损 summary,会让信息经过多次压缩后逐渐漂移。实际系统通常设置 high-water mark,再在阶段边界优先压缩。
Protected State
Protected State 是 compaction 不得自由丢弃的 durable facts,例如 objective、constraints、decisions、completed/pending、failed attempts、artifact refs。结构化字段比一段自由摘要更可验证。
它应由结构化字段保护,而非依赖 summarizer 自觉。
Compaction Drift / Information Loss
重复 summary-of-summary 会放大小遗漏。减轻方法包括结构化 compaction、保留原始 artifact/provenance、必要时 re-ground authoritative source。
尤其 negative knowledge、精确参数、边界条件最容易丢。应保留 source refs,并周期性从权威原文 re-ground。
Failure Modes
只在 Context 即将溢出时才触发 Compaction
症状: token ratio 已接近硬上限仍继续追加大 Tool Result。
为什么危险: 没有空间进行温和压缩或保留 output reserve,下一次 call 直接 overflow。
处理: 设置 soft/hard watermark,并结合 task phase、tool result size、turn count 提前触发。
Compaction 把关键约束和未决状态一起摘要掉
症状: 用户目标、审批要求、失败尝试只存在自由文本 summary。
为什么危险: 多次 summary-of-summary 后关键约束永久丢失,后续模型可能重复错误或越权。
处理: 目标、constraints、decisions、pending approvals 等结构化 protected state 独立保存并在 compaction 后校验。
Summary-of-summary 累积语义漂移
症状: 每次 compaction 都只读取上一次 summary,不再保留 provenance 或原始 artifact reference。
为什么危险: 小遗漏被后续 summary 放大,最终任务状态与真实历史偏离。
处理: 保留原始 transcript/artifact refs,结构化 summary,并定期 re-ground 到权威来源。
如何验证
| Case | 断言 |
|---|---|
| 只在 Context 即将溢出时才触发 Compaction | 模拟 token 逐步增长,断言 soft limit 触发清理/compaction,hard limit 前仍留安全余量。 |
| Compaction 把关键约束和未决状态一起摘要掉 | 连续多次 compaction,断言 protected fields 完整且与原始事实一致。 |
| Summary-of-summary 累积语义漂移 | 长程 eval 多次 compaction,检查 critical fact recall、constraint preservation 与 drift rate。 |
Codex 源码对照:Context Projection + Compaction Lifecycle
要回答的问题
Runtime 中的 source-of-truth state 怎样变成一次真正发给模型的 context?Compaction 是只在 Turn 开始前发生,还是也会在同一个 Codex Turn 的 continuation 中发生?
精确定位
Tag: rust-v0.150.1
File:
codex-rs/core/src/context_manager/history.rscodex-rs/core/src/session/context_window.rscodex-rs/core/src/session/turn.rscodex-rs/core/src/tasks/compact.rs
Symbols:
ContextManager::for_prompt(...)ContextManager::for_prompt_annotated(...)context_window_token_status(...)run_turn(...)run_pre_sampling_compact(...)run_auto_compact(...)CompactTask::run(...)
最小调用链
Context projection:
text
SessionState.history: ContextManager
→ record context / world-state updates
→ clone_history()
→ ContextManager::for_prompt(input_modalities)
→ normalize / filter model-visible history
→ sampling_request_input
→ run_sampling_request(...)Pre-turn protection:
text
run_turn(...)
→ run_pre_sampling_compact(...)
→ context_window_token_status(...)
→ token_limit_reached?
→ run_auto_compact(..., CompactionPhase::PreTurn)
→ samplingMid-turn continuation protection:
text
sampling + tool/response completion
→ context_window_token_status(...)
→ needs_follow_up
→ threshold / new-context-window request
→ should_roll_over
→ run_auto_compact(..., CompactionPhase::MidTurn)
→ continue
→ next samplingObservable Fact
ContextManager::for_prompt() 明确是“准备发送给模型的 history”:它会 normalize history,并根据 model input modalities 去掉或转换不适合发送的内容。因此 stored history 与 model-visible request projection 不是同一个对象。
context_window_token_status() 由 Runtime 计算 active context usage、auto-compact scope、full context hard cap 和 token_limit_reached。run_turn() 在第一次正常 sampling 前调用 run_pre_sampling_compact();在 sampling 完成后又重新计算 token status,如果仍需 follow-up 且需要 rollover,则以 CompactionPhase::MidTurn 执行 auto compact 后 continue 到下一次 sampling。
Design Inference
两个 invariant:
- Source-of-truth state ≠ model context projection:Runtime 可以持有比模型输入更多、更权威的状态;每次 request 应从 source state 构造受预算/能力约束的 projection。
- Compaction trigger belongs to Runtime policy:Runtime 应根据 token/context status 与 continuation need 决定何时 compact,而不是让模型自由声称“我已经压缩过上下文”。
Codex-specific Trade-off
Codex rust-v0.150.1 使用 ContextManager、AutoCompactTokenLimitScope、CompactionPhase::PreTurn/MidTurn,并根据 provider capability 选择 local/remote compact。这些命名、阈值策略和 provider 分支属于 Codex 当前实现。
Shadow Harness Delta
- 把
ContextSnapshot明确建模为从 Run/Session source state 派生的 request projection,不能当唯一真实状态库。 - Context Assembly 增加
build_projection(source_state, model_capabilities, budget)边界,并记录 projection manifest/hash。 - Compaction state machine 增加两类入口:
pre_request protection与mid-run continuation protection。 - 测试至少覆盖:连续两次 tool continuation 跨过阈值后,compact 后仍能继续下一次 sampling;protected constraints / pending action / artifact reference 不能丢。
不要过度推导
Runtime 触发了 compact 不等于 summary 一定语义无损。这些文件能证明 trigger、phase 和 continuation control 在 Runtime;不能证明任何 summarizer 都满足 Fidelity,也不能证明 compact 后所有业务约束天然保真。
完整映射见 OpenAI Codex Source Map。
自测
- Compaction 后“必须兼容 Python 3.12”这条约束消失了。这个错误说明 protected state 或 fidelity check 哪一环失效?
- 为什么等到 hard context limit 才开始压缩太晚?你会用什么 soft trigger,并怎样验证多次 compaction 后语义没有漂移?