Codex 要抛弃传统上下文压缩了?Token Budget、硬切换与外部记忆如何接力
最近看到一种说法,Codex 准备放弃 compaction,不再压缩上下文,而是改用 Token Budget,让模型自己管理剩余空间。
这句话听着很有冲击力。
Codex 最近的上下文管理方案,确实发生了一次明显转向。模型开始知道当前窗口还剩多少 Token,可以主动调用 new_context 开启新窗口,也可以通过 Notes 保存任务状态,再从 History 中找回旧记录。在这条实验路径里,窗口切换时不再自动生成旧对话摘要,而是直接重置活跃上下文。
但把这套变化概括成「放弃 compaction」,仍然不够准确。传统压缩路径没有从 Codex 中全面消失,新的窗口切换在客户端生命周期里也依然被视为一次 compaction。真正改变的,是旧信息进入新窗口的方式。
一边是把旧对话浓缩成摘要,继续放在模型眼前。另一边是把旧对话移出活跃上下文,需要时再通过 Notes 和 History 恢复。
先把结论放在这里。
Codex 没有全面放弃 compaction。它在实验性上下文管理模式中,放弃的是「把旧对话总结成一份摘要再带入新窗口」的做法,改成「清空活跃上下文,再通过 Notes 和 History 恢复所需信息」。
这不是简单地给模型加一个 Token 计数器,也不是让模型突然拥有了无限记忆。
它更像一次上下文管理思路的转向。
一. 先把完整方案放在一起看
如果只盯着 Token Budget,很容易以为 Codex 只是给模型加了一个剩余空间提示。可在完整的实验方案里,Token Budget 只是其中一环。
整套机制由四部分配合完成。
Token Budget 告诉模型当前窗口还剩多少空间。Notes 保存跨窗口继续工作所需的任务状态。History 提供查询旧消息和工具轨迹的能力。new_context 负责结束当前窗口,开启一份新的活跃上下文。
它们连起来以后,工作流程大致是这样的。
模型在当前窗口中执行任务,同时知道剩余预算。准备切换时,它需要先把目标、进度、关键决定和下一步写进 Notes。随后,模型主动调用 new_context,或者由运行时触发窗口切换。新窗口启动后,模型根据系统提供的 Notes 提示主动读取 checkpoint,遇到缺失细节时再查询 History。
这个流程确实不再依赖一份自动生成的旧对话摘要。但它依然在减少活跃上下文,也依然保留了 Codex 客户端原有的 compaction 生命周期。
真正需要弄清楚的,不是 Codex 到底还用不用 compaction 这个词,而是每次窗口切换时,旧信息以什么方式进入下一次模型请求。
这个区别才是关键。
二. 聊天记录还在,不等于模型这一轮看得见
聊压缩之前,先弄清一件很容易混淆的事。
假设你已经和 Codex 聊了 100 轮。第一轮你明确要求「只修改支付模块,不要动订单模块」。这条消息可能仍然保存在客户端或会话存储中。
但聊天界面保存的完整记录,并不等于模型下一轮实际收到的上下文。
大模型本身不会永久保存这 100 轮对话。每次需要继续生成时,Codex 都要向模型发起一次请求,并把这一轮推理需要使用的内容放进请求。模型只能处理这次请求中实际提供的系统指令、对话消息、文件内容和工具结果。
压缩之前,这份模型输入可能包含大量旧消息和工具输出。压缩之后,Codex 会把其中大部分原始内容移除,再用一份摘要,或者一份全新的上下文替代它们。
因此,即使第一轮那句「不要动订单模块」仍然保存在会话存储中,只要它没有进入压缩摘要,也没有被重新放进模型输入,模型在第 101 轮就无法知道这条限制。
旧记录是否仍被持久化,和模型当前能否使用它,是两个问题。从模型角度看,没有进入当前输入的内容就是不可见的。
这也是为什么 Codex 需要把信息分成三个层次。
| 信息位置 | 是否进入当前模型输入 | 模型现在能否使用 |
|---|---|---|
| 活跃上下文 | 已经进入 | 可以直接使用 |
| Notes | 系统可注入提示,正文需要读取 | 读入当前上下文后才能使用 |
| History | 检索并取回后才进入 | 取回以后才能使用 |
会话存储负责保存过去,活跃上下文决定模型这一轮实际知道什么。Notes 正文和 History 里的内容只有被重新取出并放回活跃上下文,才会再次参与模型推理。
所以,「旧信息还保存在 History 里」只能说明数据没有从存储中消失。只有当它被重新放进模型输入时,模型才算重新获得了这部分信息。
三. 传统 compaction 做的是一份自动交接摘要
长任务不断读取文件、执行命令、分析错误,活跃上下文迟早会接近上限。传统 compaction 的处理办法,是把旧对话交给模型总结,再用这份更短的摘要替换大段原始历史。
原来可能有几十轮对话、数万行工具输出。压缩以后,新窗口拿到一份短得多的任务摘要,里面通常会保留目标、已经完成的工作、重要决定、当前状态和待办事项。
它的优点很直接。
新窗口一启动,摘要已经在 Prompt 里。模型不需要先猜自己应该搜索什么,也不需要额外调用 History。只要摘要写得好,工作可以立即接上。
问题也同样直接。
摘要是一种有损转换。
生成摘要的那一刻,系统必须提前判断哪些内容以后有用,哪些可以舍弃。但未来会问什么,当时并不知道。某个错误日志里不起眼的一行、用户早期加过的一条限制、一次失败尝试的具体原因,都可能在后面突然变得重要。
如果它们没有进入摘要,新窗口甚至不知道自己漏掉了什么。
多次压缩还会带来另一层风险。第二次压缩处理的可能已经不是完整原文,而是上一次摘要和后续对话。信息经过反复转述,细节会逐渐变薄,任务也可能慢慢偏离最初要求。
这就是摘要式 compaction 最难解决的问题。
它节省了上下文,却把未来需要什么的判断,提前到了压缩发生的那一刻。
四. Token Budget 最初只解决了「模型不知道还剩多少」
在完整方案里,Token Budget 解决的是运行时和模型之间的信息不对称。Codex 的运行时知道上下文用了多少,模型自己却未必得到清晰的剩余额度。模型可能还在展开一段很长的分析,运行时已经准备触发压缩了。
Token Budget 改变的是这层信息不对称。
一个新窗口启动时,模型会拿到完整的预算信息。使用量跨过几个关键区间后,它还会收到剩余 Token 提醒。于是模型可以更早地收束探索、完成当前步骤,或者为即将到来的窗口切换整理状态。
这项能力很重要,但它本身没有规定旧上下文应该怎样处理。
预算信息回答的是「当前窗口还剩多少」。compaction 回答的是「空间不够以后怎么办」。一个是状态信号,一个是切换策略。
所以,Token Budget 不能单独代表一套新的压缩机制。它只是让模型能够参与窗口管理,而不是等运行时在临界点替它做决定。真正改变旧信息处理方式的,是后面的上下文切换环节。
五. 真正改变路线的是 new_context 和后续硬切换
new_context 给了模型主动结束当前窗口的能力。当模型认为窗口里已经堆了太多过期工具输出,或者剩余空间不足以安全完成下一段工作时,它可以要求 Codex 开启新窗口。
这次切换有两个很关键的特点。
它不请求模型或服务端生成旧历史摘要,也不把之前的用户消息、模型回复和工具输出继续带入下一次请求。新窗口只拿到标准的初始上下文。
在 Token Budget 实验模式下,手动 /compact 和自动 compaction 也会进入这条无摘要切换路径。无论切换由模型主动提出,还是由运行时触发,新的活跃上下文都不会继承旧对话摘要。
这里很容易产生一个疑问。既然原始任务和旧对话都不再进入新窗口,模型怎么知道自己接下来要做什么?
先纠正一个概念。Codex 创建的是同一任务线程里的新上下文窗口,不是重新创建一条聊天会话。线程还在,运行环境也还在,只是下一次发送给模型的上下文被换掉了。
新窗口启动时,Codex 会自动重新注入一批基础信息,包括系统和开发者指令、项目规则、当前工作目录、权限与沙箱设置、可用工具、环境状态,以及新的上下文窗口编号。
这些信息能让模型知道自己是谁、在哪个项目里、可以使用哪些工具,却不能告诉它「用户最初要求做什么」以及「上一窗口已经做到哪里」。源码里的测试明确检查了,新窗口的模型请求不包含旧窗口的用户消息、Assistant 回复和工具输出。
真正负责恢复任务的是 Notes 和 History。
切换之前,模型会收到预算提醒和上下文管理指引,要求它把当前目标、完成进度、重要决定、失败原因和下一步写入 Notes。这份 checkpoint 的确带有摘要性质,但它不是系统对全部聊天记录自动生成的 compaction summary,而是模型面向后续执行主动整理的任务状态。
新窗口启动时,History Notes 扩展可以自动提供一小段 thread_hint,提示有哪些 Notes 可用。这里自动进入上下文的只是提示,不是 Notes 文件的完整正文。模型仍要主动调用 Notes 工具,读取刚才保存的 checkpoint。需要核对某条旧消息或工具结果时,再主动调用 History 工具查询。
因此,新窗口恢复任务的完整链路是这样的。
旧窗口写 checkpoint → 新窗口收到 Notes 提示 → 模型读取 checkpoint → 必要时查询 History → 相关内容重新进入活跃上下文
因此,新窗口并非完全不需要摘要信息。它仍然需要一份包含目标、进度和下一步的短信息,才能继续执行任务。区别在于,这份信息不是传统 compaction 自动生成并直接放进新窗口的摘要,而是模型主动写入 Notes 的任务 checkpoint,新窗口还需要主动读取它。
如果模型切换前没有写好 Notes,thread_hint 没有提供有效线索,或者模型没有成功查询 History,源码并不保证它还能知道原始目标。新窗口真的可能失去任务连续性,这正是这套方案最需要防范的失败方式。
于是两种机制出现了真正的分叉。
左边的摘要式 compaction,是把旧内容改写成更短的文本,再把这份文本放进新窗口。
右边的无摘要切换,是让旧内容离开活跃上下文,新窗口从干净的工作集开始。需要恢复连续性时,再依靠 Notes 和 History。
两条路线都会显著减少下一次请求里的 Token,但减少方式完全不同。
一个做内容浓缩。
一个做工作集重置。
六. 为什么代码里仍然把它叫 compaction
看到这里,可能会冒出一个问题。既然没有生成摘要,为什么 Codex 仍然把这个过程叫 compaction?
因为软件里的 compaction 不只有「文本总结」这一层含义。
从 Codex 客户端的生命周期看,窗口切换前后还有一整套固定动作。压缩前后的 hooks 要执行,客户端要收到 ContextCompaction 事件,系统要记录 checkpoint,窗口编号也要推进。
这些对外行为没有消失。
改变的是 compaction 内部如何构造下一份上下文。传统路径生成摘要,Token Budget 实验路径直接启动新窗口。
因此,两句话可以同时成立。
从文本处理方式看,它放弃了摘要式 compaction。
从客户端生命周期看,它仍然在执行一次 compaction。
争论很多时候就卡在这里。有人用 compaction 指代「生成摘要」,有人用它指代「收缩活跃上下文并进入下一窗口」。定义不同,结论自然相反。
我觉得更不容易误导人的叫法,是「带外部连续性的上下文轮换」。它准确描述了发生的事,也不会让人误以为旧对话被神奇地无损搬进了新窗口。
七. Notes 和 History 怎么把任务接起来
无摘要切换最难的部分,不是清空上下文。清空很容易,难的是新窗口怎么知道上一窗口做到哪里了。
这里可以用工程团队的交接班来理解,因为两边的关系几乎可以逐项对应。
传统摘要式 compaction,像系统把整段值班群聊自动整理成一份交接报告。接班的人只看报告,原始聊天不在眼前。报告写得完整,交接就顺。漏了一条关键限制,接班人也很难察觉。
新的实验路径,更像离场前写一份简短 checkpoint,旧事件记录仍可通过 History 查询。接班的人先读 checkpoint,遇到具体疑问再检索旧记录。
这个比喻不是为了形象而形象。几项关系是严格对得上的。
当前窗口对应正在值班的人眼前掌握的材料。Notes 对应主动写下的交接检查点。History 对应可以检索的历史事件记录。new_context 对应一次明确的换班。
Notes 适合保存当前目标、已经做过的决定、修改过的文件、验证结果、未完成事项,以及下一步该从哪里继续。它不是旧窗口的完整副本,而是一份面向后续执行的状态快照。新窗口可能自动得到一段 Notes 提示,但 Notes 正文仍需要模型主动读取。
History 负责补细节。新窗口遇到不确定的信息时,可以去查询之前的消息和工具轨迹,把相关片段重新放回活跃上下文。
这样的设计有一个很聪明的地方。
摘要式 compaction 必须在切换时一次性猜中未来需要的全部信息。History 把一部分判断推迟到了真正需要信息的时候。未来问题出现后再检索,查询意图会比压缩时更明确。
但它并没有消灭信息损失,只是把风险换了位置。
过去的主要风险,是摘要没有写进去。
现在的主要风险,是 Notes 没有记、History 没有查到,或者模型根本不知道该查什么。
八. 这到底还算不算压缩
现在可以正面回答最容易争论的那个问题了。
如果压缩指的是「减少下一次请求里的活跃 Token」,它当然仍然是一种压缩,而且比生成摘要更彻底。旧对话不再以摘要形式常驻,新窗口的工作集几乎重新开始。
如果压缩指的是「把一段长文本总结成一段短文本」,新路径确实没有再做这件事。
不过,说它完全没有任何信息浓缩,也不够严谨。
Notes 本身就是一次选择。模型需要从当前工作中挑出值得交接的状态,写成短得多的 checkpoint。区别在于,Notes 不是系统强制生成的一份全量历史摘要,它更关注如何继续执行,而且旧记录理论上仍能通过 History 找回。
可以把两条路线放在一起看。
| 问题 | 摘要式 compaction | Token Budget 实验路径 |
|---|---|---|
| 下一窗口是否变小 | 是 | 是 |
| 是否自动总结整段旧历史 | 是 | 否 |
| 旧消息是否直接进入新窗口 | 以摘要形式进入 | 不直接进入 |
| 如何承接任务 | 依赖自动摘要 | 依赖 Notes 和 History |
| 能否找回摘要遗漏的原始细节 | 通常很困难 | 工具可用且检索命中时可以 |
| 主要失败方式 | 摘要遗漏和多次转述漂移 | checkpoint 缺失、检索失败和重复工作 |
| 客户端是否仍走 compaction 生命周期 | 是 | 是 |
所以我自己的判断是,用「放弃压缩」概括这次变化太宽了。
更准确的表达应该是,Codex 在一条实验路径里放弃了自动摘要式压缩,改用主动 checkpoint、上下文重置和按需历史检索。
九. 新方案为什么值得尝试
对编程 Agent 来说,长任务里的大部分 Token 并不具有同等价值。
一次搜索可能返回几百行匹配,一次测试可能打印上千行日志,一个文件可能被重复读取好几次。这些内容在当时有用,完成判断以后却很快过期。把它们继续留在每次请求里,不只浪费 Token,也会增加模型从噪声中寻找当前任务的难度。
摘要式 compaction 会尝试把这一切统一整理。但工具轨迹越长,摘要模型越需要在大量临时信息中判断什么值得保留。这个过程本身要消耗 Token 和时间,还可能把一条短小却关键的约束埋掉。
无摘要切换提供了另一种思路。
已经写进代码库的改动,可以重新读文件。已经提交到测试系统的结果,可以重新执行验证。真正需要跨窗口持续携带的,往往是用户目标、设计决定、失败原因和当前进度。
让 Notes 保存这些执行状态,让 History 负责原始细节,活跃上下文只保留当前阶段需要的材料,确实更接近一个分层存储系统。
这条路线还给了模型更多主动权。模型知道剩余预算后,可以在一个逻辑步骤完成时切换,而不是等上下文撞到上限,被运行时突然打断。
它追求的不是把每个窗口榨到最后一个 Token,而是在合适的任务边界完成交接。
十. 如何开启新的压缩机制
因为它还处于 under development 阶段,配置名、开放范围和默认行为都可能继续变化。
截至 2026 年 9 月 5 日,Codex CLI 最新稳定版是 0.153.4。这个版本已经包含 features.context_management.experimental_mode 配置和对应的运行时激活逻辑。先确认自己正在使用的版本。
1 | codex --version |
下面的操作以 0.153.4 的源码和内置配置测试为准。更早版本是否支持,不能只看配置文件有没有报错,最稳妥的做法还是先升级到当时的最新稳定版。
Codex 默认读取 ~/.codex/config.toml。如果设置过 CODEX_HOME,配置文件就在 $CODEX_HOME/config.toml。在文件中加入下面这段配置。
1 | [features.context_management] |
保存后重新启动 Codex,再执行下面的命令。
1 | codex features list |
如果输出里的 context_management 状态为 true,只能说明 Codex 已经识别并打开这个配置。它还不能证明 Token Budget、Notes 和 History 已经在当前会话中真正生效。
原因是 Codex 创建会话时还会做一轮资格检查。截至这个版本,几项条件需要同时满足。
| 检查项 | 0.153.4 中的要求 |
|---|---|
| 登录方式 | 使用 ChatGPT 账号登录,API Key 不符合条件 |
| 订阅类型 | Plus、Pro 或 Pro Lite |
| 模型后端 | 使用官方 Codex 后端 |
| 自定义连接 | 自定义 Provider 凭据、Bearer Token 和 AWS Provider 不符合条件 |
这里有个很容易踩的坑。当前代码使用的是订阅白名单,不是「付费账号都可以」。Free 和 Enterprise 都不在这份白名单里。
如果资格检查没有通过,当前实现不会因为这项配置直接报错,而是不会激活实验路径,继续使用原来的上下文管理方式。所以,context_management = true 和实验功能实际生效,是两件事。
真正进入实验路径后,Codex 才会打开 Token Budget,并启用内置的 History 和 Notes 扩展。长任务接近预算阈值时,模型会收到剩余 Token 和整理 checkpoint 的提醒。发生窗口切换后,它再通过 Notes 与 History 接续工作。
这项功能现在更适合体验和观察,还不适合当成稳定契约。以后如果发现配置突然失效,先检查当前 Codex 版本的配置 Schema、账号开放范围和 Release Notes,不要默认 experimental_mode 会一直保留这个名字和这套行为。
十一. 总结
回到最开始的问题,Codex 到底有没有放弃 compaction?
真正的变化,是上下文管理不再只依赖一份越来越长、反复改写的摘要,而是开始出现更清晰的层级。
活跃上下文负责当前推理。Notes 负责跨窗口交接。History 提供查询过去记录的能力。Token Budget 让模型知道什么时候该整理和切换。new_context 给了它执行切换的能力。
这套结构让当前模型输入只保留眼下需要的信息,把任务状态和旧记录放到上下文窗口之外,再通过 checkpoint 和检索连接起来。
它并没有突破上下文窗口的物理限制,也没有让 Codex 获得真正的无限记忆。
它只是承认了一件很现实的事。
长任务不可能把全部过去永远摊在模型眼前。系统真正需要解决的,是何时放下过去、留下什么交接信息,以及以后如何准确找回来。
所以,给这次变化一句尽量不误导人的总结,我会这样写。
Codex 没有全面放弃 compaction。它正在实验一种新的 compaction 实现,不再自动总结全部旧历史,而是把连续性拆给 Token Budget、Notes、History 和
new_context共同完成。
旧方案把希望押在一份摘要上。
新方案把希望押在一次可靠的交接和一次准确的回查上。
没有哪一种天然无损。
只是丢失信息的地方,变了。
十二. 关键 PR 与 Issue
- Codex CLI 0.153.4 Release
- PR #27438,Add token budget context feature
- PR #27488,Add new context window tool
- PR #29743,Reset context for token budget compaction
- PR #39827,Add model-facing History and Notes tools
- PR #40539,Add Notes thread hint to new context windows
- PR #42385,Add experimental context management activation
- Issue #42449,Compaction requires unavailable Notes tool and repeats work





