买速度之前先跑一条基线:10 个任务测出自己的每秒 token 和每任务成本
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 条,全过才算测完:
- 任务集必须是你自己的真实任务。 拿 10 个你上周真的做过的活,不要用 “hello world” 或者基准题。合成任务的速度分布和真实任务差一个量级,测出来的结论没用。
- 每个组合至少跑 3 遍取中位数。 单次测量受网络和机器负载影响太大,跑 3 遍是底线。脚本里
TIERS加个repeat: 3就能做到。 - 退出码必须记下来。 上面的脚本记了
exit列。如果某个档位失败率高,它的速度再快也不能买——重跑一次的时间早就吃掉了提速收益。 - 成本必须用真实用量算,不能用字符估算交差。 至少有 1 次用工具自带的 usage 输出核对一下估算值的偏差,偏差超过 30% 就说明估算法不能用,改脚本。
- 换个时间段再跑一次。 同一批任务在晚上和白天跑,墙钟时间可能差 20%。只在一种负载下测出来的结论,换个时间就不成立。
几个坑
- 别用标称倍数做预算。 官方给的是 token 生成速度的倍数,不是端到端任务的倍数。这两个数之间的差距,就是你要测的东西。
- 缓存会污染成本测量。 同一批任务跑第二遍的时候,命中缓存的输入几乎不花钱。要么每次跑之间等缓存过期,要么在记录里标注第几轮。
- 并发会把测量搞乱。 测的时候别同时开着别的 agent 在跑。本地 CPU 和网络占用都会算进墙钟时间。
- “每次省 30 秒”不等于”值得”。 一个人一天跑 20 次任务,每次省 30 秒,一天省 10 分钟。为这 10 分钟付 6 倍价,多数时候不值。先算总量再决定。
- 测完要把结论写下来,带日期。 价目表和模型三个月换一轮,没有记录下次还得重测。
最后一句
速度这东西,买了之后很难退回——习惯了 300 token 每秒,再回去看 40 token 每秒会受不了。所以这笔钱要在还没习惯之前算清楚,用一次半小时的测量换一个不会反悔的决定。