第 14 讲:Compaction 上下文压缩

Codex 源码解析 · 第 14 讲

Codex 源码解析系列 第 14 讲:Compaction 上下文压缩 基于 OpenAI Codex 源码 · 2026-10-08 💡 本讲一句话: 压缩不是"摘要一下扔了旧历史"这么简单——它是一条完整生命周期:触发判定 → 三路径分发(本地摘要 / 远程 V2 / 窗口重置)→ 协议校验 → 预算截断 → 窗口记账 → 检查点持久化。本讲逐行拆 run_auto_compact 的分发逻辑、V2 "恰好一个 Compaction item" 的硬契约、64k/20k 双预算、模型降级重试与 AutoCompactWindow 窗口链,读完你能说清 Codex 压缩后为什么既不丢用户授权事实、也不会把摘要装错位置。 一、三个入口,一个分发器 第 13 讲我们看过 ContextManager 管着"模型可见窗口 + 保留上下文"两层历史。本讲回答下一个问题:当这个窗口快装不下了,Codex 怎么压缩?触发点有三个——手动 /compact ( core/src/tasks/compact.rs )、turn 开始前的 pre-turn 检查( session/turn.rs 第 1240-1258 行)、以及 turn 执行中采样完发现超限的 mid-turn rollover(同文件第 600-640 行)。三条路最终都汇到同一个分发器 run_auto_compact : 📄 codex-rs/core/src/session/turn.rs (第 1397-1455 行) async fn run_auto_compact( // 自动压缩统一入口:pre-turn / mid-turn / 模型切换三处都调它 sess: &Arc<Session>, // 会话共享指针,历史、遥测、hook 全挂在上面 step_context: Arc<StepContext>, // 当前步上下文(模型 + 工具路由 + 设置快照),压缩请求按它构造 fallback_step_context: Option<Arc<StepContext>>, // 可选的"当前模型"备用上下文——上一模型压缩失败时拿它重试 client_session: &mut ModelClientSession, // 复用 turn 的连接会话,sticky routing / websocket 增量状态不丢 initial_context_injection: InitialContextInjection, // 新历史要不要重注入初始上下文(mid-turn 必须注入) reason: CompactionReason, // 触发原因:用户请求 / 窗口满 / 模型降级 / comp hash 变化 phase: CompactionPhase, // 所处阶段:独立 turn / pre-turn / mid-turn,决定错误上报时机 ) -> CodexResult<()> { // 函数体开始:返回压缩结果(成功或错误) let turn_context = &step_context.turn; // 取出 turn 级上下文读配置与 provider 能力 if turn_context.config.features.enabled(Feature::TokenBudget) { // TokenBudget 特性开启 → 压缩退化为"重置窗口" crate::compact_token_budget::run_inline_auto_compact_task( // 完全不调模型,直接装一个新上下文窗口 Arc::clone(sess), step_context, initial_context_injection).await?; // 传共享会话与步上下文,执行“重置窗口” return Ok(()); // 提前返回:这条路径不走任何摘要逻辑(第六节细讲) } match turn_context.provider.capabilities().remote_compaction { // 按 provider 声明的远程压缩能力三分支 RemoteCompactionSupport::V2 => { // V2:服…

阅读全文:Codex 源码解析 第 14 讲