深入 Codex 源码:Auto-Compact 机制为何"姗姗来迟"
从 Codex 源码出发,拆解 auto-compact 为什么常常显得“姗姗来迟”。文章沿着 run_turn 主循环分析 pre-turn 与 mid-turn 两个触发入口,解释 90% 自动压缩阈值与 95% UI 有效窗口的错位、用户输入未计入 pre-turn 判断带来的延迟,以及 compact 前的历史…
深入 Codex 源码:Auto-Compact 机制为何"姗姗来迟" Code Version: 基于 codex 仓库 commit 5e3793def(2026-03-22)。 你是否在使用 Codex 时注意到:上下文余量已经低至 20% 左右,系统却迟迟不触发自动 compact,反而在这个水位线上来回"晃荡"好几轮才最终压缩?这篇文章将从源码层面完整拆解这个现象背后的设计逻辑。 ⏭️ 如果你只关心结论,跳到 §7. 设计优缺点分析。1. 导航 本文按数据流组织,覆盖以下内容: | 章节 | 内容 | |------|------| | §2 | 核心概念:两个不同的 token 计数器 | | §3 | Auto-compact 触发时机:pre-turn 与 mid-turn | | §4 | 阈值计算:90% vs 95% 的错位 | | §5 | UI 百分比:你看到的数字是怎么算的 | | §6 | Compact 前的"减肥"机制 | | §7 | 设计优缺点分析 |2. 核心概念:两个不同的 token 计数器 理解整个 compact 行为的关键,在于区分 Codex 内部的 两套 token 度量——它们分别服务于不同目的,却容易被混淆: | 度量 | 用途 | 数据来源 | 定义位置 | |------|------|----------|----------| | get_total_token_usage() | auto-compact 阈值判断 | last_token_usage.total_tokens + 最后一次模型响应后新增 item 的估算 | codex-rs/core/src/context_manager/history.rs:285 | | last_token_usage | TUI 百分比显示 | 服务端返回的最近一次请求的 token 统计 | codex-rs/core/src/codex.rs:3640 | get_total_token_usage() 的核心逻辑:// codex-rs/core/src/context_manager/history.rs:285 pub(crate) fn get_total_token_usage(&self, server_reasoning_included: bool) -> i64 { let last_tokens = self .token_info .as_ref() .map(|info| info.last_token_usage.total_tokens) .unwrap_or(0); let items_after_last_model_generated_tokens = self .items_after_last_model_generated_item() .iter() .map(estimate_item_token_count) .fold(0i64, i64::saturating_add); if server_reasoning_included { last_tokens.saturating_add(items_after_last_model_generated_tokens) } else { last_tokens .saturating_add(self.get_non_last_reasoning_items_tokens()) .saturating_add(items_after_last_model_generated_tokens) } } 💡 关键点:这不是一个精确计数器——它是"上次服务端报告的 total_tokens + 此后新增 item 的本地估算"。估算值和实际值之间的偏差,是 compact 触发时机不精准的原因之一。3. Auto-Compact 触发时机 自动 compact 有且仅有 两个入口。没有后台定时器,没有独立线程轮询——一切都发生在用户对话的 run_turn 主循环中。3.1 数据流总览用户输入 │ ▼ run_turn() │ ├─ ① run_pre_sampling_compact() ← pre-turn 入口 │ ├─ maybe_run_previous_model_inline_compact() │ └─ if total_usage >= auto_compact_limit → run_auto_compact() │ ├─ record_context_updates() ← 用户输入和 context diff 写入历史 │ └─ loop { ├─ 发送 sampling request ├─ 收…
正在初始化 WebAssembly 引擎…
首次编译原生模块可能需要数秒
就绪后,页面交互将以接近原生的速度运行