我终于把 Codex 的 token 用量扒出来了:用 Python + tiktoken 拆解 CLI 账单,最贵的不是输出

发布时间:2026/10/4 11:21:42
我终于把 Codex 的 token 用量扒出来了:用 Python + tiktoken 拆解 CLI 账单,最贵的不是输出 1. Codex CLI 账单为什么总对不上token 成本结构拆解用 Codex CLI 写代码久了很容易产生一个错觉输出越长越贵。我一开始也这么想直到把本地会话日志翻出来逐条统计才发现真正吃掉额度的是输入侧那一大坨上下文尤其是缓存命中的部分。Codex 改成 token 计费之后这个问题变得更敏感——你每天到底用了多少、花在哪光看 CLI 界面那点提示根本看不出来。Codex CLI 的计费结构大致分三块输入 token、缓存输入 token、输出 token。输出单价最高但单次请求里输出通常只占很小比例输入才是大头因为每次请求都要带上系统提示、工具 schema、历史对话、文件上下文。如果开了长任务或者 agent 模式历史会不断累积输入量会滚雪球。缓存命中能把这部分成本压下来但前提是你得知道命中率是多少。问题在于Codex CLI 本身不给你一份清晰的账单。它只在会话日志里埋了token_count事件格式是 JSONL散落在~/.codex/sessions/下面。你要想知道今天用了多少、哪个任务组最烧得自己把这些日志扒出来做聚合。这就是我写统计脚本的起点。这篇要解决的问题很具体给你一套可复制的 Python tiktoken 离线统计方案把 Codex CLI 本地会话记录拆成输入、缓存、输出三档算出每档的 token 量和占比再配合任务组快照做费用归因。同时说明怎么把 Codex 的 endpoint 指到 TaoToken让用量在一个地方统一看。适合已经在用 Codex CLI、想搞清楚钱花在哪的开发者。先说清楚边界这套方案读的是本地日志里已经存在的 token 数不是重新请求 API 算的所以它是估算归因不是官方账单。tiktoken 只在手动导入 transcript 时用来做文本分词估算。两者分工不同后面会分别讲。2. TaoToken 前置把 Codex endpoint 统一到一处看用量在开始写统计脚本之前建议先把 Codex CLI 的请求出口统一到 TaoToken。原因很简单本地日志统计的是你这边发了多少但如果你同时用多个 key、多个 endpoint账单会散在好几个地方归因就断了。统一到 TaoToken 之后本地统计和平台用量能对上排查异常也方便。TaoToken 的 API 地址是https://taotoken.net/api官网入口在https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content。你需要先去控制台拿一个 API Key地址是https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite。拿到 key 之后Codex CLI 的配置入口在~/.codex/auth.json这个文件同时管 Base URL、Key 和 Model ID 三件套。Codex CLI 读取auth.json的字段名在不同版本略有差异常见的是OPENAI_API_KEY和OPENAI_BASE_URL。如果你用的是较新的版本可能还会看到base_url或api_base这种写法。最稳妥的做法是先跑一次codex --version确认版本再对照官方文档改。接入文档在https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite里面有各版本对应的字段说明。改完之后Codex CLI 的所有请求都会走 TaoToken你在控制台就能看到统一的用量曲线。这时候再跑本地统计脚本两边数据能互相印证本地日志算出来今天输入 800 万 token平台显示消耗也对得上说明统计逻辑没问题如果对不上大概率是日志里有你没统计到的事件类型或者缓存字段没解析对。有一点要注意auth.json里如果同时存在旧的 endpoint 配置Codex 可能会优先读旧的。改完之后建议把文件备份一份然后清掉旧字段只留 TaoToken 的 Base URL 和 Key。改完跑一次codex exec print hello做冒烟测试能正常返回就说明接入成功。如果你还想在网页端直接对话验证模型是否正常可以用模型对话入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite。长期跑编码任务或者 agent 的话Coding Plan 更划算入口在https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite。3. 可复制配置auth.json 与统计脚本 settings 片段这一节给两份可直接复制的配置。第一份是 Codex CLI 的auth.json第二份是统计脚本的config.json。两份都按实际路径写你复制过去改 key 就能用。先看~/.codex/auth.json。这个文件是 JSON 格式注意不要写成 TOML。字段名以你当前 Codex 版本为准下面这份是较通用的写法{ OPENAI_API_KEY: sk-你的TaoToken密钥, OPENAI_BASE_URL: https://taotoken.net/api, model: gpt-5-codex }如果你用的是支持base_url字段的版本把OPENAI_BASE_URL换成base_url即可值不变。Model ID 按你实际用的填Codex 系列常见的是gpt-5-codex具体以接入文档里的模型列表为准。改完记得chmod 600 ~/.codex/auth.json避免权限过宽。再看统计脚本的config.json。这个文件放在项目根目录和codex_logs.py同级。它管三件事日志目录、tiktoken 编码、任务组存储路径。{ codex_log_dir: ~/.codex/sessions, tiktoken_encoding: o200k_base, storage_dir: .codex-usage, default_model: gpt-5-codex, timezone: Asia/Shanghai }tiktoken_encoding这个字段很关键。tiktoken 支持多种编码常见的有cl100k_baseGPT-3.5/4 系列和o200k_baseGPT-4o 及更新系列。Codex 系列模型一般用o200k_base如果你不确定可以跑一段代码探测import tiktoken def pick_encoding(model_name: str) - str: try: enc tiktoken.encoding_for_model(model_name) return enc.name except KeyError: return o200k_base print(pick_encoding(gpt-5-codex))这段代码会返回模型对应的编码名。如果模型不在 tiktoken 的映射表里就回退到o200k_base。注意 tiktoken 的版本要0.7.0低版本可能不认识新模型。storage_dir是任务组数据的存放位置脚本会在里面生成groups.jsonl、snapshots.jsonl、turns.jsonl三个文件。JSONL 的好处是每行一条记录追加写不会破坏已有数据出问题也好手动修。配置写完之后跑一次初始化python -m codex_usage.cli doctor --config config.jsondoctor会检查日志目录是否存在、tiktoken 能否加载、存储目录是否可写。三项都通过再往下走。4. 验证请求跑通统计脚本并核对成功结果配置就绪后先跑一次最小验证确认脚本能读到日志、能算出数。命令是python -m codex_usage.cli codex report --today --lang zh --config config.json这条命令做四件事扫描~/.codex/sessions下当天的 JSONL 日志、提取token_count事件、按时间窗口取 delta、汇总成终端表格。输出大概长这样日期: 2025-XX-XX 请求数: 142 输入 token: 8,432,100 缓存输入 token: 7,910,300 (93.8%) 输出 token: 521,800 (6.2%) 合计: 8,953,900看到这个结果先别急着下结论。重点看缓存输入占比。如果缓存占比超过 90%说明你的请求大量复用了历史上下文这通常出现在长任务或 agent 模式里。如果缓存占比很低说明每次请求都在带全新上下文成本会高很多。接下来验证 tiktoken 那条线。手动导入一段 transcriptpython -m codex_usage.cli turn add \ --group repo-refactor \ --file transcript.md \ --config config.jsontranscript.md里用注释标记角色脚本会按标记分段估算!-- codex-usage:user -- 帮我把这个函数改成异步的 !-- codex-usage:assistant -- 好的这是改后的版本... !-- codex-usage:tool -- pytest 运行结果3 passed !-- codex-usage:file-context -- src/service.py 全文 200 行导入后跑turn list --group repo-refactor会看到每段的 token 估算值。这里 tiktoken 的作用是把可见文本转成 token 数它不知道 Codex 内部真实请求带了多少隐藏内容所以这个数是下限估算。最后做任务组快照验证。任务开始前记一次用量结束后再记一次python -m codex_usage.cli snapshot --group repo-refactor --usage 42 --config config.json # ... 跑任务 ... python -m codex_usage.cli snapshot --group repo-refactor --usage 47 --config config.json然后group show repo-refactor会输出这个任务组的汇总turn 数、估算请求数、工具调用次数、可见 token 估算、有效 token 估算、用量变化、每 1% 对应多少可见 token。最后这个指标最有用它帮你建立1% 额度大概等于多少 token的经验值。成功结果的判断标准有三条当天报告能出数、transcript 导入能分段、任务组快照能算出每 1% 对应 token。三条都过说明统计链路是通的。5. 常见错排查401、local proxy failed、reading choices 与 OAuth统计脚本跑起来之后报错主要集中在接入侧和解析侧。下面按真实报错逐条给排查路径。401 Unauthorized。这个最常见出现在 Codex CLI 请求阶段不是统计脚本的问题。原因通常是auth.json里的 key 失效或 Base URL 写错。先确认 key 有没有多余空格再确认 Base URL 是https://taotoken.net/api而不是带路径的完整地址。如果 key 是从控制台复制的注意别把前后引号也复制进去。改完跑codex exec print hello验证。local proxy failed。这个报错说明 Codex CLI 尝试走本地代理但连不上。检查环境变量里有没有残留的HTTP_PROXY或HTTPS_PROXY有的话先清掉。另外确认auth.json里没有指向本地端口的 Base URL。如果你之前配过别的 endpoint旧配置可能还在生效把auth.json清空重写一遍。reading choices 相关报错。这个出现在统计脚本解析日志时通常是日志格式和脚本预期不一致。Codex 不同版本的token_count事件字段名可能有差异比如input_tokens和prompt_tokens混用。打开一条原始日志看一眼实际字段名然后对照codex_logs.py里的解析逻辑改。如果字段缺失脚本会跳过该条记录不会崩但统计数会偏小。OAuth 相关报错。Codex CLI 某些版本支持 OAuth 登录如果你之前用 OAuth 登录过auth.json里可能有 token 字段和 API Key 字段并存。这种情况下 Codex 可能优先走 OAuth导致你的 TaoToken key 不生效。解决办法是把 OAuth 相关字段删掉只留 API Key 和 Base URL。删之前备份文件。tiktoken 加载失败。报错通常是Unknown encoding或KeyError。先确认 tiktoken 版本pip show tiktoken低于 0.7.0 就升级。如果版本没问题检查config.json里的tiktoken_encoding是不是拼错了。o200k_base和cl100k_base是最常用的两个别写成o200k或cl100k。统计数和平台对不上。这个不算报错但很常见。原因通常是本地日志只记录了部分事件或者缓存字段没解析。先确认脚本版本和 Codex 版本匹配再检查日志目录是不是有多个 session 文件没被扫到。如果差异在 5% 以内属于正常范围差异超过 20%就要逐条核对日志字段。排查顺序建议先保证 Codex CLI 能正常请求401 和 proxy 问题在这一层解决再保证统计脚本能读到日志reading choices 和 tiktoken 问题在这一层解决最后核对两边数据。三层分开排查比一上来就混着看效率高。6. 语义一致 CTA把用量归因变成日常习惯统计脚本跑通之后最有价值的不是某一天的数字而是持续记录形成的经验表。我自己的做法是每天收工前跑一次codex report --today把输入、缓存、输出三档记下来周末做一次汇总。跑了两周之后基本能判断出今天这个用量算正常还是异常。如果你还没接入 TaoToken建议先把 endpoint 统一过去这样本地统计和平台用量能互相印证。API Key 在https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite拿接入文档在https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite。想先在网页端验证模型是否正常用模型对话入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite。长期跑编码任务或 agentCoding Plan 入口在https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite。最后给一个实用技巧把codex report --today加到你的 shell 启动脚本里每天第一次开终端时自动跑一次。这样你不用记着去查用量异常会第一时间暴露出来。统计这件事频率比精度重要——每天看一眼比一个月后翻账单有用得多。