买速度之前先跑一条基线:10 个任务测出自己的每秒 token 和每任务成本

2026-10-01 Skills成本性能工程实践

OpenAI 这周把速度单独拿出来卖:Ultrafast 是标准价 6 倍,换 API 6 倍吞吐、Codex 里 8 倍生成速度。同一周,干活的模型降价到 2 美元。两条消息放在一起,真正该问的不是”哪个更划算”,是我的任务里,有多少时间是卡在等模型输出上的.

这个问题没有通用答案。批处理任务答案是零,交互式改代码答案可能是大半。差别这么大,靠猜一定会买错。

测什么

三个数,缺一个结论就不可靠:

  • 每秒输出 token:模型侧的原始速度。
  • 端到端墙钟时间:从发出任务到拿到结果,包含等工具、等文件、等网络。
  • 每任务成本:按官方价目表算出来的实际花销。

第三个最容易被跳过,也最容易骗人。速度快了之后同样的墙钟时间里会跑更多轮次,成本不一定降。

脚本

把下面这份存成 scripts/speed-baseline.mjs,用 node 直接跑。它做的是:对同一批任务,在两个模型档位上各跑一遍,把三个数记进 CSV。

// scripts/speed-baseline.mjs
// 用法:node scripts/speed-baseline.mjs tasks.txt
// tasks.txt 每行一个任务描述,建议 10 行
import { readFileSync, writeFileSync } from 'node:fs';
import { spawnSync } from 'node:child_process';

const PRICES = {
  // 每百万 token 的美元价,按你实际用的模型改
  'cheap': { in: 2,  out: 10  },
  'fast':  { in: 60, out: 300 },
};

const TIERS = [
  { key: 'cheap', cmd: process.env.CMD_CHEAP || 'claude', args: ['-p', '--model', 'claude-sonnet-5-5'] },
  { key: 'fast',  cmd: process.env.CMD_FAST  || 'claude', args: ['-p', '--model', 'claude-sonnet-5-5'] },
];

const tasks = readFileSync(process.argv[2], 'utf8').split('\n').map(s => s.trim()).filter(Boolean);
const rows = [['task', 'tier', 'seconds', 'tokens_out', 'usd', 'exit']];

for (const [i, task] of tasks.entries()) {
  for (const tier of TIERS) {
    const t0 = Date.now();
    const r = spawnSync(tier.cmd, [...tier.args, task], { encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
    const seconds = (Date.now() - t0) / 1000;

    // 没有统一用量接口时,用最土的办法:数输出字符,除以 3 粗估 token
    // 有 usage 输出的工具,把这一段换成真实读数
    const text = (r.stdout || '') + (r.stderr || '');
    const tokensOut = Math.round(text.length / 3);
    const p = PRICES[tier.key];
    const usd = (tokensOut / 1_000_000) * p.out;

    rows.push([String(i + 1), tier.key, seconds.toFixed(1), String(tokensOut), usd.toFixed(4), String(r.status)]);
  }
}

writeFileSync('speed-baseline.csv', rows.map(r => r.join(',')).join('\n'));
console.log('written: speed-baseline.csv');

跑之前把 TIERS 里的命令换成你自己的工具。Codex 是 codex exec,Claude Code 是 claude -p,别的 agent 框架同理换 --model 参数。

字符数除以 3 估 token 只在没有真实用量数据时用。 大部分命令行工具会在 stderr 或 JSON 输出里给 usage,能拿到就用真的,这个估算对中文会偏大。

怎么读结果

CSV 导进表格,算三行:

指标怎么算判断标准
每秒输出 token平均输出 token ÷ 平均秒数两档差多少倍
墙钟提速比便宜档秒数 ÷ 快速档秒数这个数通常远小于标称倍数
每任务成本比快速档成本 ÷ 便宜档成本与提速比对比

核心判断就一句话:墙钟提速比如果不到 2,6 倍价就不要买。

原因是 agent 的时间大部分不花在生成上。一次任务里可能有 30 次工具调用、每次等 2 秒,生成时间只占一小段。把生成速度提 6 倍,省下的只是那一小段。

怎么知道自己做对了

5 条,全过才算测完:

  1. 任务集必须是你自己的真实任务。 拿 10 个你上周真的做过的活,不要用 “hello world” 或者基准题。合成任务的速度分布和真实任务差一个量级,测出来的结论没用。
  2. 每个组合至少跑 3 遍取中位数。 单次测量受网络和机器负载影响太大,跑 3 遍是底线。脚本里 TIERS 加个 repeat: 3 就能做到。
  3. 退出码必须记下来。 上面的脚本记了 exit 列。如果某个档位失败率高,它的速度再快也不能买——重跑一次的时间早就吃掉了提速收益。
  4. 成本必须用真实用量算,不能用字符估算交差。 至少有 1 次用工具自带的 usage 输出核对一下估算值的偏差,偏差超过 30% 就说明估算法不能用,改脚本。
  5. 换个时间段再跑一次。 同一批任务在晚上和白天跑,墙钟时间可能差 20%。只在一种负载下测出来的结论,换个时间就不成立。

几个坑

  • 别用标称倍数做预算。 官方给的是 token 生成速度的倍数,不是端到端任务的倍数。这两个数之间的差距,就是你要测的东西。
  • 缓存会污染成本测量。 同一批任务跑第二遍的时候,命中缓存的输入几乎不花钱。要么每次跑之间等缓存过期,要么在记录里标注第几轮。
  • 并发会把测量搞乱。 测的时候别同时开着别的 agent 在跑。本地 CPU 和网络占用都会算进墙钟时间。
  • “每次省 30 秒”不等于”值得”。 一个人一天跑 20 次任务,每次省 30 秒,一天省 10 分钟。为这 10 分钟付 6 倍价,多数时候不值。先算总量再决定。
  • 测完要把结论写下来,带日期。 价目表和模型三个月换一轮,没有记录下次还得重测。

最后一句

速度这东西,买了之后很难退回——习惯了 300 token 每秒,再回去看 40 token 每秒会受不了。所以这笔钱要在还没习惯之前算清楚,用一次半小时的测量换一个不会反悔的决定。