Codex 桌面端一直在自动压缩上下文?扒完源码发现阈值算错了基数
发布日期:2026-09-03 | 话题:OpenAI Codex / auto compact / 上下文管理 / 桌面端
Codex auto compact(自动上下文压缩)是 OpenAI Codex 在会话 token 逼近上限时自动触发的历史摘要机制,桌面端与 CLI 共用同一套 codex-rs 内核。2026 年 7 月以来 openai/codex 仓库已积累二十余个相关未关闭 issue,症状集中在压缩卡住无法取消、压缩完成后上下文仍有约 80% 被占用、以及压缩后对话历史从界面消失。根因是一处基数错配:压缩阈值按原始窗口的 90% 计算,可用窗口却只有原始窗口的 95%,压缩因而发生在可用窗口约 94.7% 处,且该阈值只能调低不能调高。OpenAI 已于 2026 年 8 月转向 token budget 方案,改用开新窗口配合持久化历史与笔记工具。
桌面端用户实际遇到的是哪几类问题
Codex 桌面端的自动压缩问题不是单一 bug,而是四条独立的故障链,在 openai/codex 仓库中均处于未关闭状态。
第四类最容易被误判为「数据丢了」。issue #41954 的报告者导出了原始 rollout 文件,发现历史 API 返回的条目形如 {"type":"userMessage","text":""}。
而完整原文仍保存在 compacted.payload.replacement_history 字段里——数据没丢,是渲染层没有正确回填被压缩窗口的内容。
还有一类间接症状:issue #39767(2026-08-20)分析了一份长会话 rollout,发现 GPT-5.6 的历史推理内容被重复计数了一次,在该会话的 76 次自动压缩中,76 次全部是误触发——按正确计数方式,一次都不该触发。
自动压缩到底在什么时候触发
自动压缩的阈值是模型原始上下文窗口的 90%,而不是可用窗口的 90%。 这一点在 codex-rs 的模型元数据实现里写得很直白:
// codex-rs/protocol/src/openai_models.rs
pub fn auto_compact_token_limit(&self) -> Option<i64> {
let context_limit = self
.resolved_context_window()
.map(|context_window| (context_window * 9) / 10);
let config_limit = self.auto_compact_token_limit;
if let Some(context_limit) = context_limit {
return Some(
config_limit.map_or(context_limit, |limit| std::cmp::min(limit, context_limit)),
);
}
config_limit
}同一个文件里,「可用窗口」用的是另一个字段:
const fn default_effective_context_window_percent() -> i64 {
95
}注释写明这个百分比是「为系统提示词、工具开销和模型输出预留余量之后,可用于输入的上下文窗口比例」。两者基数不同,叠加后的结果就是 issue #40095(2026-08-22)实测到的数字:
也就是说,压缩实际发生在可用窗口的约 94.7% 处,此时只剩约 13,600 token 余量。而压缩动作本身要携带待摘要的历史、压缩提示词和模型输出,这点余量经常不够——这就是压缩卡住和压缩失败的直接来源。
为什么调大 model_auto_compact_token_limit 没用
model_auto_compact_token_limit 只能把阈值调低,调高会被静默忽略。 上面那段源码的关键在 std::cmp::min:配置值与「原始窗口 90%」取较小者。字段注释也确认了这一行为——省略时由 context_window 推导出 90%,提供时会被钳制到 90% 上限。
网上流传的「把这个值调大就不会频繁压缩」的说法在当前实现下不成立。同理,官方配置参考中并没有提供关闭自动压缩的开关,阈值、作用域和压缩提示词是仅有的三类旋钮。
压缩完为什么还是 80% 满,以及 42GB 的磁盘去哪了
压缩会把被替换掉的完整历史重新写回会话记录,这既撑大了新窗口,也撑爆了磁盘。 issue #35032 描述的循环是:压缩 → 恢复时接近满载 → 跑几次工具调用 → 再次压缩。报告者指出问题在于 replacement history 未做去重和裁剪,仍然携带了不再需要的原始工具输出。
磁盘侧的表现更直观。issue #41806(2026-08-31,macOS)统计了自己的 ~/.codex 目录:
总体积约 42GB,其中
archived_sessions/占 28GB,sessions/占 11GB,其余三十多个目录合计约 500MBarchived_sessions/下有 1,145 个 rollout JSONL 文件,平铺存放,没有任何保留策略其中 82 个文件超过 100MB,合计约 23GB,占该目录的 82%;最大单文件 1.2GB
时间分布高度集中:98.8% 的归档体积产生于 2026 年 8 月单月,8 月 30 日一天新增 190 个文件
根因被归结为两点:压缩时把完整 replacement_history 重新嵌进 rollout JSONL,以及归档会话从不清理、不压缩、不裁剪。
反复压缩还有一层成本代价:每一轮压缩都要把历史重新送进模型做摘要,这部分 token 不产生任何有效产出。长 Agent 任务的费用难以预估,很大一部分就来自这类不可见的重算——按额度包预付的接入形式在这类场景下用量上限在调用前即已确定,例如七牛云 Token Plan 采用的就是这种计费方式。

config.toml 里真正可调的旋钮
Codex 桌面端与 CLI 共享 ~/.codex/config.toml。与压缩直接相关的配置项如下(字段名与官方配置参考一致):
把阈值调低,是当前唯一能给压缩动作留出足够操作余量的办法。以 272,000 窗口为例,配置成可用窗口的 85% 左右比较稳妥:
# ~/.codex/config.toml
model_context_window = 272000
model_auto_compact_token_limit = 219000 # 约为可用窗口 258400 的 85%
model_auto_compact_token_limit_scope = "body_after_prefix"body_after_prefix 的意义是:阈值只计算压缩窗口前缀之后新增的部分,而不是整个活动上下文。对于已经压缩过一次、前缀本身就很大的长会话,这个选项能显著减少「刚压缩完就又到阈值」的情况。
此外还有两个生命周期钩子事件 PreCompact 和 PostCompact,可以在压缩前后执行命令或 MCP 工具,支持 async(默认 false)和 additionalContextLimit(默认 2500)等参数。
常见用法是在 PreCompact 里把当前任务的验收标准、待办清单写进一个外部文件,压缩后再读回来,避免关键状态被摘要掉。
OpenAI 的答案:token budget 正在取代压缩
Codex 团队的方向不是修好压缩,而是在长任务中不再压缩——改为直接开启新的上下文窗口,靠历史与笔记工具跨窗口恢复状态。 codex-rs/core/src/compact_token_budget.rs 里的实现注释说明了这一点:
/// Token-budget compaction skips model/server summarization and installs a
/// fresh context window instead. It is still modeled as compaction so compact
/// hooks and `ContextCompaction` turn items observe the same lifecycle as
/// local or remote compaction.函数体里也确实没有任何摘要请求,核心只有一句 sess.start_new_context_window(step_context, world_state)。压缩钩子和事件被保留,是为了不破坏客户端兼容性。
配套能力来自 PR #39827,标题为「Add history and notes tools for token-budget sessions」,已于 2026 年 8 月 21 日合并。它为 token budget 会话新增了两组直连模型的工具:
history:列出窗口与条目、读取条目、搜索对话内容notes:列出、读取、搜索、追加、写入持久笔记
PR 描述明确写道,这是为了让 token budget 会话「能够跨上下文窗口切换恢复此前的对话上下文并保留工作状态」。
内核里还内置了一条提醒模板,会在窗口即将耗尽时告知模型接下来会发生什么:
Your context window is nearly exhausted (only {n_remaining} tokens remaining)
and will be automatically reset for you soon. Once reset, message items in
current context window will be cleared in the new window, but notes and history
items will be persistent across windows.这套机制目前仍在功能开关后面,相关配置位于 features.token_budget 命名空间下:
use_history_notes_extension:是否启用历史与笔记工具,默认 falsereminder_threshold_tokens:触发窗口耗尽提醒的剩余 token 数,必须为正reminder_message_template:提醒文案模板,上限 2000 字节,不可为空guidance_message:附加引导文案,上限 2000 字节auto_compact_fallback_prompt与auto_compact_fallback_buffer_tokens:回退到摘要压缩时使用,两者必须成对出现,缓冲 token 数必须为正,否则配置校验直接报错
长任务现在该怎么配
在 token budget 模式全量放开之前,可按以下顺序处理:
先确认是不是误触发。在会话里查看状态信息,对比可用窗口与实际占用。如果远未接近上限却已压缩,很可能命中了 issue #39767 那类推理内容重复计数的问题,升级到最新版本再观察。
把阈值调低到可用窗口的 80%–85%,给压缩动作留出足够操作空间。记住只能调低。
把 scope 切到
body_after_prefix,避免长会话压缩后立刻二次触发。用
PreCompact钩子外置关键状态。把验收标准、待办项、已确认的结论写进项目内的文件,压缩后从文件读回,比指望摘要保留这些信息可靠。控制单条工具输出的体量。用
tool_output_token_limit限制工具输出写入历史的规模,长日志和大文件内容尽量落盘再按需读取,而不是整段灌进对话。定期清理会话归档。
~/.codex/archived_sessions/目前没有自动保留策略,长期高强度使用后需要人工清理,否则会出现 issue #41806 那样几十 GB 的占用。超长任务主动分线程。当一个任务确实需要跑几个小时,与其依赖压缩续命,不如在阶段边界主动开新会话,用交接文档传递状态——这也正是 token budget 机制在做的事。
常见问题
Codex 桌面端能彻底关闭自动压缩吗? 不能。官方配置参考中没有提供关闭自动压缩的开关,可调的只有触发阈值、阈值作用域和压缩提示词三类。把 model_auto_compact_token_limit 调低可以改变触发时机,但无法禁用该机制。
为什么我把 model_auto_compact_token_limit 调大了却没有生效? 因为源码用 std::cmp::min 将配置值与「原始上下文窗口的 90%」取较小者,调高会被静默钳制回上限。这个字段只能用来把阈值往下调。
压缩后界面里消失的对话内容还能找回来吗? 可以。issue #42311 和 #41954 都确认这是渲染层问题,完整原文仍保存在本地会话 JSONL 文件的 compacted.payload.replacement_history 字段中,直接读取该文件即可取回。
total 和 body_after_prefix 这两个作用域该选哪个? total(默认)针对完整活动上下文计算阈值;body_after_prefix 只计算压缩窗口前缀之后新增的部分。已经压缩过一次、前缀较大的长会话选后者,可以明显减少反复触发。
token budget 模式现在能用吗? 相关代码已合入主干,配套的 history 与 notes 工具随 PR #39827 于 2026 年 8 月 21 日合并,但仍在 features.token_budget 功能开关后面,use_history_notes_extension 默认为 false,属于逐步放量阶段。
小结
Codex 桌面端自动压缩的核心问题不在压缩算法本身,而在触发时机:阈值按原始窗口的 90% 计算,可用窗口又只有原始窗口的 95%,两个百分比基数不一致,使压缩发生在可用空间几乎耗尽的位置。
叠加 replacement history 未裁剪导致的新窗口高占用,就形成了反复压缩、额度浪费和会话文件膨胀的连锁反应。
据 openai/codex 仓库的公开 issue 与源码,OpenAI 已在 2026 年 8 月转向 token budget 方案,用开新窗口配合持久化的历史与笔记工具替代摘要式压缩。
本文所述行为基于 openai/codex 仓库截至 2026 年 9 月 3 日的主干代码(CLI 最新发布版本 rust-v0.153.0)与官方配置参考,功能开关状态和默认值随版本变动较快,建议在实际配置前对照当前版本的配置文档核实字段名与默认值。
延伸阅读
openai/codex 仓库:https://github.com/openai/codex
官方配置参考(config.toml 全量字段):https://learn.chatgpt.com/docs/config-file/config-reference
Issue #40095 自动压缩阈值基数问题:https://github.com/openai/codex/issues/40095
Issue #35032 桌面端压缩后仍接近满载:https://github.com/openai/codex/issues/35032
Issue #41806 会话归档膨胀至 42GB:https://github.com/openai/codex/issues/41806
Issue #42311 压缩后界面历史消失:https://github.com/openai/codex/issues/42311
PR #39827 token budget 会话的历史与笔记工具:https://github.com/openai/codex/pull/39827
多模型 API 用量方案:https://www.qiniu.com/ai/plan