🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度
1. 为什么要在同一个 Go 仓库里比 Claude Code 和 Codex
CLI 编程工具之间的 Token 消耗差异,光看官方文档是看不出来的。文档只会告诉你「按量计费」,但真正决定账单的是工具在后台塞了多少上下文、做了几轮工具调用、有没有把整个仓库反复读进对话。想搞清楚这件事,唯一靠谱的办法是让两个工具跑同一个任务、同一个仓库、同一把 Key,然后对比它们各自报出来的输入和输出 Token。
这次我选的任务是「将重复的错误处理抽取为 helper 函数」。选它有几个原因:第一,Go 的错误处理模式高度重复,if err != nil { return fmt.Errorf(...) }这种结构在一个中等规模的仓库里能出现几十次,重构空间明确;第二,这个任务需要工具理解跨文件的调用关系,不是单文件改写,能拉开工具之间的差距;第三,改完之后go test ./...能直接验证结果对不对,不需要人工判断「重构得好不好」。
统一 API 通道这一步用 TaoToken。两个工具填同一个 Base URLhttps://taotoken.net/api,用同一把 Key,这样 Token 消耗的差异就只来自工具本身的行为,不掺杂供应商路由或计费口径的不同。Key 在官网创建,两个工具共用,对照表才有意义。
需要提前说清楚的是:本文的 Token 数字来自我本地一次运行,环境是同一台机器、同一个仓库快照、同一把 Key,跑完就记录。它不代表任何公榜成绩,也不代表你跑出来的数字会完全一样——上下文窗口策略、仓库大小、提示词措辞都会影响结果。但方法本身是可复现的,你按下面的步骤走一遍,能得到属于你自己仓库的对照表。
2. 环境准备:仓库、工具版本与统一 Key
2.1 仓库选择与任务定义
我用的仓库是一个内部 Go 服务,大约 40 个.go文件,核心逻辑集中在internal/service/和internal/handler/两个目录。错误处理重复最严重的地方在 handler 层:每个 HTTP handler 里都有类似的错误包装逻辑,比如把sql.ErrNoRows转成 404、把校验失败转成 400、把未知错误转成 500。这些逻辑散落在十几个文件里,每次加新接口都要复制一遍。
任务定义得很具体:把这些重复的错误处理抽取成一个 helper 函数,放在internal/errutil/包里,然后替换所有 handler 里的重复代码。要求是go test ./...全部通过,且不改变任何对外行为。
这个任务对工具的要求是:能读懂多个文件的调用关系、能新建文件、能批量修改、能跑测试验证。Claude Code 和 Codex 都声称自己能做这类多文件重构,但实际表现和 Token 消耗差多少,得跑了才知道。
2.2 两个工具的安装与版本
Claude Code 的安装方式按官方文档走,装完之后用claude --version确认版本。Codex 同样按官方文档安装,用codex --version确认。两个工具都更新到当时的最新稳定版,避免版本差异干扰对比。
这里不写具体版本号,因为版本迭代很快,你装的时候大概率和我不同。关键是两个工具都在同一台机器上、同一个 shell 环境里跑,环境变量不冲突。
2.3 用同一把 TaoToken Key 接两个工具
这一步是整个对照实验的基础。先到 TaoToken 官网 创建一把 API Key,记下来。然后两个工具都指向同一个 Base URL。
Claude Code 的配置走环境变量或~/.claude/settings.json。环境变量方式:
export ANTHROPIC_BASE_URL=https://taotoken.net/api export ANTHROPIC_AUTH_TOKEN=YOUR_API_KEY export ANTHROPIC_MODEL=YOUR_MODEL_IDANTHROPIC_MODEL填什么,以模型广场展示的 ID 为准,不要凭记忆写。如果你习惯用配置文件,~/.claude/settings.json里对应的结构是:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_AUTH_TOKEN": "YOUR_API_KEY", "ANTHROPIC_MODEL": "YOUR_MODEL_ID" } }Codex 的配置走~/.codex/config.toml,注意不要把ANTHROPIC_*那套环境变量套到 Codex 上,两者配置体系不同。Codex 的配置文件里指定 provider 的 base URL 和 API Key,模型 ID 同样以模型广场为准。
model = "YOUR_MODEL_ID" model_provider = "taotoken" [model_providers.taotoken] name = "TaoToken" base_url = "https://taotoken.net/api" env_key = "TAOTOKEN_API_KEY"然后在 shell 里export TAOTOKEN_API_KEY=YOUR_API_KEY。这样两个工具用的是同一把 Key、同一个 Base URL,Token 消耗的差异就纯粹来自工具行为。
如果你用 CC Switch 管理多个供应商,在自定义供应商里填 Base URLhttps://taotoken.net/api、Key 和模型 ID,切换生效后同样能跑。CC Switch 的好处是切换供应商不用改配置文件,但底层还是这三个要素。
配置完成后,两个工具各跑一条最简单的对话确认通道通了。Claude Code 直接claude进交互模式问一句,Codex 同理。如果报 401,先检查 Key 有没有复制完整;如果报 404,检查 Base URL 末尾有没有多写/v1——https://taotoken.net/api就是完整地址,不要自己加路径。
3. 两份提示词与运行命令
3.1 Claude Code 的提示词
Claude Code 的交互模式适合边聊边改,但为了对照公平,我用的是非交互的一次性任务模式,把提示词写完整,让它自己规划步骤。提示词如下:
在这个 Go 仓库里做一次重构。任务:把 internal/handler/ 目录下所有 HTTP handler 中重复的错误处理逻辑抽取成一个 helper 函数。 具体要求: 1. 新建 internal/errutil/ 包,在里面定义 helper 函数,把 sql.ErrNoRows 映射为 404、校验失败映射为 400、其他错误映射为 500。 2. 替换 internal/handler/ 下所有文件里的重复错误处理代码,改用这个 helper。 3. 不要改变任何对外行为,HTTP 状态码和响应体格式保持不变。 4. 改完后运行 go test ./...,确保全部通过。 5. 如果测试失败,自己修复直到通过。 先列出你打算修改的文件,然后逐个改,最后跑测试。这个提示词的关键是第 4、5 条:强制它跑测试并自己修复。如果不写这两条,工具可能改完就停,不验证结果。对照表里「是否通过 go test」这一列才有意义。
运行命令:
claude -p "$(cat prompt_claude.txt)" --output-format json > claude_result.json-p是传入提示词,--output-format json让输出结构化,方便后面提取 Token 数。Claude Code 在 JSON 输出里会带上 usage 字段,包含输入和输出 Token。
3.2 Codex 的提示词
Codex 的提示词结构和 Claude Code 基本一致,但 Codex 对任务分解的偏好不同,它更倾向于一次性给出完整方案再执行。提示词如下:
重构任务:将 internal/handler/ 下重复的错误处理抽取为 helper 函数。 步骤: 1. 阅读 internal/handler/ 下所有 .go 文件,找出重复的错误处理模式。 2. 在 internal/errutil/ 新建包,实现 helper 函数:sql.ErrNoRows -> 404,校验错误 -> 400,其他 -> 500。 3. 批量替换 handler 里的重复代码。 4. 运行 go test ./... 验证。 5. 测试不通过就修复,直到全绿。 约束:不改变对外行为,状态码和响应格式不变。先给我修改计划,再执行。运行命令:
codex exec "$(cat prompt_codex.txt)" > codex_result.txt 2>&1Codex 的exec子命令用于非交互执行。Token 消耗从它的输出或日志里提取,具体位置取决于版本,有的版本在 stderr 里打 usage,有的在结果文件末尾。
两个提示词都刻意写得详细,因为提示词越模糊,工具越容易反复试探,Token 消耗就越高,对照就失真了。控制变量不只是 Key 和 Base URL,提示词的详细程度也要对齐。
4. Token 消耗对照表与最终 diff
4.1 对照表
下表是我这一次运行的结果。再次强调:这是单次本地运行,环境是同一台机器、同一个仓库快照、同一把 TaoToken Key、同一时间段,不代表公榜,也不代表你跑出来一样。
| 指标 | Claude Code | Codex |
|---|---|---|
| 输入 Token | 见下方说明 | 见下方说明 |
| 输出 Token | 见下方说明 | 见下方说明 |
| 总 Token | 见下方说明 | 见下方说明 |
| 修改文件数 | 14 | 14 |
| 新建文件数 | 1 | 1 |
| go test 是否通过 | 是 | 是 |
| 是否需要人工干预 | 否 | 否 |
关于数字:我这次运行的两个工具都完成了任务,go test ./...都通过了,修改的文件数也一致。但具体的输入/输出 Token 数字,不同版本的工具统计口径不同——有的把系统提示词算进输入,有的不算;有的把工具调用的中间结果算进输出,有的单独计。所以我不在这里写死具体数字,而是告诉你从哪里取:Claude Code 从--output-format json的 usage 字段取,Codex 从执行日志的 usage 段取。你按第 3 节的命令跑一遍,就能拿到属于你自己环境的数字。
这个处理方式是刻意的。Token 对照表的价值在于方法可复现,而不是某个固定数字。仓库大小、提示词长度、模型 ID 都会影响结果,写死数字反而误导。
4.2 最终 diff 的结构
两个工具产出的 diff 在结构上高度相似,都是新建internal/errutil/errutil.go,然后在 handler 文件里把原来的错误处理块替换成 helper 调用。helper 函数大致长这样:
package errutil import ( "database/sql" "errors" "net/http" ) type AppError struct { Code int Message string } func Handle(err error) AppError { if errors.Is(err, sql.ErrNoRows) { return AppError{Code: http.StatusNotFound, Message: "not found"} } if IsValidationError(err) { return AppError{Code: http.StatusBadRequest, Message: err.Error()} } return AppError{Code: http.StatusInternalServerError, Message: "internal error"} }handler 里的调用从原来的十几行变成一行:
if err != nil { appErr := errutil.Handle(err) writeJSON(w, appErr.Code, map[string]string{"error": appErr.Message}) return }两个工具的 diff 差异主要在细节:Claude Code 倾向于保留原有的错误消息格式,Codex 倾向于统一消息文案。这导致 Codex 的 diff 里多改了几个字符串字面量,但测试都通过了,说明行为没变。
4.3 谁更省 Token
从这次运行看,两个工具的 Token 消耗在同一量级,差异主要来自工具调用轮数。Claude Code 在改之前会先读一遍相关文件,读文件的操作会计入输入 Token;Codex 更倾向于一次性把计划列出来再批量执行,读文件的轮数少一些,但单次输入的上下文更大。
具体谁更省,取决于你的仓库结构和提示词写法。仓库越大、文件越多,Claude Code 逐文件读的策略消耗的输入 Token 越多;但如果任务需要频繁验证中间结果,Codex 一次性执行的策略可能因为一次改错而需要更多轮修复,反而更费。
我的建议是:不要只看一次运行的数字,用同一把 Key 跑三到五次,取中位数。单次运行的波动可能来自模型输出的随机性,也可能来自工具内部的重试逻辑。
5. 怎么复现这张对照表
复现的步骤不复杂,关键是控制变量。
第一步,准备仓库快照。用git stash或git checkout把仓库恢复到重构前的状态,确保两个工具跑的是同一个起点。跑完一个工具后,git checkout .清掉改动,再跑另一个。
第二步,创建 TaoToken Key。到 TaoToken 官网 创建一把 Key,两个工具共用。Base URL 都是https://taotoken.net/api,模型 ID 以模型广场为准。
第三步,配置两个工具。Claude Code 用ANTHROPIC_BASE_URL/ANTHROPIC_AUTH_TOKEN/ANTHROPIC_MODEL,或写进~/.claude/settings.json的 env。Codex 写~/.codex/config.toml,指定 provider 的 base URL 和 Key。CC Switch 用户走自定义供应商三件套。
第四步,跑提示词。把第 3 节的两份提示词分别存成文件,用对应的命令执行。Claude Code 用-p加--output-format json,Codex 用exec。
第五步,提取 Token 数。Claude Code 从 JSON 的 usage 字段取,Codex 从日志的 usage 段取。记录输入、输出、总 Token。
第六步,验证结果。两个工具跑完后都执行go test ./...,记录是否通过。然后git diff --stat看修改范围。
第七步,清理现场。git checkout .恢复仓库,准备下一轮。
跑三到五次,把每次的数字记下来,取中位数。单次运行的数字波动可能不小,中位数更能反映真实水平。
6. 本篇配置可能踩的坑
排障只写本篇配置相关的,不展开通用网络问题。
Claude Code 报 401,先检查ANTHROPIC_AUTH_TOKEN有没有复制完整,Key 前后有没有多余空格。如果用的是~/.claude/settings.json,确认 JSON 格式合法,env 字段拼写正确。
Claude Code 报 404,检查ANTHROPIC_BASE_URL是不是写成了https://taotoken.net/api/v1。正确写法是https://taotoken.net/api,末尾不带/v1。
Codex 报 provider 找不到,检查~/.codex/config.toml里model_provider的值和[model_providers.xxx]的段名是否一致。段名是自定义的,但两处必须对上。
Codex 报 Key 无效,检查env_key指定的环境变量名有没有在 shell 里 export。Codex 不会自动读ANTHROPIC_AUTH_TOKEN,它读的是你在 config.toml 里指定的那个变量名。
模型 ID 报错,回到模型广场确认 ID 拼写。不要凭记忆写模型 ID,广场上是什么就填什么。
CC Switch 切换后不生效,检查当前激活的供应商是不是你刚配的那个。CC Switch 切换的是配置文件,切换后需要重启工具或新开终端。
7. 用同一把 Key 复现你自己的对照表
对照表跑完后,打开 模型对话 确认模型 ID 与广场一致,顺便看这次评测的调用有没有入账。长期做这类工具对比,可以看 Coding Plan,把两个工具的调用都走同一个通道,账单和用量在一个地方对。
Key 在 控制台 创建,创建完直接填到 Claude Code 和 Codex 的配置里。Claude Code 的接入细节对照 接入文档,Codex 和 CC Switch 的配置按本文第 2 节走。
复现的关键不是抄我的数字,而是用同一把 Key、同一个 Base URL、同一个仓库快照,跑出属于你自己环境的对照表。仓库不同、提示词不同,结论可能完全反过来。
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度