
1. 推理基准测试到底在测什么为什么你需要统一 Key 跑评测大模型推理基准测试说白了就是给模型或推理服务出一套标准考卷用同一批题目、同一套打分规则量出它在真实业务里的表现。它和普通的功能测试不一样功能测试只关心答案对不对而推理基准测试要同时盯住准确率、首 Token 时间、Token 间延迟、吞吐量、Token 消耗这几条线。因为线上成本往往不是被“答错”拖垮的而是被“答得慢、答得贵”拖垮的。我见过不少团队的做法是拿几个 prompt 手动在网页里点一点感觉“挺快的”就上线了。结果一到晚高峰用户排队等首字账单还翻倍。问题就出在没有可复现的评测链路。推理基准测试要解决的正是把“感觉快”变成“TTFT 320ms、ITL 18ms、TPS 42、单请求消耗 780 Token”这种能对比、能回归的数字。适合读这篇的人有三类一是正在选模型或推理服务的工程同学需要横向对比二是做 Agent、RAG 应用想压延迟和成本的开发者三是要把评测接进 CI、做版本回归的团队。这三类人有个共同痛点——评测脚本要同时打多个模型通道每个通道一套 Key、一套 Base URL改起来烦还容易把 Key 写进代码里。所以这篇的落地视角是用 TaoToken 的统一 Key 和统一 API 通道把“数据集选择 → 批量发起推理请求 → 采集核心指标 → 对比输出”这条链路一次跑通。你只需要维护一份配置就能把请求打到不同模型上指标口径也保持一致。下面从接入准备开始一步步给可复制的配置和脚本。2. TaoToken 统一 Key 接入准备与评测环境搭建先说清楚 TaoToken 在这条链路里的角色。它是一个统一的大模型 API 通道你拿到一个 Key配一个 Base URL就能用 OpenAI 兼容的方式调用多家模型。对评测来说最大的好处是评测脚本不用为每个模型写一套 SDK 适配请求体、返回结构、流式解析都统一指标采集代码只写一遍。接入前你需要准备三样东西一个 TaoToken API Key、一个能跑 Python 的环境建议 3.10、以及你要评测的模型 ID 列表。Key 在控制台的 API Keys 页面创建地址是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 。创建后复制保存它只完整显示一次。Base URL 用 https://taotoken.net/api 注意这个地址后面不加任何 UTM 参数脚本里直接写死即可。模型 ID 建议先去模型对话页面确认一下当前可用的名称避免拼错https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。环境依赖很简单装三个包就够pip install openai httpx pandasopenai用来发请求TaoToken 兼容 OpenAI 协议httpx用来做更细的流式计时pandas用来汇总指标。装完后建议先做一次最小连通性验证别急着写完整评测脚本。最小验证只需要一个请求确认 Key、Base URL、模型 ID 三件套都对from openai import OpenAI client OpenAI( api_key你的_TaoToken_Key, base_urlhttps://taotoken.net/api ) resp client.chat.completions.create( model你确认过的模型ID, messages[{role: user, content: 只回复两个字收到}], max_tokens16 ) print(resp.choices[0].message.content)如果这一步返回“收到”说明通道通了。如果报 401先别怀疑代码九成是 Key 复制时带了空格或者用了别的项目的 Key。如果报模型不存在回到模型对话页面核对 ID 拼写。这一步过了再进入评测脚本能省掉大量“到底是网络问题还是代码问题”的排查时间。环境变量建议这样管理别把 Key 硬编码进脚本export TAOTOKEN_API_KEY你的_TaoToken_Key export TAOTOKEN_BASE_URLhttps://taotoken.net/api脚本里用os.environ读取。这样评测脚本可以进 GitKey 不会泄露。长期跑评测或 Agent 任务的话可以考虑 Coding Plan额度更稳适合反复回归https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。3. 可复制的评测脚本配置数据集、批量请求与指标采集这一节是核心给一份能直接跑的评测脚本骨架。先定评测数据集。推理基准测试常用的数据集有 MMLU知识、GSM8K数学推理、HumanEval代码、以及自建的业务问答集。选数据集的原则是题目要能自动判分且输入输出长度分布贴近你的真实场景。比如你做摘要就别用输出超长的推理题集否则 ITL 数据没参考价值。下面这份配置用 JSON 描述评测任务路径和字段都写清楚方便你改{ eval_name: gsm8k_smoke, base_url: https://taotoken.net/api, models: [模型A_ID, 模型B_ID], dataset_path: ./data/gsm8k_sample.jsonl, concurrency: 4, max_tokens: 512, temperature: 0, ignore_eos: false, stream: true, output_path: ./results/eval_result.csv }几个参数解释一下。concurrency是并发数建议从 1 开始逐步加到略高于推理引擎的最大批处理大小观察 TPS 饱和点。temperature设 0 走 Greedy评测时最稳避免随机性干扰。ignore_eos在测固定输出长度时设为 true让模型生成到max_tokens才停这样 ITL 和 TPS 才可比。stream必须开否则拿不到 TTFT。数据集用 JSONL每行一道题{id: q1, prompt: 小明有12个苹果给了小红5个又买了8个现在有几个, answer: 15} {id: q2, prompt: 一个班40人60%是女生女生多少人, answer: 24}批量请求和指标采集脚本如下重点是流式计时import os, json, time, csv from concurrent.futures import ThreadPoolExecutor from openai import OpenAI API_KEY os.environ[TAOTOKEN_API_KEY] BASE_URL os.environ[TAOTOKEN_BASE_URL] def load_dataset(path): with open(path, r, encodingutf-8) as f: return [json.loads(line) for line in f if line.strip()] def run_one(client, model, item, cfg): start time.perf_counter() ttft None token_times [] text stream client.chat.completions.create( modelmodel, messages[{role: user, content: item[prompt]}], max_tokenscfg[max_tokens], temperaturecfg[temperature], streamTrue ) for chunk in stream: delta chunk.choices[0].delta.content if delta: now time.perf_counter() if ttft is None: ttft now - start token_times.append(now) text delta end time.perf_counter() e2e end - start n_tokens len(token_times) itl None if n_tokens 1: itl (token_times[-1] - token_times[0]) / (n_tokens - 1) tps n_tokens / e2e if e2e 0 else 0 return { id: item[id], model: model, ttft_ms: round(ttft * 1000, 2) if ttft else None, itl_ms: round(itl * 1000, 2) if itl else None, e2e_ms: round(e2e * 1000, 2), tokens: n_tokens, tps: round(tps, 2), output: text.strip(), answer: item.get(answer, ) } def run_eval(cfg): client OpenAI(api_keyAPI_KEY, base_urlBASE_URL) data load_dataset(cfg[dataset_path]) rows [] for model in cfg[models]: with ThreadPoolExecutor(max_workerscfg[concurrency]) as pool: futures [pool.submit(run_one, client, model, item, cfg) for item in data] for fut in futures: rows.append(fut.result()) with open(cfg[output_path], w, newline, encodingutf-8) as f: writer csv.DictWriter(f, fieldnameslist(rows[0].keys())) writer.writeheader() writer.writerows(rows) return rows if __name__ __main__: with open(./config/eval_config.json, r, encodingutf-8) as f: cfg json.load(f) run_eval(cfg)这份脚本把 TTFT、ITL、e2e、TPS、Token 数都采下来了。准确率单独算把output和answer做字符串匹配或正则抽取数字后比对。注意 ITL 的计算排除了首 Token和 GenAI-Perf 的口径一致这样跨工具对比不会打架。4. 验证请求与成功结果跑通一次完整评测配置写好后先别上全量数据集用 5 条样本做冒烟测试。把dataset_path指向gsm8k_sample.jsonlconcurrency设 1models只放一个模型。运行python eval_runner.py成功的话./results/eval_result.csv会生成内容类似idmodelttft_msitl_mse2e_mstokenstpsq1模型A412.3519.821580.445836.70q2模型A388.1018.451320.774937.10看到这张表说明链路通了。接下来做三件事验证结果可信度。第一把concurrency从 1 调到 4、8观察 TPS 是否先升后饱和、TTFT 是否随并发上升。如果 TPS 一直线性涨说明还没压到瓶颈如果 TTFT 暴涨而 TPS 不涨说明排队严重。第二换第二个模型 ID 再跑一遍对比同一批题目的 TTFT 和 ITL这才是横向评测的意义。第三把ignore_eos设 true、max_tokens设 256跑一次固定长度测试看 ITL 是否稳定——ITL 稳定说明内存管理和带宽利用没问题。准确率验证用一个小脚本import csv, re def extract_num(s): m re.search(r-?\d, s.replace(,, )) return m.group() if m else None correct total 0 with open(./results/eval_result.csv, encodingutf-8) as f: for row in csv.DictReader(f): total 1 if extract_num(row[output]) row[answer]: correct 1 print(f准确率: {correct}/{total} {correct/total:.2%})冒烟测试准确率不用太在意样本太少。它的作用是确认判分逻辑没写错。真正评测时数据集至少几百条准确率才有统计意义。到这里你已经有了可复现的评测结果换模型、换并发、换数据集都只是改配置的事。5. 本篇常见报错排查401、local proxy failed、reading choices、OAuth评测跑不起来报错基本集中在这几类逐个说清楚。401 Unauthorized。最常见。原因通常是 Key 没读到、Key 失效、或者 Base URL 写错。先确认环境变量echo $TAOTOKEN_API_KEY有没有值。再确认base_url是https://taotoken.net/api结尾不要多斜杠、不要拼成别的路径。如果 Key 是从别处复制的注意首尾空格。还有一种情况是用了已删除的 Key回控制台重新建一个即可。local proxy failed / connection error。这类报错说明请求根本没出去或者被本机网络配置拦了。检查你的运行环境有没有设置HTTP_PROXY、HTTPS_PROXY环境变量有的话先清掉再跑。另外确认机器能正常访问外网。如果是在容器里跑检查容器网络是否正常。这类问题和 Key 无关别反复重建 Key。reading choices / IndexError: list index out of range。报错出现在解析返回时chunk.choices[0]取不到。原因一般是请求被限流返回了错误结构、或者模型返回了空 choices。处理办法是加防御for chunk in stream: if not chunk.choices: continue delta chunk.choices[0].delta.content if delta: ...同时把max_tokens设得太小也可能导致空返回评测时别低于 64。OAuth / authentication 相关报错。如果你用的是某些 CLI 工具比如 Claude Code 类它可能默认走 OAuth 登录而不是 API Key。这时候要在配置里显式指定 Base URL、Key、Model ID 三件套。以 Claude Code 为例配置里需要写全{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: 你的_TaoToken_Key, ANTHROPIC_MODEL: 你确认过的模型ID } }三件套缺一不可Base URL 决定请求打到哪Key 决定身份Model ID 决定用哪个模型。只配 Key 不配 Base URL工具会走默认端点自然报认证失败。同理Cline、Codex 的auth.json也要把这三项写全别只填 Key。Token 数对不上。如果你发现脚本统计的 tokens 和账单对不上先确认统计的是输出 Token 还是输入加输出。脚本里len(token_times)只数了输出增量块输入 Token 要另外从返回的 usage 里取非流式才有完整 usage。评测成本时两者都要算。6. 把评测接进日常统一 Key 的长期用法跑通一次评测只是开始真正有价值的是把它变成可重复的动作。我的做法是把评测脚本和配置一起放进仓库每次模型版本更新、或者切换推理服务就跑一次回归对比 TTFT、ITL、TPS、准确率四条线有没有退化。配置里的模型 ID 列表就是你的评测矩阵加一个模型只是加一行。统一 Key 的好处在这里体现得最明显你不需要为每个模型维护一套鉴权逻辑评测代码只写一遍换模型只改配置。数据集也可以复用同一批题目打不同模型结果才可比。如果要做更复杂的 Agent 评测比如多轮工具调用建议用 Coding Plan 拿更稳的额度避免评测中途被限流打断https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。最后给一个实用技巧评测结果 CSV 别只看平均值把 P50、P95、P99 都算出来。平均 TTFT 400ms 看着不错但 P99 可能到 3 秒那部分用户体验是崩的。用 pandas 一行就能算import pandas as pd df pd.read_csv(./results/eval_result.csv) print(df.groupby(model)[[ttft_ms, itl_ms, tps]].quantile([0.5, 0.95, 0.99]))把这张分位数表贴进你的选型文档比任何“感觉挺快”都有说服力。评测链路搭好后你会发现选模型这件事从拍脑袋变成了看数据这才是推理基准测试真正的价值。