Codex Token统计Skill实战:一句话打开每日用量看板

发布时间:2026/9/12 12:23:40
Codex Token统计Skill实战:一句话打开每日用量看板
我用 Codex 快一年了重度使用的情况下每个月花在 Token 上的钱不比一杯咖啡便宜。真正让人焦虑的不是花多少而是你根本不知道它怎么花掉的——每次对话结束Codex 只会告诉你这轮用了多少 token但你要看今天、这个月、哪个项目烧得最狠基本靠猜。后来我写了一个 Skill让 Codex 用一句话就能打开每日用量看板彻底解决了这个黑箱问题。这篇文章把整个升级过程拆开讲清楚从为什么用 Skill 而不是外部脚本到 SKILL.md 怎么设计、统计脚本怎么写、部署时踩了哪些坑全部记录下来。适合两类人看一类是天天用 Codex 写代码但没仔细算过成本的人另一类是打算给 Codex 集成自定义 Skill、想找个完整案例参考的开发者。1. 为什么你急需一个 Token 统计 Skill1.1 用量焦虑看不见的 token 在烧钱大多数人用 Codex 的方式是“有问题就问”一条任务可能来回跑几十轮每轮都会把上下文重新拼进模型里。你以为自己只写了一百行代码实际上模型把整个项目的目录结构、过往对话、工具输出全部读了一遍——这些都要算 token。Codex 的计费逻辑是按“输入 输出”总量走的上下文越长单轮成本越高。更麻烦的是Codex 的会话记录分散在本地目录里官方界面只管展示“本次会话用了多少 token”没有给你一个“今天总共花了多少”的汇总视角。你一个月结束看到账单才发现咦怎么超了这么多那时候已经来不及省了。我个人的经验是用量统计必须每天都看就像记账一样一旦变成月末回头看就等着被数字吓一跳。1.2 为什么选择 Skill 而不是外部脚本有人可能会说想统计 token写个 Python 脚本不就行了为什么非要绕一圈做成 Skill区别在于使用场景。外部脚本你得在终端里手动跑到文件夹、找到正确的文件、执行命令然后盯着输出看。对技术人来说这一套不算难但问题是——你总是会忘记跑。人会偷懒这是常态。做成 Skill 之后就不一样了。Skill 的本质是给 Codex 注入一套“行为预设”让它在特定触发条件下自动执行一组操作。你不需要记住脚本路径不需要翻历史命令只要在对话里说一句“打开每日用量看板”剩下的全部交给 Codex。还有一个更重要的点直接让 Codex 读取本地文件、计算数据往往会出现格式不稳定的问题。用 Skill 把统计逻辑固化下来每次得到的结果都是同一套口径不会这次按 session 算、下次按 usage 字段算。对于做记录、做对比来说口径一致比什么都重要。1.3 升级前的老方案痛点我在做这个 Skill 之前用的是最原始的方式手动打开 Codex 的会话目录用jq和awk现场拼命令把 JSONL 里的 usage 字段捞出来求和。这套做法有几个明显的问题。首先是麻烦每次都要回忆一遍 JSONL 的结构时间一长根本不记得哪个字段代表输入 token、哪个代表输出 token。其次是容易出错Codex 的会话文件偶尔会写入不完整的 JSON 行jq一碰到解析失败就整个挂掉你还得单独处理容错。最关键的是手动命令只能告诉你“总数”给不了“每天的趋势”。而用量管理最需要的就是趋势周一为什么爆了是不是那天跑了几个超大任务这些信息一旦变成历史再去查就很费劲。所以升级的方向很清楚把统计逻辑固化成 Skill用自然语言触发输出结构化的每日用量看板。2. 升级设计一句话触发的用量看板2.1 核心思路与交互设计整个 Skill 的设计目标我定成了三条硬性要求只用一句话触发不需要额外参数统计结果必须按“日期”分组而不是按会话输出必须直接可读不能再套一层工具去解析交互上我参考了 Claude Code 的 Skill 机制——一个 Skill 对应一个文件夹里面必须有SKILL.md作为说明书其他辅助脚本放在同目录下。Codex 读到这里有 Skill 定义会把这套能力注册进上下文用户只要提到“用量”“token 统计”这类关键词就会自动触发。为什么强调“一句话”因为使用频率越高的操作进入门槛越低越好。如果每次都要给 Codex 解释“你去看哪个文件、用什么脚本、输出什么格式”那和手动敲命令没有区别Skill 就失去了意义。2.2 数据从哪里来本地会话记录解析Codex 在本地会保存每一条会话记录通常是 JSONL 格式一行一条消息事件里面包含多个字段其中就有usage对象记录着input_tokens和output_tokens之类的数据。这里有个容易混淆的点不是所有行都有usage。大部分用户消息、工具调用消息都不带用量信息只有模型响应那一条才携带。所以统计脚本不是把每一行都拿过来累加而是要识别出“这一行是模型完成响应并且带 usage 字段”再把它取出来。不同操作系统的会话目录路径不一样这是部署时最容易踩的坑。我把路径探测逻辑直接写在脚本里优先读取系统环境变量找不到就按常见默认路径去匹配这样换了电脑也能直接跑。2.3 看板展示什么从总量到每日趋势我设计的看板分三块内容区块展示内容解决的痛点总览总 token 数、总会话数、估算金额快速判断今天是不是“超标”了按日分组每日 token 消耗柱状图终端渲染看趋势找出峰值日期按项目/角色分组不同角色消耗排序判断是编码任务多还是聊天任务多其中最实用的就是“按日分组”。Codex 的会话文件命名通常带有时间戳可以直接从文件名或文件内首条消息的时间提取日期。按天聚合后再用简单的print拼字符画柱状图——不需要引入任何第三方图形库终端里完全够用。3. 核心实现SKILL.md 与统计脚本拆解3.1 Skill 的文件结构与触发词定义一个完整的 Skill 目录长这样~/.codex/skills/token-stats/ ├── SKILL.md ├── token_stats.py └── requirements.txtSKILL.md是这个 Skill 的入口。Codex 通过它识别你安装了什么能力里面要写清楚这个 Skill 是干什么的、什么时候触发、怎么用。建议加上若干触发词让模型更容易命中。下面是我整理过的SKILL.md内容省略了部分注释核心结构如下--- name: token-stats description: 统计 Codex Token 用量按天汇总输出看板 triggers: - 用量 - token 统计 - token 用量 - 每日用量 - usage --- # Token 统计 Skill 当用户请求查看 Codex Token 用量或每日用量看板时执行本 Skill。 步骤 1. 定位 Codex 会话记录目录 2. 运行 token_stats.py 3. 将脚本输出的表格直接展示给用户注意里面我特意写了“将脚本输出的表格直接展示给用户”——这是对模型行为的约束。没有这一句模型很可能自己编一个表格出来而不是老老实实跑脚本。3.2 Token 统计字段与计算逻辑统计脚本是整个 Skill 的核心。下面这个是我的实际实现略作精简它做的事情是遍历会话目录下所有 JSONL 文件提取带usage字段的消息按天聚合 token 消耗。#!/usr/bin/env python3 import json import os from pathlib import Path from collections import defaultdict from datetime import datetime # 可以自定义路径默认按常见位置查找 HOME Path.home() CANDIDATE_DIRS [ Path(os.environ.get(CODEX_SESSIONS_DIR, )), HOME / .codex / sessions, HOME / .codex / log, ] def find_sessions_dir(): for d in CANDIDATE_DIRS: if d.exists(): return d raise SystemExit(未找到 Codex 会话目录请检查路径) def parse_date_from_file(path: Path) - str: 优先从文件名里提取日期兜底用文件的修改时间 try: parts path.stem.split(_) date_part parts[0] if parts else datetime.strptime(date_part, %Y-%m-%d) return date_part except (ValueError, IndexError): ts path.stat().st_mtime return datetime.fromtimestamp(ts).strftime(%Y-%m-%d) def main(): sessions_dir find_sessions_dir() daily defaultdict(lambda: {input: 0, output: 0, sessions: 0}) total {input: 0, output: 0, sessions: 0} for path in sessions_dir.glob(*.jsonl): date parse_date_from_file(path) daily[date][sessions] 1 try: with open(path, r, encodingutf-8) as f: for line in f: line line.strip() if not line: continue try: obj json.loads(line) except json.JSONDecodeError: continue usage obj.get(usage) if isinstance(usage, dict): inp usage.get(input_tokens, usage.get(input, 0)) or 0 out usage.get(output_tokens, usage.get(output, 0)) or 0 daily[date][input] inp daily[date][output] out total[input] inp total[output] out except Exception as e: print(f警告{path.name} 读取失败 - {e}) print( * 48) print(fCodex Token 用量看板总计 {len(daily)} 天) print( * 48) print(f总 Token: {total[input] total[output]:,}) print(f输入 Token: {total[input]:,}) print(f输出 Token: {total[output]:,}) print(f会话总数: {total[sessions]}) print(- * 48) print(f{日期:12}{输入:12}{输出:12}{合计:14}) for d in sorted(daily.keys(), reverseTrue): row daily[d] total_day row[input] row[output] print(f{d:12}{row[input]:12,}{row[output]:12,}{total_day:14,}) if __name__ __main__: main()这段代码有几个值得说的细节。第一个是容错。JSONL 文件数量多了之后偶尔会出现某一行写坏的情况比如断电、进程被杀。如果不做try/except脚本会挂在第一个坏行上。这里的选择是“能跳就跳不影响整体统计”。第二个是字段兼容性。不同版本的 Codex 对 usage 的字段名并不完全一致有的叫input_tokens有的叫input还有的嵌套在别的地方。我同时兼容了两种最常用的写法遇到都没有的情况就归零而不是直接报错。3.3 看板输出与终端渲染脚本的输出我特意做成了“冷静但清晰”的风格。第一行是汇总紧接着是每天的明细表格。列宽对齐用的是 Python 的格式化字符串12表示右对齐、宽度 12数字大一些也不会错位。有人会问为什么不直接生成 HTML 或者图片因为 Skill 的定位是“对话内快速查看”输出到终端已经足够。真想做可视化排名可以把脚本改成输出 CSV再接入自己的报表系统。我建议不要在 Skill 里塞太重的图形依赖。Python 的rich、plotly是好看但每次执行都要加载一堆东西响应速度会变慢在终端里反而显得累赘。4. 实操部署5分钟接入你的 Codex4.1 手动安装 Skill 到配置目录部署步骤其实非常简单核心就是把你的 Skill 文件夹放到 Codex 能找到的位置。先确认 Codex 配置目录的位置。在终端里执行ls ~/.codex正常情况下你能看到sessions、history之类的目录。如果没有skills目录手动创建一个mkdir -p ~/.codex/skills/token-stats然后把SKILL.md和token_stats.py放进去。requirements.txt其实可以省略因为这个统计脚本只用 Python 标准库没有任何第三方依赖。保留它只是习惯方便以后扩展。提示如果你用的是 Codex 的容器版或远程开发环境路径会不一样。先echo $CODEX_SESSIONS_DIR看环境变量有就优先用这个。安装完成后重启 Codex 会话。不要指望正在运行的会话立刻感知新的 Skill一定要新开一个会话再测试。4.2 第一次触发与实测记录新开会话后直接输入打开每日用量看板如果没有反应试试触发词更明确的说法用 token-stats skill 统计一下 token 用量第一次跑的时候Codex 可能会先给你一段解释比如“正在定位会话目录”然后运行脚本把表格展示出来。如果一切正常你会看到类似这样的输出 Codex Token 用量看板总计 7 天 总 Token: 1,234,567 输入 Token: 900,000 输出 Token: 334,567 会话总数: 23 ------------------------------------------------ 日期 输入 输出 合计 2025-06-18 210,000 80,000 290,000 2025-06-17 150,000 55,000 205,000如果出现了这个界面说明整个链路已经通了从触发词命中到脚本执行、到结果回传全部正常。如果你说了触发词但 Codex 没有跑脚本而是自己编了一段话大概率是SKILL.md的写法不够“坚定”。回到文件里把描述改得更直接在步骤里明确写“必须执行 token_stats.py”然后重新测一次。4.3 升级玩法定时日报与多项目汇总跑通基础版之后可以考虑两个升级方向。第一个是加定时日报。在 macOS 或 Linux 上用cron每天下午六点跑一次统计把结果输出到文件或者推送到消息机器人。这个需求可以写成第二个 Skill也可以直接在cron里调用脚本本身。第二个是分项目汇总。Codex 会话里大部分情况下是一单一会话但有时候你会开着同一个会话连续做好几个任务。要区分项目可以在会话目录下再建子目录然后把不同项目放到不同路径下脚本里按二级目录聚合即可。我实际操作下来最常用的还是“每日看板”因为趋势一旦能看见你就知道该收敛哪些操作了。5. 常见问题与避坑指南5.1 token 统计与 credits 换算的坑做这个 Skill 的过程中最容易让人困惑的是“token 和 credits 的区别”。Codex 登录后界面上显示的是 credits跑任务时消耗的也是 credits。但底层模型计费的单位是 token。两者之间不是固定比例而是按模型、按输入输出方向动态换算的。具体来说同样一个请求输入 token 价格便宜输出 token 价格贵模型档次越高单位 token 折算的 credits 也越多。所以你在本地用脚本统计出 100 万 token不等于你在官网看到的 credits 消耗就是某一个固定值。这个 Skill 的价值在于“相对趋势”而不是“绝对账单”。你想知道今天比昨天多用多少这个统计足够准确但如果你想和官方案单逐一对账那还得引入模型单价表按会话内记录的模型名逐条计价。后者复杂不少属于更高阶的需求我目前也没有完全做自动对账。5.2 登录态失效与 token exchange failed 的处理我在测试过程中碰到过几次“报告用量时提示 token exchange failed”的情况。这个错误包含的原文比较长但核心意思就是登录凭证已失效无法调用后台接口。这类问题通常和长期不活跃、网络切换后的会话过期有关。处理方式是我踩过几次坑之后总结的注意这一步只是处理登录失效不涉及任何网络环境调整先退出当前会话codex logout重新登录codex login登录完成后重开会话再次触发“打开每日用量看板”如果你在用旧版本客户端升级到新版本后再做上述操作因为旧版本的会话存储格式与新版本不一定兼容读取会话目录时可能显示不出数据。5.3 模型兼容性与 Skill 失效排查另一个容易踩的坑是Codex 更新版本后Skill 突然不触发了。我遇到过 Codex 升级后旧会话文件里的消息结构变了usage字段位置也变了脚本统计结果变成 0。排查思路很简单随便选一个 JSONL 文件用编辑器打开搜索usage看看它在什么位置、字段名是什么。如果发现字段名不对改脚本里的兼容分支就行。涉及模型本身的问题也要注意。某些新模型标识符在旧的 Codex 客户端里不被支持会出现“model not supported”之类的报错这时候登录态是正常的但任务跑不起来。遇到类似问题最直接的解法是检查版本号、升级到最新版再重试。注意写 Skill 的时候一定不要指定绝对路径比如/home/yourname/.codex/...换一台电脑就废了。用~和$HOME派生的相对路径才是稳妥做法。5.4 几个提升体验的小技巧最后补充几个实战里发现的小技巧。触发词别太多。三到五个就够了写太多反而容易误触发比如你正常聊“这个函数内存占用怎么优化”的时候不小心命中了“用量”两个字Skill 就会跑起来。输出格式要固定。脚本里我建议把日期格式固定成YYYY-MM-DD不要用“今天”“昨天”这类描述因为模型回传展示时可能会改写一改写统计口径就乱了。定期清空会话目录不是好习惯。很多人为了“节省空间”删掉旧 JSONL代价就是历史用量统计直接丢数据。编码会话文件通常不大留着无妨真正占空间的往往是日志文件。写在最后我做这个 Skill 的过程最大的感触是工具能不能用好往往不在于功能多少而在于你多快能看到反馈。Codex 本身是个黑盒子你问它问题、它写代码中间消耗了多少资源原本很难感知。现在一句话就能看到每日用了多少 token、哪个项目烧得最多、哪天跑量异常用量管理从“月末惊吓”变成了“日常习惯”。后面我还打算把这个 Skill 继续往“自动告警”方向扩展比如单日 token 超过阈值就输出一条提醒再配合定时任务推送到聊天软件里。如果你也在用 Codex 做深度开发建议先把这个统计能力搭起来看完一周的数据你会对自己每天到底写了多少行代码、烧了多少 token 有一个全新认识。