
1. 为什么你不需要自己跑一遍 benchmark先说结论TTFT、TPOT、吞吐量、显存占用这四个指标公开数据已经足够全你要做的是「读懂 对照自己的硬件做决策」而不是再跑一份没人看的跑分。我见过太多开发者一上来就折腾 vLLM 的 benchmark 脚本结果驱动版本、CUDA 版本、后台进程一干扰跑出来的数字和公开数据差不了多少时间全花在环境上了。7B 模型的 TTFT 大概就是那个范围你跑十遍也不会变成另一个量级。所以这篇的目标很明确给你一套可复制的 benchmark 结果对照表模板一份 config.toml 配置骨架再用 TTFT、TPOT、吞吐量、显存占用四项指标做具体验证动作让你建立可复现的评测流程。适合谁手上有 RTX 4060 / 5090 这类消费级卡、准备评估 API 通道性能、或者想给团队定一套评测规范的开发者。四个指标先用人话对齐一下TTFTTime To First Token从你发请求到收到第一个 token 的时间决定「感觉快不快」。TPOTTime Per Output Token首 token 之后每个 token 的平均生成时间决定「吐字顺不顺」。吞吐量Throughput单位时间产出的 token 数高并发场景看这个。显存占用模型权重 KV Cache 系统开销决定「能不能跑起来」。这四个指标不是孤立的。TTFT 低但 TPOT 高用户会觉得「响应快但打字慢」吞吐量高但显存爆了服务直接挂。下面逐个拆。2. TaoToken 前置把评测通道先接上在解读 benchmark 之前你得先有一条稳定的通道来发验证请求。TaoToken 在这里的角色是统一入口一个 API Key 对接多家模型省去你为每个模型单独配环境。官网入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentAPI 地址不带 UTMhttps://taotoken.net/api拿 Key 的路径很直接进控制台创建即可控制台https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleAPI Keys 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keys如果你只是想先验证模型输出质量不想写代码可以直接用模型对话页面模型对话https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite长期做编码或 Agent 场景的看 Coding PlanCoding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite接入文档在这里参数细节以文档为准接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite注意API Key 只放在环境变量里别硬编码进脚本更别提交到 Git。这是评测流程可复现的第一步。3. 可复制的 benchmark 对照表模板与 config.toml 骨架3.1 benchmark 结果对照表模板这张表你可以直接抄进自己的评测文档每次测完填一行。关键是「环境列」必须写全否则数据没法对比。模型量化工具硬件TTFT(s)TPOT(ms)吞吐(tok/s)显存(GB)并发备注Qwen2.5-7BQ4_K_MOllamaRTX 4060 8G0.828354.51空上下文短输入Qwen2.5-7Bfp8vLLMRTX 5090 32G0.2812081生产级Qwen2.5-14Bfp8vLLMRTX 5090 32G0.31190141推荐配置Qwen2.5-32Bfp8vLLM双卡 32G0.51660261需双卡填表时记住三条铁律同一行内环境必须一致并发数单独列别和单请求混着比显存写「实际占用」而不是「参数量」。3.2 config.toml 配置骨架下面这份骨架把评测需要的参数都留了位置你按自己环境改。重点是[benchmark]段它决定了你的数据能不能复现。# config.toml - benchmark 评测配置骨架 [server] host 0.0.0.0 port 8000 api_base https://taotoken.net/api [auth] # 从环境变量读取不要写死 api_key_env TAOTOKEN_API_KEY [model] name qwen2.5-7b-instruct quantization q4_k_m # q4_k_m / fp8 / fp16 max_model_len 8192 [benchmark] # 四项核心指标采集开关 measure_ttft true measure_tpot true measure_throughput true measure_vram true # 请求参数必须固定才能复现 prompt_tokens 128 # 输入长度固定 max_tokens 256 # 输出长度固定 concurrency 1 # 并发数单请求填 1 warmup_runs 3 # 预热次数丢弃前几次 repeat_runs 5 # 正式测量次数取中位数 [hardware] gpu RTX 4060 vram_gb 8 driver 记录你的驱动版本 cuda 记录你的 CUDA 版本提示warmup_runs和repeat_runs是复现的关键。第一次请求往往包含模型加载和缓存预热直接算进去 TTFT 会虚高。4. 用四项指标做验证请求与成功结果配置好了接下来是具体动作。我用一个 Python 脚本演示怎么采集 TTFT 和 TPOT你可以直接改。4.1 采集 TTFT 与 TPOTimport os import time import requests API_BASE https://taotoken.net/api API_KEY os.environ[TAOTOKEN_API_KEY] def measure_ttft_tpot(prompt, max_tokens256): url f{API_BASE}/v1/chat/completions headers { Authorization: fBearer {API_KEY}, Content-Type: application/json, } payload { model: qwen2.5-7b-instruct, messages: [{role: user, content: prompt}], max_tokens: max_tokens, stream: True, } start time.perf_counter() first_token_time None token_count 0 with requests.post(url, headersheaders, jsonpayload, streamTrue) as resp: for line in resp.iter_lines(): if not line: continue if line.startswith(bdata: ) and b[DONE] not in line: if first_token_time is None: first_token_time time.perf_counter() token_count 1 end time.perf_counter() ttft first_token_time - start tpot (end - first_token_time) / max(token_count - 1, 1) throughput token_count / (end - start) return { ttft_s: round(ttft, 3), tpot_ms: round(tpot * 1000, 2), throughput_tok_s: round(throughput, 2), tokens: token_count, } if __name__ __main__: # 预热 for _ in range(3): measure_ttft_tpot(你好, max_tokens16) # 正式测量取中位数 results [measure_ttft_tpot(用一句话解释什么是 KV Cache, max_tokens128) for _ in range(5)] results.sort(keylambda x: x[ttft_s]) print(中位数结果:, results[len(results) // 2])跑通后你会看到类似输出中位数结果: {ttft_s: 0.82, tpot_ms: 28.4, throughput_tok_s: 34.7, tokens: 128}这就是 RTX 4060 跑 7B Q4 的典型区间和公开数据对得上。4.2 采集显存占用显存用nvidia-smi采注意要在请求进行中采而不是空闲时。# 请求进行中另开终端执行 nvidia-smi --query-gpumemory.used,memory.total --formatcsv -l 1或者用 Python 的 pynvml 在脚本里采from pynvml import nvmlInit, nvmlDeviceGetHandleByIndex, nvmlDeviceGetMemoryInfo nvmlInit() handle nvmlDeviceGetHandleByIndex(0) info nvmlDeviceGetMemoryInfo(handle) print(f显存占用: {info.used / 1024**3:.2f} GB / {info.total / 1024**3:.2f} GB)4.3 成功结果的判断标准什么算「验证成功」不是数字好看而是可复现。同一份 config.toml连跑三次TTFT 波动在 ±10% 以内就算稳定。如果波动超过 30%先查后台进程和驱动版本别急着换模型。对照公开数据的合理区间场景TTFT 合理区间吞吐合理区间RTX 4060 7B Q40.6–1.0s30–40 tok/sRTX 5090 14B fp80.2–0.4s80–100 tok/s落在区间内说明你的环境和公开数据一致可以放心用公开数据做决策。5. 本篇常见错排查5.1 TTFT 虚高第一次请求特别慢这是最常见的坑。原因通常是模型冷加载或缓存未预热。解决办法就是在正式测量前跑warmup_runs次把前几次结果丢掉。如果你用的是 Ollama第一次加载模型可能要几秒别把它算进 TTFT。5.2 TPOT 波动大忽快忽慢先看是不是并发数没固定。单请求测 TPOT并发测吞吐两者混在一起数据就废了。另外检查max_tokens是否固定输出长度不同TPOT 的统计口径就不一样。5.3 吞吐量对不上公开数据大概率是并发数不同。公开数据里 vLLM 的高吞吐往往是在 10/50/100 并发下测的你单请求跑当然低。对照时先确认并发数一致再看硬件是否同档。5.4 显存占用比预期高模型参数量不等于显存占用。KV Cache 会随上下文长度线性增长max_model_len设成 8192 和 32768显存差很多。粗略公式显存 ≈ 参数量 × 量化精度 KV Cache 系统开销。7B Q4 纯模型约 3.5GB加上 KV Cache 和系统开销实际到 4.5GB 左右。5.5 请求报 401 或 403检查 API Key 是否从环境变量正确读取以及请求头格式是不是Bearer key。别把 Key 写进 config.toml 的明文字段用api_key_env指向环境变量。5.6 流式响应解析出错streamTrue时返回的是 SSE 格式每行以data:开头最后一行是data: [DONE]。解析时先判断前缀再过滤[DONE]否则会把结束标记当成 token 计数。6. 把评测流程固化下来到这里四项指标的采集和对照都跑通了。最后给你一个固化流程的建议把 config.toml 和采集脚本放进同一个仓库每次换硬件或换模型改配置跑一遍结果追加到对照表里。这样三个月后你回头看能清楚知道每个决策的依据是什么。需要长期做编码或 Agent 评测的Coding Plan 里有更完整的配额方案https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite想先验证模型输出质量再决定测哪个的直接开模型对话https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewriteKey 和接入参数以控制台和文档为准API Keyshttps://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keys接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite评测这件事跑一次不难难的是每次都用同一把尺子。把尺子固定下来数据才有意义。