Codex 用完一个月的额度只用了一个上午,这种事在开发者群里越来越常见。很多人以为是任务太复杂,其实往往是同一个原因:每次请求时塞进模型的上下文太大了。Codex 并不会凭空把你的 Token 烧掉,它只是把你给它的每一段历史对话、每一份重复粘贴的代码、每一条啰嗦的说明都忠实地计了费。
这篇文章要聊的不是“少用 Codex”,那是因噎废食。真正的方向是:用同样的功能,让每次请求携带更少冗余内容,让模型更快进入有效工作状态。在长上下文重复型任务里,把 Token 消耗降低 80% 并不是夸张的说法,而是上下文管理做到位以后的自然结果。读完这篇文章,你会掌握 Codex 的 Token 消耗构成、会话清理方法、System Prompt 精简技巧、增量式任务描述方法、模型与输出预算控制,以及一套可以落地的成本排查与监控方案。
1. 为什么 Codex 的 Token 消耗总是“看不见上限”
先纠正一个常见误解:很多人以为 Codex 的 Token 消耗等于“模型解答问题时生成的文字量”。实际上,模型收费的对象不只是输出内容,还包括每一次请求时发送给模型的全部输入内容。
举个例子。你在终端里执行一次 Codex 任务,告诉它“帮我看看这个项目里登录模块的 bug”。Codex 收到的不只是这句话,它可能还要附带上:
- 系统内置的指令和工具说明;
- 你当前工作区的文件列表、Git 状态、相关代码片段;
- 前面几轮对话已经产生的历史记录;
- 模型检测到的项目配置、AGENTS.md 或类似的项目级提示文件。
这些内容加起来,往往比你的问题本身大几十倍。一次两次看不出问题,但如果一个任务需要连续迭代 10 轮,每一轮都会把之前所有的对话内容重新发送一遍。Token 的消耗是指数级叠加的,不是线性的。
从材料来看,很多 Codex 用户遇到的问题并不只是“用量大”,还包括登录态失效、Token 刷新失败、403 地区限制提示等。这些属于认证与网络层面的问题,后面会单独讲。但绝大多数“Token 不够用”的核心原因,其实是使用习惯问题:会话开得太久不清理,代码反复粘贴,任务描述一次说太多无关细节。
所以,省 Token 的第一步不是心疼模型,而是先看清钱到底花在了哪里。
2. 前置认知:Token、上下文窗口与 Prompt 缓存
2.1 Token 到底是什么
Token 是语言模型处理文本的基本单位。它可以是一个单词的一部分、一个标点、一个汉字,甚至一个空格。对于英文文本,通常一个 Token 约等于 0.7 到 1 个单词;对于中文文本,一个汉字大约对应 0.6 到 0.8 个 Token,具体取决于模型使用的分词器。
对于 Codex 这种编程场景,代码里的缩进、换行、括号、注释都会被拆分。看起来不起眼的空行和大段注释,累计起来会消耗大量 Token。
2.2 上下文窗口的三种角色
模型处理文本的空间叫做上下文窗口(Context Window),它分为三个部分:
| 部分 | 说明 | Token 消耗特征 |
|---|---|---|
| System Prompt | 系统级指令,决定模型行为方式 | 每次请求都会计入,且通常不可压缩 |
| 用户输入与工具结果 | 你提供的任务、代码、文件内容、命令输出 | 这部分是变量最大的来源 |
| 模型输出 | 模型生成的回答、代码、修改建议 | 可以通过限制输出长度来控制 |
上下文窗口不是“无限聊天记录”,而是每一轮都会完整发送的数组。这是许多人忽略的关键:你以为在“继续对话”,实际上是在不断复制粘贴全部历史。
2.3 利用 Prompt 缓存省钱
主流模型接口普遍支持 Prompt Caching 机制:如果多次请求使用相同的前缀内容,服务商可以对该部分缓存,缓存命中的输入 Token 费用通常显著低于未命中。
这意味着:如果你能让对话的前缀保持不变,或者让多轮请求共享相同的系统提示符和项目说明,那么大量 Token 会以更便宜的价格计费。反过来,如果每次请求前都无意义地调整 System Prompt 或重新贴一段内容,缓存就永远命不中,成本自然居高不下。
3. 技巧一:从会话层面控制上下文膨胀
3.1 一个任务一个会话,别让 Codex “带病工作”
Codex 的长期会话会积累大量历史。假设你上午 10 点开始排查一个 bug,过了两个小时又把 Codex 叫来写一个新模块,此时它还记得上午的排错过程。这些老内容不仅没有帮助,还会抢占上下文窗口,让模型在无关信息里找重点。
最朴素也最有效的做法是:换任务就换会话。如果你是重度终端用户,不要舍不得关掉当前会话。重新开一个会话的成本,比让模型带着几十轮历史继续工作低得多。
# 查看当前 Codex 会话状态 codex status # 启动一个新会话(具体命令以你安装的版本为准) codex # 如果某次任务已经结束,直接退出并重启会话 exit3.2 主动清理历史与压缩上下文
如果任务确实很长、不适合完全重开,可以采用分段会话策略:把一个大任务拆成几个阶段,每个阶段完成后清空上下文,只保留必要的结论。很多 Codex 工具支持会话压缩或重置命令,实际使用前可以先执行codex --help查看自己的版本支持哪些命令。
清理历史时可以遵循一个原则:只把与当前步骤直接相关的文件和描述喂给模型。比如刚完成了登录模块的 bug 修复,下一步要写单元测试,就应该把登录模块的核心代码路径传给 Codex,而不是把整个项目的全部文件都丢进去。
3.3 少闲聊,多下指令
Codex 不是聊天机器人,它更适合被当作“执行具体任务的工程师”。每次对话里加入“你觉得怎么样”“帮我分析一下原因”“你明白我的意思吗”这类模糊表达,不仅不会提高回答质量,还会让模型输出大量过渡性内容,白白消耗 Token。
在实操中,更推荐直接用动词开头的短句告诉它要做什么:
在 src/auth/login.ts 中修复登录超时未抛出自定义异常的问题 不要修改其他文件 完成后运行 npm test 验证相比之下,这种描述比“我这边登录超时了,你帮我看看是什么原因,然后看看能不能改一下,顺便跑一下测试”少消耗很多 Token,而且结果更可控。
4. 技巧二:精简 System Prompt 与项目说明文件
4.1 AGENTS.md 写太多反而费钱
现在很多 AI 编程工具支持项目级说明文件,比如AGENTS.md。这个文件里的内容会随每次请求一起发送给模型,也就是说,它里面的每一行都会变成 Token 账单上的数字。
很多团队会把 AGENTS.md 写得像一本手册:公司历史、团队文化、编码规范全抄进来、甚至还有几十条“禁止事项”。这些内容模型虽然能读,但属于稀缺的上下文资源。
一个比较合理的 AGENTS.md 应该只回答三个问题:
- 这个项目的构建、测试、运行命令是什么;
- 项目结构和约定有哪些模型必须知道的硬约束;
- 有哪些文件绝对不能动、有哪些目录是生成出来的。
优化前:
# 项目说明 这是一个电商系统的前端仓库。 我们团队使用 React 18,由前端架构组统一维护状态管理方案。 所有组件都放在 src/components 下面,页面放在 src/pages 下面。 如果遇到任何问题,请优先查看 README.md 或者联系 @前端负责人。 请注意,我们使用 pnpm 而不是 npm,也不要用 yarn。 构建命令是 pnpm build,测试命令是 pnpm test,类型检查是 pnpm typecheck。 不要修改 src/constants 下任何文件,这些是业务常量。 如果有 ESLint 报错,先看是不是自动修复能解决。优化后:
# 项目说明 - 包管理器:pnpm(不要使用 npm / yarn) - 构建:pnpm build - 测试:pnpm test - 类型检查:pnpm typecheck - 禁止修改:src/constants 下 的常量文件 - 组件路径:src/components,页面路径:src/pages同样一份信息,后者的 Token 消耗可能只有前者的三分之一。能直接给结论,就不要给背景故事。
4.2 系统提示词也要做减法
如果你通过 Codex API 或自定义配置调用模型,系统提示词同样影响每次请求的成本。系统提示词可以精简为三层:
- 角色层:一句话说明模型的职责范围;
- 操作层:只写输出格式、禁止行为等硬性要求;
- 信息层:不放具体代码,只放路径索引。
一个容易踩的坑是:有人为了让模型“更懂项目”,把一大段业务背景写进系统提示词,结果每次请求都背着这份背景。背景知识如果只在个别任务里用得到,就应该放进任务描述,而不是全局提示词。
5. 技巧三:改用“增量式任务描述”,避免重复粘贴代码
5.1 一次只让它读该读的文件
初级用户最常见的浪费是:把整个文件甚至整个目录的代码复制粘贴到对话里,然后说“帮我改”。这种方式不仅消耗大量 Token,而且会让模型面对过多无关代码,反而降低修改质量。
推荐的做法是:用文件路径代替代码全文,让 Codex 自己去读。Codex 本身具备文件读取能力,只要项目文件在它的访问范围内,你给出路径和明确的修改目标即可。
codex "修改 src/services/order.ts 中的 createOrder 方法,加入库存校验逻辑"如果任务是让 Codex 搜索代码,同样不需要把搜索到的内容全部贴回来。让它直接修改目标文件并汇报改动点,而不是把大段代码复制到对话里讨论,这样更省。
5.2 任务描述要“增量”,不要“全量重述”
很多人在多轮任务里会重复描述背景。比如第一轮已经说了“我在做一个订单管理系统,使用 React 和 TypeScript”,第二轮又开始说一遍。这种重复对模型理解没有帮助,却会让 Token 消耗翻倍。
正确的增量式描述应该默认 Codex“还记得”上一轮的结论,只补充当前步骤的变化:
继续,现在给 createOrder 增加一个订单状态字段,默认值为 pending这样一句话就够了。背景信息只在会话开头给一次,后续都以“继续”开头,而不是重新叙述背景。
5.3 不要用“长对话”对抗“短记忆”
有一种错误用法:用户担心 Codex 忘记需求,于是不断在每轮请求里复述需求。这会让上下文越来越长、成本越来越高,但模型“记得住”的能力并不会变得更好。
更合理的做法是:把核心需求写进项目级说明文件或者一个独立的需求文档,然后在任务描述里直接引用文件路径。这样即使会话中途换模型或清理上下文,需求也不会丢。
6. 技巧四:选对模型、限制输出、利用前缀缓存
6.1 模型选择直接影响成本
不同模型的价格差异很大。对于简单任务,使用轻量级模型往往已经足够;只有处理复杂推理、架构设计和多文件重构时,才需要调用更强的模型。如果你只是让 Codex 补全函数、写单元测试或格式化代码,却默认使用最强模型,成本会明显偏高。
从社区讨论看,Codex 接入第三方模型(如 DeepSeek)也是不少开发者尝试的方向,这样可以用更低的单价完成类似任务。但需要注意兼容性问题:不是所有模型都支持 Codex 的工具调用格式,接入前要先确认模型对 function calling 的支持情况。
6.2 用输出限制防止“废话连篇”
模型生成完代码后,往往会惯性输出一段“这段代码实现了以下功能”之类的总结。这些输出同样消耗 Token。可以通过配置或提示词约束输出格式。
# config.toml 示例,字段以你使用的 Codex 版本为准 model = "gpt-5.4" # 换成你实际可用的模型名称 model_provider = "openai" approval_policy = "on-request"在配置或提示词中明确要求“不要输出解释,只输出代码”,可以有效减少模型生成无意义文字的比例。
只输出修改后的文件内容,不要解释、不要总结、不要给出额外建议6.3 前缀稳定,缓存才能命中
前面提到过 Prompt Caching。要让缓存生效,需要保持系统提示词和项目说明稳定。换句话说:
- 不要每次请求都调整 AGENTS.md 的措辞;
- 多轮会话中,前缀尽量保持不变;
- 避免在会话中途插入大段与任务无关的对话。
一个常见的反模式是:用户每轮在对话开头加一句“忽略我上面说的话,现在开始新任务”。这相当于强制让缓存前缀发生变化,不仅不能省钱,还可能让模型更困惑。
7. 实战示例:一次代码重构任务的优化前后对比
7.1 优化前的做法
假设现在要完成一个任务:重构src/utils/format.ts中的日期格式化函数,让它支持时区参数。
优化前的任务描述可能是这样:
我这边有一个日期格式化工具文件,路径是 src/utils/format.ts。 里面有个 formatDate 函数,现在不支持时区参数。 我想让它支持传入 timezone,然后根据时区输出对应的时间。 这个函数很多地方在用,所以不能破坏原来的功能。 另外有测试文件在 src/utils/__tests__/format.test.ts,你改完之后记得跑一下测试。 哦对了,项目用的是 Jest,测试命令是 npm test -- format。 如果你看到别的地方也用了这个函数,能不能也检查一下有没有受影响? 如果时间充裕,顺便把文档注释也更新一下。这段描述包含了大量冗余信息:文件路径重复出现、额外附带“如果时间充裕”这类模糊指令、还让模型自行决定检查范围。这会导致模型不必要地读取多个文件、输出更多解释,Token 消耗自然偏高。
7.2 优化后的做法
同样任务,可以拆成两步:
第一步:
codex "修改 src/utils/format.ts 中的 formatDate,新增可选参数 timezone,默认值为 'UTC',不能改变现有调用方式的返回值格式。只改这一个文件。"第二步:
codex "补充 src/utils/__tests__/format.test.ts 中关于 timezone 参数的测试用例,运行 npm test -- format 验证通过。"两步分开,任务边界清晰,模型不需要在一轮里同时处理修改、测试、全局影响分析和文档更新。Token 节省不是来自少干活,而是来自不干多余的活。
7.3 为什么在某些场景下能接近 80%
80% 这个数字并不是在所有场景下都能达到。当你执行的任务是“长历史会话 + 重复上下文 + 模型额外输出”的组合时,优化空间巨大。比如:
- 一个会话持续了 30 轮,每轮都携带 2 万 Token 的历史背景;
- 用户每轮重新粘贴 300 行代码,而实际上只需要其中 20 行;
- 模型每轮都生成大段解释性文字。
这种情况下,从会话清理、提示压缩、输出限制三个方向同时优化,80% 是合理的期望。但如果你的任务是单轮短对话、模型输出本身就很少,那能省的空间就没有那么夸张。把 80% 理解为一个方向,而不是一张保证达到的支票。
8. Codex 登录、Token 失效与网络报错排查
8.1 为什么明明 Token 失效的不是 API Key
很多用户把开发中遇到的 “Token Exchange Failed” 和模型计费里的 Token 混在一起,其实这是两回事。Codex 登录时的 Token 是 OAuth 认证令牌,用于确认用户身份;模型计费里的 Token 是文本切分单位。
从社区反馈看,这些报错信息出现频率比较高:
token exchange failed: error sending requesttoken endpoint returned status 403 forbidden: countryfailed to refresh token: 400 bad requestsign-in could not be completed token exchange failed
这类问题的核心是认证流程无法完成,与对话内容的 Token 消耗无关。出现这些问题时,优先检查的不是“是不是我说太多了”,而是登录态和网络环境。
8.2 常见认证失败排查表
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
登录时报error sending request | 网络连通性异常,无法访问认证服务 | 检查当前网络能否访问官方登录域名 | 切换网络环境,或检查系统代理设置是否正确 |
返回 403,提示forbidden: country | 所在地区不在服务允许范围内 | 查看认证服务返回的错误码和地区限制说明 | 确认所在地区是否在官方支持范围内,或联系团队管理员确认合规访问方式 |
failed to refresh token | 本地保存的刷新令牌过期或失效 | 查看本地认证缓存文件,确认登录时间 | 手动退出后重新登录,重新走一遍 OAuth 流程 |
| 登录成功但无法加载组织设置 | 组织权限或会话缓存异常 | 检查账号是否有对应组织访问权限 | 重新登录并确认组织授权范围 |
8.3 一个稳妥的重置流程
遇到认证问题时,最稳妥的做法是按顺序逐步重置,而不是反复点击登录按钮:
# 1. 查看当前登录状态 codex login status # 2. 退出当前账号(命令以你的 Codex 版本为准) codex logout # 3. 清除本地残留缓存后重新登录 codex login如果退出重新登录后仍然报错,检查一下系统的日期时间是否准确。OAuth 令牌对时间偏差很敏感,本机时间不准确会导致令牌签名验证失败。
这里要特别提醒:不要为了绕过地区限制而使用未经授权的访问工具。更合理的做法是查看官方支持地区列表,结合团队实际部署情况选择合规的使用方式。
9. 工程化建议:把 Token 消耗纳入开发流程管理
9.1 用脚本估算输入 Token
在生产实践中,可以在调用 Codex 前先对任务描述做一次 Token 估算,提前发现“这条 prompt 太重”的问题。使用tiktoken库可以快速估算文本的 Token 数量:
# estimate_tokens.py import tiktoken def estimate(text: str, model: str = "cl100k_base") -> int: enc = tiktoken.get_encoding(model) return len(enc.encode(text)) if __name__ == "__main__": prompt = open("prompt.txt", encoding="utf-8").read() print(f"估算 Token 数:{estimate(prompt)}")这个脚本的价值不在于精确计费,而在于让开发者对“一句话到底值多少 Token”有一个体感。当你把一段 500 字的任务描述压缩到 100 字时,就能直观看到 Token 数量的下降。
9.2 记录每次请求的用量
如果是通过 API 调用 Codex,响应结果里通常包含usage字段。把它记录下来,按项目和会话维度聚合,就能看清哪个模块消耗最多。
# 示例:在脚本中保存响应信息(伪代码) codex run "你的任务" --output-format json | jq '.usage'通过长期记录,你会发现 Token 消耗往往集中在少数几个高密度任务里。针对这些任务做专项优化,比全面压缩所有对话更有效。
9.3 团队协作层面的省钱规范
如果团队多人使用 Codex,建议在项目说明里加一条使用规范:
- 每个任务必须对应一个新会话;
- 不要粘贴超过 50 行的代码块,改用文件路径;
- 模型输出指定为“只输出代码”或“只输出结论”;
- 每周检查一次 Token 用量统计,寻找异常高的会话。
这些规范不需要强制执行,只要让每个使用者意识到“上下文是有成本的”,就能大幅降低整体消耗。
10. 总结
回头看,Codex 省 Token 的核心不是玄学,而是四件事:控制会话长度、精简系统提示词、使用增量式任务描述、限制模型输出。这四件事单独拿出来都不复杂,但组合起来,足以在常见的多轮开发场景里省下大量 Token。需要承认的是,80% 是一个在特定条件下成立的目标,不是每个任务都能达到。真正值得做的,是建立“上下文成本”意识,把省 Token 从偶尔一次的操作变成一套使用习惯。
如果你下次打开 Codex 时发现额度又不够用了,先别急着换模型或开新账号。检查一下自己的会话历史有多长,看看自己是不是又把整份代码贴进了对话里。答案往往就在那里。