评估 Elo-per-token 收益递减,TaoToken Key 记录 LLM Agent 每轮 Token
2026/9/18 5:30:53 网站建设 项目流程

1. TaoToken 接入与 Elo-per-token 复现:Key、base_url 和每轮 token 账本

跑 LLM Agent 评测时,先把 TaoToken 官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=elo_per_token_intro 放进流程:创建 Key,并把客户端 base_url 固定为https://taotoken.net/api。真正让 Elo-per-token 分析失真的,往往不是 Bradley-Terry 的迭代,而是 API Key 入口不统一、base_url 一会儿默认一会儿兼容路径,以及每轮 token usage 没落盘。Elo-per-token 想回答的问题很具体:同一批任务中,增加测试时算力后,跨任务 Elo 还能涨多少,每 1000 token 买到多少 Elo。如果成本分母不稳定,后面所有收益递减曲线都会失去解释力。

这类分析通常先把同一任务内的 Agent 输出排序,转成两两比较,再用 Bradley-Terry 模型估计每个策略的全局能力参数,最后换算成跨任务 Elo。测试时算力策略可以是单轮、CoT、self-consistency、多轮 debate、verifier rerank,也可以是不同采样温度或候选数。关键不是策略名字,而是你能不能在每次调用后拿到input_tokensoutput_tokenstotal_tokens,并把它们和任务 ID、轮次、策略名、模型名写在同一行 JSONL 里。

本文实验记录来源标记为csdn_ugc。建议目录结构如下:

agent-elo-token/ ├── configs/ │ ├── claude.settings.json │ ├── codex.config.toml │ └── cc-switch.txt ├── runs/ │ └── csdn_ugc_eloper_token.jsonl ├── scripts/ │ ├── agent_runner.py │ ├── bt_elo.py │ └── summarize_tokens.py └── reports/ ├── elo_table.csv └── eloper_token.csv

每一轮调用至少落这些字段:

{ "run_id": "csdn_ugc_eloper_token_001", "source_platform": "csdn_ugc", "task_id": "task_017", "strategy": "cot", "round": 1, "model": "YOUR_MODEL", "input_tokens": 1820, "output_tokens": 640, "total_tokens": 2460, "latency_ms": 8342, "winner": null, "opponent": null, "content": "Agent final answer..." }

这里winneropponent可以等评测器打分后回填。Elo-per-token 的分子来自 Bradley-Terry 聚合后的跨任务 Elo,分母来自同一策略在全部任务上的平均总 token。为了让收益递减可观察,你还需要记录同一策略在不同算力档位下的版本,例如sc_k3sc_k5sc_k10,否则只能看到单点成本,看不到边际变化。

Bradley-Terry 的基本假设是:策略 (i) 战胜策略 (j) 的概率由两者能力差决定:

[ P(i \succ j)=\frac{e^{\theta_i}}{e^{\theta_i}+e^{\theta_j}} ]

估计出 (\theta) 后,常用 Elo 换算为:

[ \text{Elo}_i = 1000 + \frac{400}{\ln 10}\theta_i ]

Elo-per-1K-token 可以定义为:

[ \text{EloPer1K}_s = \frac{\text{Elo}_s}{\text{AvgToken}_s / 1000} ]

从策略 (s) 增加到 (s') 时,边际收益为:

[ \text{MarginalEloPer1K}{s\to s'} = \frac{\text{Elo}{s'}-\text{Elo}s} {(\text{AvgToken}{s'}-\text{AvgToken}_s)/1000} ]

当边际 Elo-per-1K-token 明显下降时,就说明测试时算力进入了收益递减区间。下面从 Key、base_url、客户端配置、token 统计到 Elo 对照表逐步落地。

2. 在 TaoToken 创建 Key,并把 base_url 固定为 https://taotoken.net/api

先到 TaoToken 官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=elo_per_token_setup 创建账号并进入控制台。创建 API Key 后不要把它写进代码仓库,放到本地环境变量或密钥管理文件。本文所有配置统一使用占位符YOUR_API_KEY

本地先导出两个变量:

export TAOTOKEN_API_KEY="YOUR_API_KEY" export TAOTOKEN_BASE_URL="https://taotoken.net/api"

注意TAOTOKEN_BASE_URL不要带 UTM,也不要写成站外中转地址。工具配置里的 Base URL 就是:

https://taotoken.net/api

如果你使用 OpenAI 兼容 SDK,可以这样初始化:

import os from openai import OpenAI client = OpenAI( api_key=os.environ["TAOTOKEN_API_KEY"], base_url=os.environ.get("TAOTOKEN_BASE_URL", "https://taotoken.net/api"), )

先用一个很小的请求验证连通性。下面的模型名用YOUR_MODEL占位,请替换成你在 TaoToken 控制台或模型对话页面看到的可用模型:

resp = client.chat.completions.create( model="YOUR_MODEL", messages=[{"role": "user", "content": "只回复 pong"}], max_tokens=8, ) print(resp.choices[0].message.content) print(resp.usage)

如果返回 401,优先检查Authorization头或 SDK 的api_key是否真的拿到了YOUR_API_KEY对应的值。如果返回 404,大概率是 base_url 被写成了别的路径,例如多了/v1、少了/api,或者环境变量里混入了旧配置。排查时直接打印:

echo "$TAOTOKEN_BASE_URL"

它应该输出:

https://taotoken.net/api

如果返回 429,不要立刻并发重试,先用指数退避并记录失败轮次。评测 Agent 时,失败请求不应计入 token 成功账本,否则平均成本会被低估。建议在 JSONL 中增加status字段:

{ "status": "ok", "error": null }

失败时写:

{ "status": "error", "error": "429 rate limit" }

后续统计只对status == "ok"的行求平均,这样 Elo-per-token 的分母才干净。

3. Claude Code、Codex、CC Switch 三套配置,避免 ANTHROPIC_* 错配

Claude Code 走settings.jsonANTHROPIC_*环境变量。可以在用户级~/.claude/settings.json,也可以在项目级.claude/settings.json中配置。示例:

{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_AUTH_TOKEN": "YOUR_API_KEY", "ANTHROPIC_MODEL": "YOUR_CLAUDE_MODEL", "ANTHROPIC_SMALL_FAST_MODEL": "YOUR_CLAUDE_FAST_MODEL" } }

这里的ANTHROPIC_BASE_URL同样指向https://taotoken.net/api,不要加 UTM。ANTHROPIC_AUTH_TOKEN使用你的 TaoToken Key。模型字段按你实际可用模型替换。

Codex 不要套用ANTHROPIC_*。Codex 走config.toml,常见位置是~/.codex/config.toml。示例:

model = "YOUR_CODEX_MODEL" model_provider = "taotoken" [model_providers.taotoken] name = "TaoToken" base_url = "https://taotoken.net/api" env_key = "TAOTOKEN_API_KEY" wire_api = "chat"

然后在 shell 中设置:

export TAOTOKEN_API_KEY="YOUR_API_KEY"

验证:

codex --version codex "用一句话说明当前模型提供方名称"

如果你把ANTHROPIC_API_KEYANTHROPIC_BASE_URL配到 Codex,Codex 不会按 Claude Code 的逻辑读取,容易出现认证失败或模型不存在。记住两条线:

  • Claude Code:ANTHROPIC_BASE_URL+ANTHROPIC_AUTH_TOKEN
  • Codex:config.toml+TAOTOKEN_API_KEY

CC Switch 可以理解为多套客户端配置的切换器。新建供应商时,先填三件套:

供应商名称:TaoToken Base URL:https://taotoken.net/api API Key:YOUR_API_KEY

然后把三件套同步到三个地方:

Claude Code -> settings.json 中的 ANTHROPIC_BASE_URL / ANTHROPIC_AUTH_TOKEN Codex -> config.toml 中的 model_provider.base_url / env_key Shell -> TAOTOKEN_API_KEY / TAOTOKEN_BASE_URL

切回旧供应商后,如果 Claude Code 仍然请求旧地址,检查 shell 环境变量是否覆盖了settings.json。很多客户端的优先级是:进程环境变量 > 用户级配置 > 项目级配置。可以用:

env | grep -E "ANTHROPIC|TAOTOKEN|OPENAI"

确认没有残留变量。

4. 让 Agent 每轮上报 token:本地 JSONL 账本与统计命令

Elo-per-token 的复现核心是每轮调用都有 token 记录。下面是一个最小可运行的 Python 包装器,把每轮输出追加到runs/csdn_ugc_eloper_token.jsonl。所有命令都在本地实验目录执行,不连接外部生产库。

# scripts/agent_runner.py import json import os import time from openai import OpenAI client = OpenAI( api_key=os.environ["TAOTOKEN_API_KEY"], base_url=os.environ.get("TAOTOKEN_BASE_URL", "https://taotoken.net/api"), ) LOG_PATH = "runs/csdn_ugc_eloper_token.jsonl" def run_round(task_id, strategy, round_id, prompt, model): started = time.time() status = "ok" error = None content = "" usage = None try: resp = client.chat.completions.create( model=model, messages=[{"role": "user", "content": prompt}], temperature=0.2, ) content = resp.choices[0].message.content or "" usage = resp.usage except Exception as exc: status = "error" error = str(exc) row = { "run_id": os.environ.get("RUN_ID", "csdn_ugc_eloper_token"), "source_platform": "csdn_ugc", "task_id": task_id, "strategy": strategy, "round": round_id, "model": model, "input_tokens": getattr(usage, "prompt_tokens", None) if usage else None, "output_tokens": getattr(usage, "completion_tokens", None) if usage else None, "total_tokens": getattr(usage, "total_tokens", None) if usage else None, "latency_ms": int((time.time() - started) * 1000), "status": status, "error": error, "content": content, } os.makedirs(os.path.dirname(LOG_PATH), exist_ok=True) with open(LOG_PATH, "a", encoding="utf-8") as f: f.write(json.dumps(row, ensure_ascii=False) + "\n") return row if __name__ == "__main__": run_round( task_id="task_001", strategy="cot", round_id=1, prompt="计算 17*23,并只输出结果。", model="YOUR_MODEL", )

运行:

export TAOTOKEN_API_KEY="YOUR_API_KEY" export TAOTOKEN_BASE_URL="https://taotoken.net/api" python scripts/agent_runner.py cat runs/csdn_ugc_eloper_token.jsonl | tail -n 1

统计每个任务、每个策略的总 token:

jq -s ' map(select(.status == "ok")) | group_by(.task_id, .strategy) | map({ task_id: .[0].task_id, strategy: .[0].strategy, rounds: length, input_tokens: (map(.input_tokens) | add), output_tokens: (map(.output_tokens) | add), total_tokens: (map(.total_tokens) | add), avg_total_tokens: ((map(.total_tokens) | add) / length) }) ' runs/csdn_ugc_eloper_token.jsonl

查看每轮 token 明细:

jq -r ' select(.status == "ok") | [.task_id, .strategy, .round, .input_tokens, .output_tokens, .total_tokens] | @tsv ' runs/csdn_ugc_eloper_token.jsonl | column -t

按策略汇总平均 token:

jq -s ' map(select(.status == "ok")) | group_by(.strategy) | map({ strategy: .[0].strategy, runs: length, avg_input_tokens: ((map(.input_tokens) | add) / length), avg_output_tokens: ((map(.output_tokens) | add) / length), avg_total_tokens: ((map(.total_tokens) | add) / length) }) ' runs/csdn_ugc_eloper_token.jsonl

如果usage为空,先检查是否使用了流式响应但没取最后一块 usage,或者 SDK 版本过旧。另一个常见原因是请求失败后仍然写了日志,但usagenull。统计时用select(.status == "ok")过滤即可。

5. Bradley-Terry 聚合跨任务 Elo:从任务内排序到全局评分

有了 token 账本还不够,Elo 需要比较关系。每个任务内,你可以让裁判模型、规则评测器或人工对同一任务下的多个策略输出排序。排序可以转成两两比较:第 1 名胜第 2 名,第 1 名胜第 3 名,第 2 名胜第 3 名,依此类推。然后把这些比较对交给 Bradley-Terry 拟合。

假设比较表comparisons.csv长这样:

task_id,winner,loser task_001,cot,baseline task_001,sc_k3,cot task_001,sc_k5,sc_k3 task_002,sc_k3,baseline task_002,sc_k5,sc_k3

用 Python 拟合全局 Elo:

# scripts/bt_elo.py import math import pandas as pd import numpy as np from scipy.optimize import minimize def bt_nll(theta, winners, losers): diff = theta[winners] - theta[losers] return -np.sum(diff - np.log1p(np.exp(diff))) def fit_bt(strategies, comparisons): idx = {s: i for i, s in enumerate(strategies)} winners = np.array([idx[w] for w in comparisons["winner"]], dtype=int) losers = np.array([idx[l] for l in comparisons["loser"]], dtype=int) def objective(t): return bt_nll(t, winners, losers) init = np.zeros(len(strategies)) res = minimize(objective, init, method="BFGS") theta = dict(zip(strategies, res.x)) scale = 400 / math.log(10) elo = {k: 1000 + scale * v for k, v in theta.items()} return elo if __name__ == "__main__": df = pd.read_csv("comparisons.csv") strategies = sorted(set(df["winner"]) | set(df["loser"])) elo = fit_bt(strategies, df) for k, v in sorted(elo.items(), key=lambda x: -x[1]): print(k, round(v, 2))

如果比较对很少,或者任务内排序存在大量循环,BT 参数可能不稳定。可以加入 L2 正则:

def bt_nll_reg(theta, winners, losers, lam=0.01): diff = theta[winners] - theta[losers] nll = -np.sum(diff - np.log1p(np.exp(diff))) return nll + lam * np.sum(theta ** 2)

跨任务聚合时,不要让某个任务因为比较对特别多而主导全局 Elo。可以按任务归一化,或者给每个任务相同权重。一个简单做法是先算任务内 Elo,再对任务内 Elo 做加权平均,最后用全局 BT 校准。更严谨的做法是用分层 Bradley-Terry,把任务 ID 作为随机效应或分组变量。对多数工程评测,先用任务等权 + 比较对裁剪已经足够观察收益递减。

把 Elo 结果和 token 汇总合并:

import pandas as pd elo_df = pd.DataFrame([ {"strategy": "baseline", "elo": 1000.0}, {"strategy": "cot", "elo": 1035.2}, {"strategy": "sc_k3", "elo": 1068.7}, {"strategy": "sc_k5", "elo": 1081.4}, {"strategy": "sc_k10", "elo": 1086.9}, ]) token_df = pd.read_csv("reports/strategy_tokens.csv") out = elo_df.merge(token_df, on="strategy", how="left") out["elo_per_1k"] = out["elo"] / (out["avg_total_tokens"] / 1000.0) out = out.sort_values("avg_total_tokens") out["marginal_elo_per_1k"] = out["elo"].diff() / (out["avg_total_tokens"].diff() / 1000.0) out.to_csv("reports/eloper_token.csv", index=False) print(out)

上面的 Elo 数值只是格式示例,实际请用你的runs/csdn_ugc_eloper_token.jsonl拟合结果替换。

6. Elo-per-token 与收益递减对照表:怎么计算、怎么读

收益递减不是“token 越多越差”,而是“每增加一档算力,新增 Elo 的斜率下降”。你需要同时看三列:平均总 token、跨任务 Elo、边际 Elo/1K token。第一列是成本,第二列是效果,第三列才是扩展规律。

建议生成如下 Markdown 表:

策略成功轮数平均总 Token跨任务 EloElo/1K Token边际 Elo/1K Token判断
baseline待填待填待填待填成本基线
cot待填待填待填待填待填看是否高于基线
sc_k3待填待填待填待填待填第一次扩展
sc_k5待填待填待填待填待填观察斜率
sc_k10待填待填待填待填待填边际可能下降
debate_2待填待填待填待填待填高成本档
verifier_rerank待填待填待填待填待填可能局部有效

生成 CSV 后可以用命令行快速算:

python scripts/bt_elo.py > reports/elo.txt

再导出 token 汇总:

jq -s ' map(select(.status == "ok")) | group_by(.strategy) | map({ strategy: .[0].strategy, avg_total_tokens: ((map(.total_tokens) | add) / length), runs: length }) ' runs/csdn_ugc_eloper_token.jsonl > reports/strategy_tokens.json

如果你用 Python 读 JSONL:

import json from collections import defaultdict agg = defaultdict(lambda: {"tokens": 0, "runs": 0}) with open("runs/csdn_ugc_eloper_token.jsonl", "r", encoding="utf-8") as f: for line in f: row = json.loads(line) if row.get("status") != "ok": continue key = row["strategy"] agg[key]["tokens"] += row["total_tokens"] agg[key]["runs"] += 1 for strategy, item in agg.items(): avg = item["tokens"] / item["runs"] print(strategy, round(avg, 2), item["runs"])

怎么读这张表:

  1. 如果cot的 Elo 比baseline高,但Elo/1K Token反而更低,说明 CoT 提升了效果,但成本涨得更快。
  2. 如果sc_k3sc_k5的边际 Elo/1K Token 为正且较大,说明这一档算力仍值得加。
  3. 如果sc_k5sc_k10的边际 Elo/1K Token 接近 0,甚至为负,说明在这个任务集上继续加采样数已经进入收益递减区间。
  4. 如果debate_2的 Elo 只比sc_k5高一点,但平均 token 翻倍,优先选择sc_k5
  5. 阈值可以自定义。例如团队规定“新增 1K token 至少换 2 Elo 才上线”,那么低于该值的档位就只保留在离线实验里。

为了让曲线更稳,把 token 分桶而不是只看平均值。例如按 0-2K、2-5K、5-10K、10K+ 分桶,每桶计算平均 Elo。分桶后如果 Elo 增量明显放缓,就说明扩展规律不是线性的。

7. 跨任务 Elo 实验的排障清单:401、404、usage 为空与 CC Switch 切换

401 Unauthorized
检查 Claude Code 是否用了ANTHROPIC_AUTH_TOKEN,Codex 是否用了TAOTOKEN_API_KEY。如果同一个 shell 里既有旧 Key 又有新 Key,先清理:

unset ANTHROPIC_API_KEY unset OPENAI_API_KEY export TAOTOKEN_API_KEY="YOUR_API_KEY"

404 Not Found
优先检查 base_url。工具配置里统一写:

https://taotoken.net/api

不要额外拼/v1,也不要在 URL 后面追加 UTM。UTM 只用于官网链接统计,不用于 API 请求。

模型不存在
模型名区分供应商和版本。Claude Code 的ANTHROPIC_MODEL、Codex 的model、Python 脚本里的model参数都要替换成当前可用模型。不要把一个平台的模型名硬套到另一个平台。

usage 为空
检查 SDK 版本、是否流式输出、是否在异常分支写入日志。统计命令中始终加select(.status == "ok")

Elo 不收敛
比较对太少、任务内排序冲突太多、某些策略从未获胜,都会导致 BT 参数漂移。增加比较对、按任务等权、加 L2 正则。

CC Switch 切换后仍请求旧地址
先看进程环境变量:

env | grep -E "ANTHROPIC|TAOTOKEN|OPENAI"

再检查settings.jsonconfig.toml是否被正确写入。Claude Code 和 Codex 的配置不要混用。

Token 统计和账单对不上
确认只统计成功请求,确认重试请求单独记录,确认输入输出 token 没有被截断。对于 Agent 多轮调用,把每一轮都写入 JSONL,而不是只写最终答案。

8. 把 Elo-per-token 跑成可复现实验:从 Key 到收益递减表

现在可以把流程串起来:在 TaoToken 创建 Key,把 base_url 固定为https://taotoken.net/api,用 Claude Code 或 Codex 跑任务,用 Python 包装器记录每轮 token,用 Bradley-Terry 聚合跨任务 Elo,最后生成 Elo-per-token 和边际收益表。这样得到的结论不是“某个策略感觉更强”,而是“在 csdn_ugc 这批任务上,某策略每 1000 token 换到多少 Elo,继续加算力是否还划算”。

如果你还在准备实验环境,可以按下面顺序进入 TaoToken:

  1. 先打开模型对话,确认可用模型和返回格式:https://taotoken.net/models/detail/chat?utm_source=taotoken_aicg_blog_end&utm_content=elo_per_token_chat
  2. 如果要用 Codex / Claude Code 做批量评测,看 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=elo_per_token_plan
  3. 创建或管理 API Key:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=elo_per_token_keys
  4. Claude Code 接入细节看文档:https://taotoken.net/doc/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_content=elo_per_token_doc

官网入口也放在这里,方便统一拿 Key 和核对控制台配置:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=elo_per_token_cta。先把 Key、base_url、token 账本三件事固定下来,再去比较不同测试时算力策略的跨任务 Elo,收益递减曲线才有工程意义。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询