1. 长会话跑到一半突然失忆,问题到底出在哪
如果你用 Codex 跑过超过半小时的重构任务,大概率遇到过这种场景:前面十几轮已经把支付模块的边界、不能动的订单模块、必须保留的兼容分支都聊清楚了,结果某一次工具调用返回了几千行日志之后,模型下一轮突然开始问「你希望我修改哪个文件」。这不是模型变笨了,而是活跃上下文被换掉了,而换掉的方式决定了它还能不能记得你最初说过什么。
Codex 最近的上下文管理方案确实发生了一次明显转向。模型开始知道当前窗口还剩多少 Token,可以主动调用 new_context 开启新窗口,也可以通过 Notes 保存任务状态,再从 History 中找回旧记录。在这条实验路径里,窗口切换时不再自动生成旧对话摘要,而是直接重置活跃上下文。很多人把这套变化概括成「Codex 要抛弃传统上下文压缩了」,这个说法传播很广,但不够准确。传统压缩路径并没有从 Codex 中全面消失,新的窗口切换在客户端生命周期里依然被视为一次 compaction。真正改变的,是旧信息进入新窗口的方式。
这篇文章面向的是已经在用 Codex 做长任务、并且被上下文断裂坑过的开发者。我会把 Token Budget、new_context 硬切换、Notes 落盘、History 回填这四件事串成一条可复制的接力链路,给出具体的 config.toml 配置、阈值触发条件、Notes 模板,以及一次硬切换前后的 History 回填验证动作。所有请求都走 TaoToken 统一 Key 和 API 通道,这样你不需要在多个后端之间来回切账号,也能把整条链路跑通。
先把结论放在这里:Codex 没有全面放弃 compaction。它在实验性上下文管理模式中,放弃的是「把旧对话总结成一份摘要再带入新窗口」的做法,改成「清空活跃上下文,再通过 Notes 和 History 恢复所需信息」。这不是简单地给模型加一个 Token 计数器,也不是让模型突然拥有了无限记忆,而是一次上下文管理思路的转向。理解这个转向,比争论它到底叫不叫压缩重要得多。
2. TaoToken 前置准备:统一 Key 与 API 通道怎么配
在动手改 Codex 配置之前,先把请求通道固定下来。Codex 的上下文管理实验路径对模型后端有资格检查,而通过 TaoToken 的统一 API 通道接入,可以让你在同一个 Key 下切换模型、观察 Token Budget 行为,不用每次换后端都重新配一遍凭据。这一步的目标很简单:拿到一个可用的 API Key,把 Base URL 指向 TaoToken 的 API 地址,然后在 Codex 里验证一次普通请求能通。
先到 TaoToken 控制台创建 API Key。打开 https://taotoken.net/api-keys ,登录后新建一个 Key,复制出来。这个 Key 后面会同时用于 Codex 的模型请求和上下文管理实验路径的凭据校验。注意不要把它提交到 Git 仓库,建议放在环境变量里。
export TAOTOKEN_API_KEY="sk-你的key" echo $TAOTOKEN_API_KEY | head -c 8接着确认 Codex 的版本。上下文管理实验模式在较早版本里并不存在,配置项写进去也不会报错,但不会生效。先升级到当前稳定版,再继续后面的步骤。
codex --version # 期望输出类似:codex-cli 0.153.4如果你还没装 Codex CLI,可以用 npm 全局安装。装完之后先跑一次最基础的对话,确认 Key 和网络都正常,再去碰上下文配置。这一步的顺序很重要,因为后面如果实验模式没生效,你需要先排除「Key 本身就不通」这个变量。
npm install -g @openai/codex codex --versionCodex 默认读取~/.codex/config.toml。如果你设置过CODEX_HOME,配置文件就在$CODEX_HOME/config.toml。先看一下当前文件内容,避免覆盖掉你已有的配置。
cat ~/.codex/config.toml把模型后端指向 TaoToken 的 API 地址,同时把 Key 通过环境变量注入。下面这段是基础通道配置,先保证普通请求能通,再叠加上下文管理实验项。
# ~/.codex/config.toml model = "gpt-5-codex" model_provider = "taotoken" [model_providers.taotoken] name = "TaoToken" base_url = "https://taotoken.net/api" env_key = "TAOTOKEN_API_KEY" wire_api = "responses"保存后重启 Codex,跑一句最简单的请求验证通道。如果这一步返回正常,说明 Key、Base URL、模型 ID 三件套都对上了。如果报 401,先回到控制台确认 Key 有没有复制完整、有没有被禁用,再检查环境变量是不是在当前 shell 里生效。
codex exec "用一句话说明当前工作目录是什么"通道打通之后,再叠加上下文管理实验配置。这里要提醒一句:实验模式对登录方式和订阅类型有资格检查,通过 API Key 接入时,部分资格条件可能不满足,导致配置被识别但不激活。这不是配置写错了,而是当前实现的白名单机制。遇到这种情况,先确认版本和账号范围,不要反复改配置。
3. 可复制配置:Token Budget 阈值与 new_context 触发条件
这一节是整篇文章的核心,所有片段都可以直接复制。先把上下文管理实验模式打开,再理解 Token Budget 的阈值区间和 new_context 的触发逻辑。配置写错一个层级,实验路径就不会激活,所以我会把路径和原文保持一致,你照着放就行。
在~/.codex/config.toml里加入下面这段。注意[features.context_management]是独立表,不要塞进[model_providers.taotoken]里面。
# ~/.codex/config.toml [features.context_management] experimental_mode = true保存后重启 Codex,执行特性列表命令确认配置被识别。
codex features list # 期望看到 context_management 状态为 true这里有个关键区别要讲清楚:context_management = true只说明 Codex 识别并打开了这个配置,不代表 Token Budget、Notes、History 已经在当前会话中真正生效。Codex 创建会话时还会做一轮资格检查,几项条件需要同时满足,包括登录方式、订阅类型、模型后端等。如果资格检查没通过,当前实现不会因为这项配置直接报错,而是静默回退到原来的上下文管理方式。所以你要在后面的验证环节里,用实际行为去确认它到底有没有生效。
Token Budget 的阈值逻辑是这样的:新窗口启动时,模型会拿到完整的预算信息;使用量跨过几个关键区间后,它会收到剩余 Token 提醒。这些提醒不是硬性中断,而是给模型一个信号,让它有机会在合适的任务边界收束探索、整理状态、准备切换。你可以把阈值理解成三档:宽裕档、提醒档、临界档。宽裕档下模型正常干活;提醒档下模型开始考虑把当前步骤收尾;临界档下模型应该主动写 Notes 并调用 new_context。
new_context 的触发条件有两类。第一类是模型主动触发:当它判断窗口里堆了太多过期工具输出,或者剩余空间不足以安全完成下一段工作时,主动要求开启新窗口。第二类是运行时触发:手动/compact或自动 compaction 在实验模式下也会进入这条无摘要切换路径。无论哪一类,新的活跃上下文都不会继承旧对话摘要。
这里要纠正一个常见误解:Codex 创建的是同一任务线程里的新上下文窗口,不是重新创建一条聊天会话。线程还在,运行环境也还在,只是下一次发送给模型的上下文被换掉了。新窗口启动时,Codex 会自动重新注入一批基础信息,包括系统和开发者指令、项目规则、当前工作目录、权限与沙箱设置、可用工具、环境状态,以及新的上下文窗口编号。这些信息能让模型知道自己是谁、在哪个项目里、能用哪些工具,却不能告诉它「用户最初要求做什么」以及「上一窗口已经做到哪里」。
真正负责恢复任务的是 Notes 和 History。切换之前,模型会收到预算提醒和上下文管理指引,要求它把当前目标、完成进度、重要决定、失败原因和下一步写入 Notes。这份 checkpoint 带有摘要性质,但它不是系统对全部聊天记录自动生成的 compaction summary,而是模型面向后续执行主动整理的任务状态。新窗口启动时,History Notes 扩展可以自动提供一小段 thread_hint,提示有哪些 Notes 可用。这里自动进入上下文的只是提示,不是 Notes 文件的完整正文。模型仍要主动调用 Notes 工具,读取刚才保存的 checkpoint。需要核对某条旧消息或工具结果时,再主动调用 History 工具查询。
如果你用的是 Claude Code 或 Cline 这类工具,配置思路类似,但字段名不同。以 Cline 的 MCP 配置为例,Base URL、Key、Model ID 三件套要写全,缺一个都会连不上。
{ "mcpServers": { "taotoken": { "command": "npx", "args": ["-y", "@taotoken/mcp-server"], "env": { "TAOTOKEN_BASE_URL": "https://taotoken.net/api", "TAOTOKEN_API_KEY": "sk-你的key", "TAOTOKEN_MODEL_ID": "gpt-5-codex" } } } }Codex 的auth.json如果你手动维护过,也要确认里面的凭据和 config.toml 一致。三件套对不上,最常见的表现就是 401 或者 local proxy failed。下面是一个 auth.json 的结构参考,实际字段以你当前版本为准。
{ "provider": "taotoken", "base_url": "https://taotoken.net/api", "api_key_env": "TAOTOKEN_API_KEY", "model": "gpt-5-codex" }配置到这里就齐了。下一步是验证请求,确认整条链路真的跑起来了,而不是停在「配置被识别」这一步。
4. 验证请求:硬切换前后的 History 回填动作
配置写完不等于生效,这一节用一次完整的硬切换来验证。我会演示一个最小可复现的长任务:先让 Codex 记住一条约束,再故意把上下文推到切换点,最后检查新窗口能不能通过 Notes 和 History 把约束找回来。整个过程走 TaoToken 通道,你照着做就能复现。
第一步,启动一个交互式会话,给 Codex 一条明确的、后续必须遵守的约束。这条约束要足够具体,方便后面验证它有没有被记住。
codex # 在会话里输入: # 本次任务只修改 src/payment/ 目录下的文件,绝对不要动 src/order/ 目录。 # 记住这条约束,后面每一步都要遵守。第二步,制造足够的上下文压力。让 Codex 连续读取几个大文件、跑一次测试、分析一段日志。目的是把活跃上下文推到提醒档甚至临界档。你可以用下面的方式快速堆叠工具输出。
# 在会话里依次输入: # 读取 src/payment/ 下所有文件并列出每个文件的函数签名 # 运行一次测试并输出完整日志 # 分析 src/order/ 目录结构,但不要修改任何文件第三步,观察 Token Budget 提醒。当使用量跨过提醒档时,模型会收到剩余 Token 提示。这时候它应该开始整理状态。你可以主动触发一次切换,模拟临界档行为。
# 在会话里输入: # /compact在实验模式下,这次/compact会进入无摘要切换路径。新窗口不会继承旧对话摘要,只会拿到标准初始上下文加一段 Notes 提示。切换完成后,立刻做回填验证。
# 在新窗口里输入: # 读取你刚才保存的 Notes,告诉我本次任务的核心约束是什么如果 Notes 写得完整,模型应该能回答出「只修改 src/payment/,不要动 src/order/」。如果它答不出来,说明 Notes 没写成功,或者 thread_hint 没提供有效线索。这时候再让它查 History。
# 在新窗口里输入: # 用 History 工具查询我之前说过的约束,把原文找出来History 工具会检索旧消息和工具轨迹,把相关片段重新放回活跃上下文。如果这一步能找回原始约束,说明整条接力链路是通的:旧窗口写 checkpoint,新窗口收到 Notes 提示,模型读取 checkpoint,必要时查询 History,相关内容重新进入活跃上下文。
这里有个实测下来很容易踩的坑:如果模型切换前没有写好 Notes,thread_hint 没有提供有效线索,或者模型没有成功查询 History,源码并不保证它还能知道原始目标。新窗口真的可能失去任务连续性。这正是这套方案最需要防范的失败方式。所以你在长任务里,最好在关键节点主动提醒模型写 Notes,而不是完全依赖它自己判断。
为了让你更直观地对照,我把两种机制放在一起看。左边的摘要式 compaction,是把旧内容改写成更短的文本,再把这份文本放进新窗口。右边的无摘要切换,是让旧内容离开活跃上下文,新窗口从干净的工作集开始,需要恢复连续性时再依靠 Notes 和 History。两条路线都会显著减少下一次请求里的 Token,但减少方式完全不同:一个做内容浓缩,一个做工作集重置。
| 问题 | 摘要式 compaction | Token Budget 实验路径 |
|---|---|---|
| 下一窗口是否变小 | 是 | 是 |
| 是否自动总结整段旧历史 | 是 | 否 |
| 旧消息是否直接进入新窗口 | 以摘要形式进入 | 不直接进入 |
| 如何承接任务 | 依赖自动摘要 | 依赖 Notes 和 History |
| 能否找回摘要遗漏的原始细节 | 通常很困难 | 工具可用且检索命中时可以 |
| 主要失败方式 | 摘要遗漏和多次转述漂移 | checkpoint 缺失、检索失败和重复工作 |
| 客户端是否仍走 compaction 生命周期 | 是 | 是 |
验证通过之后,你就可以把这套流程固化到日常长任务里。每次接近切换点,先确认 Notes 写好了,再触发切换,切换后立刻做一次回填验证。这个习惯能大幅降低「新窗口失忆」的概率。
5. 本篇常见错排查:401、local proxy failed 与 reading choices
这一节对照真实报错,把你在配置和验证过程中最可能撞上的几个问题拆开。每个问题都给出触发原因和排查顺序,你按顺序走,基本能定位到根因。
第一个高频报错是 401。表现是请求直接被拒,日志里能看到 unauthorized 或 invalid api key。触发原因通常是三件套里有一件对不上:Base URL 写错、Key 复制不完整、Model ID 不存在。排查顺序是先确认环境变量在当前 shell 里生效,再确认 config.toml 里的env_key和实际变量名一致,最后确认 Key 没有过期或被禁用。
echo $TAOTOKEN_API_KEY | wc -c # 正常应该是一个明显大于 20 的字符数 curl -s -o /dev/null -w "%{http_code}" \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ https://taotoken.net/api/models # 期望返回 200第二个高频报错是 local proxy failed。表现是 Codex 启动后请求发不出去,日志里出现连接被拒或代理相关字样。触发原因通常是本地网络配置和 Codex 的 provider 设置冲突,或者 Base URL 指向了一个不可达的地址。排查顺序是先确认base_url写的是https://taotoken.net/api,没有多余路径;再确认本机没有残留的代理环境变量干扰。
env | grep -i proxy # 如果有输出,先 unset 掉再重试 unset HTTP_PROXY HTTPS_PROXY ALL_PROXY第三个报错是 reading choices 相关。表现是请求返回了内容,但解析失败,日志里出现 reading choices 或 unexpected response shape。触发原因通常是wire_api字段和实际后端不匹配。Codex 的 provider 配置里wire_api要和你使用的接口形态一致,写错会导致响应结构对不上。排查顺序是确认wire_api的值,再确认模型 ID 是否支持该接口形态。
[model_providers.taotoken] wire_api = "responses" # 如果后端是 chat 形态,这里要改成对应值第四个问题是 OAuth 相关。表现是登录态校验失败,或者实验模式资格检查不通过。触发原因是上下文管理实验路径对登录方式和订阅类型有白名单要求,通过 API Key 接入时可能不满足。排查顺序是先确认 Codex 版本是否包含实验模式,再确认当前账号范围。如果资格不满足,配置会被识别但不激活,这时候不要反复改配置,先接受「实验模式暂不可用」这个事实,用普通上下文管理继续工作。
codex features list # 如果 context_management 显示 true 但行为没变化, # 说明配置被识别但资格检查未通过第五个问题是 Notes 没写成功导致新窗口失忆。表现是切换后模型不知道原始目标,反复问你已经说过的事。触发原因是模型在切换前没有主动写 Notes,或者 thread_hint 没有提供有效线索。排查顺序是在长任务的关键节点主动提醒模型写 Notes,切换后立刻做回填验证。如果 History 也查不到,说明旧记录没有被正确索引,这时候要检查 History 扩展是否真的启用。
# 在会话里主动触发 Notes 写入: # 现在把当前目标、进度、下一步写入 Notes,然后我们再继续第六个问题是重复工作。表现是新窗口把已经做过的步骤又做了一遍。触发原因是 Notes 里的进度信息不完整,模型不知道哪些已经完成。解决办法是在 Notes 模板里明确写出「已完成」「进行中」「待办」三段,让新窗口一眼能看出边界。这个模板我建议你固定下来,每次切换前都按这个结构写。
## 任务目标 只修改 src/payment/ 目录,不动 src/order/ ## 已完成 - 读取 payment 下全部文件 - 列出函数签名 - 跑通一次测试 ## 进行中 - 分析 payment 模块的依赖关系 ## 待办 - 修改 payment 的校验逻辑 - 回归测试 ## 关键决定 - 保留兼容分支,不删除旧接口 ## 下一步 从 payment/validator.ts 第 42 行继续把这六个问题对照一遍,你基本能覆盖配置和验证阶段 90% 的坑。剩下的就是版本差异带来的行为变化,遇到时先查当前版本的配置 Schema 和 Release Notes,不要默认实验模式会一直保留这个名字和这套行为。
6. 语义一致 CTA:把接力链路固定到你的工作流
走到这里,你已经有了完整的配置、验证方法和排错清单。接下来最重要的事,是把这套接力链路固定成你的日常习惯,而不是每次遇到上下文断裂再临时救火。我自己的做法是在项目根目录放一份 Notes 模板,长任务开始前先让 Codex 读一遍,切换前按模板写 checkpoint,切换后立刻做回填验证。这个习惯坚持下来,长任务的连续性会稳定很多。
如果你还没拿到 Key,先去 https://taotoken.net/api-keys 创建一个,然后回到第 2 节把 Base URL、Key、Model ID 三件套配好。接入文档在 https://taotoken.net/doc ,里面有各语言和各工具的接入示例,遇到字段不确定的时候可以直接对照。想先验证模型对话行为,可以用 https://taotoken.net/chat 跑几轮,确认 Token Budget 提醒和 Notes 写入的实际表现,再回到 Codex 里做长任务。
如果你打算长期用 Codex 做编码和 Agent 任务,建议直接上 Coding Plan,把额度固定下来,避免长会话跑到一半因为额度问题中断。地址是 https://taotoken.net/coding-plan 。控制台在 https://taotoken.net/console ,可以随时查看用量和 Key 状态。API Keys 管理页在 https://taotoken.net/api-keys ,需要轮换 Key 的时候从这里操作。
最后回到最开始那个问题:Codex 到底有没有放弃 compaction?我的判断是,用「放弃压缩」概括这次变化太宽了。更准确的表达是,Codex 在一条实验路径里放弃了自动摘要式压缩,改用主动 checkpoint、上下文重置和按需历史检索。旧方案把希望押在一份摘要上,新方案把希望押在一次可靠的交接和一次准确的回查上。没有哪一种天然无损,只是丢失信息的地方变了。你要做的,是在自己的任务里选一条更可控的路径,然后把验证动作固定下来。