1. 从 Agents API 到 Codex harness:先把调用改走 TaoToken
如果你正在把 OpenAI Agents API 的公测调用接到云端 Codex harness,先去 TaoToken 官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=agents_api_codex_harness_intro 拿一个 TaoToken Key,再把请求 Base URL 设为 https://taotoken.net/api。这是本文所有追踪工作的起点。因为 Agents API 公测版的特点是:一次外层 API 调用,可能驱动 Codex harness 在云端执行多轮推理、工具调用和结果汇总。账单上 Token 涨得很快,但你未必知道是哪个调用方、哪个 run、哪一轮 harness 消耗的。本文不讨论模型能力,只解决三个工程问题:第一,如何把 Agents API 和 Codex harness 的请求改到 TaoToken;第二,Claude Code、Codex、CC Switch 多套配置怎么隔离,避免 ANTHROPIC_* 混进 Codex;第三,如何产出一张可复现的“调用方与 Token 统计表”,让谁在消耗 Token 一目了然。
很多团队第一次接 Agents API 时,会把“外层调用返回的 usage”当成全部成本。但 Codex harness 在云端执行时,内部可能包含规划、工具调用、结果校验、再规划等多个步骤。外层请求只是入口,真正的大头可能来自 harness 内部的每一轮模型调用。所以“改走 TaoToken”不只是换一个 Base URL,而是把外层调用、harness 内部调用、本地 CLI 调用统一到同一个计费入口,再用 Key 别名和 run_id 把消耗方拆开。
下面从准备 Key 开始,逐步给出 Codex config.toml、Claude Code settings.json、CC Switch 三件套、Agents API 外层调用改写、以及 Token 统计表的完整做法。
2. 前置准备:TaoToken Key、Base URL 与三条链路
先去 TaoToken 官网注册或登录:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=agents_api_codex_harness_prepare 。进入控制台后,打开 API Keys 管理页创建 Key:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=agents_api_codex_harness_keys 。这里建议不要所有调用方共用一个 Key,而是按“调用方”建 Key。例如:
- agents-api-prod:你的服务端外层 Agents API 调用。
- codex-harness-worker:云端 Codex harness 执行器。
- claude-code-local:本地 Claude Code CLI。
- eval-runner:批量评测或回放任务。
TaoToken 侧可以按 Key 看用量,调用方侧按 Key 别名写日志,两边就能对齐。统一使用的 Base URL 是:
https://taotoken.net/api注意,Base URL 是工具配置项,不要加 UTM 参数。API Key 占位符统一写YOUR_API_KEY,实际使用时替换成你在 TaoToken 创建的 Key。
需要区分三条链路:
- Agents API 外层调用:你的服务端代码,OpenAI SDK 或 HTTP 请求,base_url 指向 TaoToken。
- Codex harness:云端或本地 Codex CLI 执行器,config.toml 的 provider base_url 指向 TaoToken。
- Claude Code 或其他 CLI:settings.json 或 ANTHROPIC_* 环境变量,ANTHROPIC_BASE_URL 指向 TaoToken。
这三条链路不要混用环境变量。Codex 不读 ANTHROPIC_*,Claude Code 也不应该读 Codex 的 config.toml。混用的结果通常是 401、404,或者用量统计对不上。
3. 外层 Agents API 调用改写:OpenAI SDK 与裸 HTTP 两种方式
无论你用官方 Agents SDK、自己封装的 harness,还是直接发 HTTP 请求,最终都要落到某个 API 端点。改走 TaoToken 的核心只有两项:base_url和api_key。
先看 OpenAI SDK 方式。以下以 Responses 风格为例,如果你用的 Agents API 接口不同,保留base_url与api_key两项即可:
import os from openai import OpenAI client = OpenAI( api_key=os.environ["TAOTOKEN_API_KEY"], base_url="https://taotoken.net/api", ) resp = client.responses.create( model="gpt-5-codex", input="请给出一个三步任务计划,并说明每步需要的工具。", ) print(resp.output_text) print(resp.usage)环境变量这样设置:
export TAOTOKEN_API_KEY="YOUR_API_KEY"Windows PowerShell:
$env:TAOTOKEN_API_KEY="YOUR_API_KEY"如果你不想依赖 SDK,也可以用裸 HTTP。下面是一个最小请求示例,重点看Authorization与 URL 拼接:
import os import requests url = "https://taotoken.net/api/v1/responses" headers = { "Authorization": f"Bearer {os.environ['TAOTOKEN_API_KEY']}", "Content-Type": "application/json", } payload = { "model": "gpt-5-codex", "input": "请给出一个三步任务计划。", } resp = requests.post(url, headers=headers, json=payload, timeout=120) resp.raise_for_status() data = resp.json() print(data.get("usage"))如果你的调用路径是 chat 风格,把 URL 换成https://taotoken.net/api/v1/chat/completions,payload 按 chat 格式组织。关键点是:Base URL 始终是https://taotoken.net/api,不要在工具配置里写成带 UTM 的地址。
外层调用改完后,下一步是把 Codex harness 也指到 TaoToken。否则外层走 TaoToken,harness 内部仍走别处,统计表会缺一大块。
4. Codex 侧配置:config.toml 指向 TaoToken Base URL
Codex CLI 常用config.toml。先备份原文件,再增加一个 provider。示例:
# ~/.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"然后设置环境变量:
export TAOTOKEN_API_KEY="YOUR_API_KEY"Windows PowerShell:
$env:TAOTOKEN_API_KEY="YOUR_API_KEY"说明几个字段:
model:模型名以 TaoToken 模型对话页展示为准,可以在 https://taotoken.net/models/detail/chat?utm_source=taotoken_aicg_blog_end&utm_content=agents_api_codex_harness_chat 确认。model_provider:指向下面定义的taotoken。base_url:必须是https://taotoken.net/api。env_key:环境变量名,不是 Key 本身。这样 Key 不会硬编码进 config.toml。wire_api:如果当前 Codex 版本支持 Responses 风格,用responses;如果只支持 chat 风格,改成chat。如果报unknown wire_api,先升级 Codex CLI,或改回你的版本支持的取值。
验证方式:执行一次最小 Codex 任务,然后观察 TaoToken 控制台 API Keys 页面用量是否增加。也可以临时在 config.toml 中增加更详细的日志配置,但不要在这里写ANTHROPIC_API_KEY、ANTHROPIC_BASE_URL,Codex 不认这些变量。
如果你有多个 Codex 调用方,建议为每个调用方建独立 Key,并写不同 profile。例如codex-harness-worker使用TAOTOKEN_CODEX_WORKER_KEY,codex-local-debug使用TAOTOKEN_CODEX_DEBUG_KEY。这样在 TaoToken 侧按 Key 看用量时,能直接区分是 harness 消耗还是本地调试消耗。
5. Claude Code 侧配置:settings.json 与 ANTHROPIC_* 不要混到 Codex
Claude Code 的配置走settings.json或ANTHROPIC_*环境变量。示例settings.json:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_AUTH_TOKEN": "YOUR_API_KEY", "ANTHROPIC_MODEL": "claude-sonnet-4-5" } }如果使用环境变量:
export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_AUTH_TOKEN="YOUR_API_KEY" export ANTHROPIC_MODEL="claude-sonnet-4-5"注意:这些变量只给 Claude Code 使用。不要把ANTHROPIC_*写进 Codex 的config.toml,也不要在 Codex 启动脚本里 source Claude Code 的环境文件。反过来,也不要把 Codex 的model_provider、wire_api写进 Claude Code 的settings.json。
Claude Code 文档可以参考:https://taotoken.net/doc/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_content=agents_api_codex_harness_doc 。配置完成后,启动 Claude Code,执行一个简单问答,再到 TaoToken API Keys 页面看对应 Key 的用量。如果 401,优先检查ANTHROPIC_AUTH_TOKEN是否使用了正确的 TaoToken Key;如果 404,检查ANTHROPIC_BASE_URL是否误写成带/v1的地址,统一写https://taotoken.net/api即可,具体路径由客户端追加。
6. CC Switch 三件套:用 profile 隔离调用方
如果你用 CC Switch 做多配置切换,本质上是维护三份 profile:
- Claude Code profile:
settings.json中的env.ANTHROPIC_BASE_URL、env.ANTHROPIC_AUTH_TOKEN、env.ANTHROPIC_MODEL。 - Codex profile:
config.toml中的model、model_provider、base_url、env_key、wire_api。 - Key/环境变量 profile:
TAOTOKEN_API_KEY、ANTHROPIC_AUTH_TOKEN等,按调用方命名。
下面是一个结构示意,具体字段以你使用的 CC Switch 版本为准:
{ "profiles": [ { "name": "claude-code-taotoken", "tool": "claude-code", "settings": { "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_AUTH_TOKEN": "YOUR_API_KEY", "ANTHROPIC_MODEL": "claude-sonnet-4-5" } } }, { "name": "codex-taotoken", "tool": "codex", "settings": { "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" } } } } ] }切换时重点检查三件事:
- 当前 profile 的
base_url是否是https://taotoken.net/api。 - Codex profile 里有没有误放
ANTHROPIC_*。 - Claude Code profile 里有没有误放
model_provider。
如果 CC Switch 支持命令切换,建议在每次运行前打印当前 profile 名和 Key 别名,写入日志。这样后面统计 Token 时,profile 名可以直接作为caller_id的候选。
7. 消耗方追踪:独立 Key + run_id 日志 + Token 统计表
这是本文的核心目标。Agents API 公测版的特点是一次 API 调用驱动云端 Codex harness,harness 内部可能有多轮模型调用。外层请求返回的 usage 可能只覆盖外层,内部多轮需要靠 harness 自己上报,或者按 Key/时间窗口在 TaoToken 侧看总量。要追踪“谁在消耗”,做三件事:
- 每个调用方分配独立 TaoToken Key。
- 每次外层调用生成
run_id/trace_id,并写入日志。 - harness 每一轮把
turn、model、input_tokens、output_tokens、key_alias写日志。
Python 采集示例:
import os import time import uuid import json from openai import OpenAI client = OpenAI( api_key=os.environ["TAOTOKEN_API_KEY"], base_url="https://taotoken.net/api", ) caller_id = "agents-api-prod" run_id = str(uuid.uuid4()) started_at = time.time() resp = client.responses.create( model="gpt-5-codex", input="请给出一个三步任务计划,并说明每步需要的工具。", ) ended_at = time.time() usage = getattr(resp, "usage", None) record = { "caller_id": caller_id, "run_id": run_id, "turn": 1, "model": "gpt-5-codex", "input_tokens": getattr(usage, "input_tokens", None) if usage else None, "output_tokens": getattr(usage, "output_tokens", None) if usage else None, "total_tokens": getattr(usage, "total_tokens", None) if usage else None, "started_at": started_at, "ended_at": ended_at, "key_alias": "agents-api-prod", } with open("token_usage.jsonl", "a", encoding="utf-8") as f: f.write(json.dumps(record, ensure_ascii=False) + "\n") print(record)如果 SDK 返回的 usage 字段名不同,按实际字段映射。关键是不要只记录总 Token,还要记录caller_id、run_id、turn、key_alias。没有这四个字段,后面无法拆账。
汇总成 Markdown 表:
import json from collections import defaultdict rows = defaultdict(lambda: { "input_tokens": 0, "output_tokens": 0, "total_tokens": 0, "runs": set(), }) with open("token_usage.jsonl", encoding="utf-8") as f: for line in f: r = json.loads(line) key = (r["caller_id"], r["key_alias"]) rows[key]["input_tokens"] += r["input_tokens"] or 0 rows[key]["output_tokens"] += r["output_tokens"] or 0 rows[key]["total_tokens"] += r["total_tokens"] or 0 rows[key]["runs"].add(r["run_id"]) print("| 调用方 | Key 别名 | Run 数 | 输入 Token | 输出 Token | 总 Token |") print("|---|---|---:|---:|---:|---:|") for (caller, key), v in rows.items(): print(f"| {caller} | {key} | {len(v['runs'])} | {v['input_tokens']} | {v['output_tokens']} | {v['total_tokens']} |")如果你习惯用本地 SQLite 做临时分析,可以把 JSONL 导入后执行下面的查询。命令由你在本地执行:
-- 先建表 CREATE TABLE token_usage ( caller_id TEXT, run_id TEXT, turn INTEGER, model TEXT, input_tokens INTEGER, output_tokens INTEGER, total_tokens INTEGER, started_at REAL, ended_at REAL, key_alias TEXT ); -- 按调用方和 Key 汇总 SELECT caller_id, key_alias, COUNT(DISTINCT run_id) AS runs, SUM(input_tokens) AS input_tokens, SUM(output_tokens) AS output_tokens, SUM(total_tokens) AS total_tokens FROM token_usage GROUP BY caller_id, key_alias ORDER BY total_tokens DESC;最终可复现产出表如下:
| 调用方 | Key 别名 | Run 数 | 输入 Token | 输出 Token | 总 Token | 备注 |
|---|---|---|---|---|---|---|
| agents-api-prod | agents-api-prod | 12 | 45210 | 18320 | 63530 | 外层 Agents API 调用 |
| codex-harness-worker | codex-harness-worker | 12 | 128400 | 55100 | 183500 | harness 内部多轮 |
| claude-code-local | claude-code-local | 8 | 22100 | 9800 | 31900 | 本地 CLI |
| eval-runner | eval-runner | 5 | 31000 | 12000 | 43000 | 批量评测 |
这张表的数据来自你自己的日志和 TaoToken 侧用量,不是估算。关键是对齐字段:caller_id用 Key 别名,run_id全链路传递,turn标记 harness 第几轮。外层调用和 harness 内部调用都用同一个run_id,这样在统计表里可以按 Run 汇总,也可以按 Turn 下钻。
如果发现 harness 内部 Token 远大于外层,说明单次 API 调用驱动的云端执行器确实在内部做了多轮推理。此时不要只优化外层输入长度,还要看 harness 的计划步骤、工具返回内容、以及是否重复读取大文件。把turn和model加进日志后,你能看到第几轮开始膨胀。
8. 排障清单:Base URL、401、404、模型名、用量不增长
常见问题按优先级排查:
- 401 Unauthorized:Key 错误或没放到正确环境变量。Codex 看
config.toml的env_key是否指向TAOTOKEN_API_KEY;Claude Code 看ANTHROPIC_AUTH_TOKEN是否使用了正确的 Key。 - 404 Not Found:Base URL 多了
/v1或少了/api。统一写https://taotoken.net/api,路径由 SDK 追加。 - 模型不存在:模型名要和 TaoToken 支持的模型一致。可以在模型对话页确认:https://taotoken.net/models/detail/chat?utm_source=taotoken_aicg_blog_end&utm_content=agents_api_codex_harness_chat 。
- Codex 不读 config:检查
~/.codex/config.toml是否被其他 profile 覆盖,确认当前用户目录正确,确认model_provider指向taotoken。 - Claude Code 与 Codex 混用:不要在 Codex 的
config.toml写ANTHROPIC_*,也不要在 Claude Code 的settings.json写model_provider。 - 用量不增长:检查
HTTP_PROXY/HTTPS_PROXY是否把请求转到了不可达地址;确认请求实际打到了 TaoToken Base URL。 - 云端 harness 用量对不上:外层 usage 只代表外层调用,harness 内部多轮要单独记录。用
run_id+ 时间窗口在 TaoToken API Keys 页面按 Key 对账。 - CC Switch 切换后配置未生效:重启终端或重新加载 profile;检查环境变量是否被 shell 缓存。
- 统计表出现空值:说明某些调用没有记录 usage。给 harness 每一轮加日志,至少记录
input_tokens、output_tokens、total_tokens。
另外,不要把 TaoToken Key 提交到 Git。用YOUR_API_KEY占位,实际值放本地环境变量或密钥管理工具。如果 Key 泄露,立即到 API Keys 页面轮换:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=agents_api_codex_harness_keys 。
9. 文末 CTA:模型对话 → Coding Plan → 创建 Key → Claude Code 文档
现在可以按顺序操作:
- 先体验模型对话,确认模型名与响应格式:https://taotoken.net/models/detail/chat?utm_source=taotoken_aicg_blog_end&utm_content=agents_api_codex_harness_chat
- 选择适合你的 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=agents_api_codex_harness_plan
- 创建 API Key,并按调用方拆分 Key 别名:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=agents_api_codex_harness_keys
- 查看 Claude Code 文档,配置
settings.json或ANTHROPIC_*:https://taotoken.net/doc/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_content=agents_api_codex_harness_doc
最后回到 TaoToken 官网查看整体能力与入口:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=agents_api_codex_harness_cta 。把 Agents API 外层调用、Codex harness、Claude Code 都指到https://taotoken.net/api,再用独立 Key、run_id、turn三件套补齐日志,你就能产出一张真正可复现的调用方与 Token 统计表,回答“Codex harness 到底谁在消耗 Token”这个问题。