LLM 推理的核心指标:TTFT、TPOT 与 Throughput 怎么测才准?TaoToken 统一 Key 通道实测
1. 为什么你测的 TTFT 和线上体验对不上很多人第一次做 LLM 推理性能评测都会遇到一个很尴尬的情况本地脚本跑出来的 TTFT 只有 200ms感觉挺快结果上线后用户还是抱怨打字机效果卡顿。问题往往不在模型本身而在于测量方式把三个指标混在一起了。先把概念理清楚。TTFTTime To First Token是从你发出请求到收到第一个 token 的时间它决定了用户点下发送后要盯着空白屏幕多久。TPOTTime Per Output Token是第一个 token 之后平均每个 token 的生成间隔它决定了文字流出来的顺滑程度。Throughput吞吐量则是单位时间内所有并发请求加起来生成了多少 token它直接对应你的推理成本。这三个指标的关系可以用一个公式串起来Latency TTFT TPOT × 输出 token 数。而 TPS单请求每秒 token 数 输出 token 数 / Latency。注意 TPS 和 Throughput 不是一回事前者是单请求视角后者是全局视角。常见的测量误区有这么几个。第一用非流式接口测 TTFT那测出来的其实是完整 Latency因为你要等所有 token 生成完才拿到响应。第二客户端计时把网络往返、DNS 解析、TLS 握手全算进去导致 TTFT 虚高换个网络环境数据就完全变了。第三固定并发下只测一次忽略了首请求冷启动、KV Cache 未命中的影响。第四输入长度不固定prompt 从 50 token 到 2000 token 混着测TPOT 波动巨大却找不到原因。我试过用同一份 prompt 在不同通道上跑TTFT 能差出三倍后来发现是有的通道做了请求排队。所以要做可复现的评测必须固定三件事输入长度、并发数、测量通道。这篇就围绕这三点给一套能直接复制运行的压测流程通道统一走 TaoToken 的 Key/API避免多供应商差异干扰。适合谁看正在做推理服务选型、想给模型接口做性能基线、或者需要向团队解释为什么并发一高就变慢的开发和运维同学。下面从环境准备开始一步步把三个指标测准。2. TaoToken 统一 Key 通道准备与压测环境搭建要做可复现的评测第一步是让所有对比实验走同一条通道。如果 A 模型走这家、B 模型走那家网络路径和网关策略都不一样测出来的差异根本说不清是模型的问题还是通道的问题。TaoToken 提供统一的 Key 和 API 入口把模型切换收敛到一个 Base URL 上这样你换模型时只需要改 Model ID网络层保持不变。先拿 Key。访问 https://taotoken.net/api-keys 登录后在控制台创建 API Key。建议给压测单独建一个 Key方便后续在用量页面区分实验流量和正常业务流量。创建后复制保存它只显示一次。Base URL 统一用 https://taotoken.net/api 注意这个地址不带任何查询参数。模型对话的调试入口在 https://taotoken.net/models 可以先用它确认某个 Model ID 是否可用再去写压测脚本。环境准备分两块。Python 侧建议用独立虚拟环境装 openai 和 httpxpython -m venv venv source venv/bin/activate pip install openai httpx numpy如果你更习惯命令行压测可以用 curl 配合 time 命令做单请求粗测但并发场景还是脚本更可控。设置环境变量避免 Key 硬编码进脚本export TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/api这里有个容易踩的坑Base URL 结尾不要自己加/v1。OpenAI SDK 会自动拼接路径你手动加了会变成/v1/v1/chat/completions直接 404。如果你用的是某些只认完整路径的老客户端才需要显式写全但用官方 SDK 就按上面这样。固定输入长度是评测的关键。准备一份约 500 token 的 prompt 作为基准可以用一段技术文档或者重复的说明文字。为什么强调固定因为 TTFT 和 TPOT 都受输入长度影响prefill 阶段要处理的 token 越多首 token 越慢。你可以在脚本里用 tiktoken 估算长度或者干脆用固定字符串保证每次一致。并发控制用 asyncio semaphore不要用多线程硬怼否则测出来的是你本机 CPU 的瓶颈而不是服务端的。下面进入具体配置。2.1 可复制的压测配置与参数说明先给一份完整的 Python 压测脚本它同时采集 TTFT、TPOT 和 Throughput。核心思路是用流式接口记录每个 chunk 到达的时间戳。import asyncio import time import os import numpy as np from openai import AsyncOpenAI API_KEY os.environ[TAOTOKEN_API_KEY] BASE_URL os.environ[TAOTOKEN_BASE_URL] MODEL_ID gpt-4o-mini # 换成你要测的 Model ID client AsyncOpenAI(api_keyAPI_KEY, base_urlBASE_URL) PROMPT 请用大约300字解释什么是KV Cache以及它对推理性能的影响。 * 3 async def single_request(sem, results, idx): async with sem: start time.perf_counter() first_token_time None token_times [] token_count 0 try: stream await client.chat.completions.create( modelMODEL_ID, messages[{role: user, content: PROMPT}], streamTrue, temperature0, max_tokens256, ) async for chunk in stream: if chunk.choices and chunk.choices[0].delta.content: now time.perf_counter() if first_token_time is None: first_token_time now token_times.append(now) token_count 1 end time.perf_counter() ttft (first_token_time - start) * 1000 if first_token_time else None if token_count 1: intervals np.diff(token_times) tpot float(np.mean(intervals)) * 1000 else: tpot None latency (end - start) * 1000 results.append({ idx: idx, ttft_ms: ttft, tpot_ms: tpot, latency_ms: latency, tokens: token_count, }) except Exception as e: results.append({idx: idx, error: str(e)}) async def run_benchmark(concurrency, total_requests): sem asyncio.Semaphore(concurrency) results [] tasks [single_request(sem, results, i) for i in range(total_requests)] wall_start time.perf_counter() await asyncio.gather(*tasks) wall_end time.perf_counter() wall_time wall_end - wall_start ok [r for r in results if error not in r and r[ttft_ms]] total_tokens sum(r[tokens] for r in ok) throughput total_tokens / wall_time print(f并发{concurrency} 成功{len(ok)}/{total_requests}) print(fTTFT P50{np.percentile([r[ttft_ms] for r in ok],50):.1f}ms fP95{np.percentile([r[ttft_ms] for r in ok],95):.1f}ms) print(fTPOT P50{np.percentile([r[tpot_ms] for r in ok],50):.1f}ms) print(fThroughput{throughput:.1f} tokens/s) if __name__ __main__: for c in [1, 4, 8, 16]: asyncio.run(run_benchmark(c, total_requestsc * 4))几个参数要说明。temperature0是为了让输出长度尽量稳定减少随机性对 TPOT 的干扰。max_tokens256限制输出上限避免个别请求生成超长文本拉偏吞吐。total_requests concurrency * 4保证每个并发档位有足够样本同时不会跑太久。如果你用 Cline 或 Claude Code 这类工具做接入测试配置项要写全三件套Base URL 填https://taotoken.net/apiAPI Key 填你的 KeyModel ID 填具体模型名。缺任何一个都会连接失败。Codex 用户如果走auth.json把 base_url 和 api_key 对应字段填好即可。2.2 固定并发与输入长度的实验设计实验设计决定了你的数据能不能用。建议按并发 1、4、8、16 四档跑每档至少 4 倍并发的请求数。为什么从 1 开始因为并发 1 是基线能反映单请求的真实 TTFT 和 TPOT没有排队干扰。并发上去之后如果 TTFT 明显上升而 TPOT 变化不大说明瓶颈在请求排队如果 TPOT 也涨说明 GPU 计算资源被抢占了。输入长度固定后还要注意输出长度。虽然设了 max_tokens但模型可能提前停止。所以统计 TPOT 时要过滤掉 token 数过少的样本比如少于 20 个 token 的请求否则均值会被拉偏。跑之前先做一次预热请求把连接池和模型加载的冷启动成本排除掉。预热就是正常发一个请求等它完成再开始正式计时。这一步很多人省掉结果第一档并发数据总是偏高。3. 验证请求与成功结果解读配置写好后先别急着跑全量。用一条 curl 命令验证通道是否通这是最快的排障手段。curl https://taotoken.net/api/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: gpt-4o-mini, messages: [{role: user, content: 说一句话}], stream: true }如果返回一串data: {...}的流式内容说明 Key、Base URL、Model ID 三件套都对。如果返回 401检查 Key 是否复制完整、有没有多余空格。如果返回 404八成是 Base URL 多写了/v1。跑压测脚本后你会看到类似这样的输出并发1 成功4/4 TTFT P50312.4ms P95358.1ms TPOT P5018.7ms Throughput52.3 tokens/s 并发8 成功32/32 TTFT P50890.2ms P951420.5ms TPOT P5024.1ms Throughput310.6 tokens/s怎么读这组数据并发从 1 到 8TTFT 从 312ms 涨到 890ms涨了近三倍说明请求在网关或服务端排队了。TPOT 从 18.7ms 涨到 24.1ms涨幅不大说明单请求的生成速度还稳。Throughput 从 52 涨到 310接近 6 倍说明并发确实提升了整体产出但没到线性8 倍存在资源竞争。这就是典型的用 TTFT 换 Throughput的权衡。在线流式应用对 TTFT 敏感并发不能开太高离线批处理对 Throughput 敏感可以牺牲 TTFT 把并发拉满。你的业务属于哪种决定了你该看哪个指标。验证成功还有一个标志所有请求都返回了内容没有 error。如果出现部分失败先看错误信息再对照下一节的排查表。4. 常见报错与排查对照压测过程中最容易撞上的几类错误这里逐个拆解。401 UnauthorizedKey 无效或没带上。检查Authorization头格式是不是Bearer sk-xxx中间有空格。环境变量有没有正确 export脚本里读的是不是同一个变量名。404 Not Found路径拼错。最常见的是 Base URL 写成https://taotoken.net/api/v1SDK 又拼了一次/chat/completions变成/api/v1/chat/completions之外的错误路径。正确写法就是https://taotoken.net/api。local proxy failed / connection error本机网络或代理配置问题。检查有没有设置HTTP_PROXY、HTTPS_PROXY环境变量指向了不可用的地址。压测脚本里可以显式传http_client禁用代理或者清掉这些环境变量。reading choices 相关报错通常是流式响应解析时chunk.choices为空数组代码没做判空。上面脚本里if chunk.choices and chunk.choices[0].delta.content就是防这个的。有些模型在流结束时发一个空 choices 的 chunk不判空会直接抛异常。OAuth / auth.json 报错如果你用 Codex 或 Claude Code 这类工具认证方式可能不是简单的 API Key。Codex 走auth.json时要确认字段名和层级正确Claude Code 走 Anthropic 兼容接口时 Base URL 和 Key 的填法要按文档来。这类工具报 OAuth 错误多半是认证模式选错了不是 Key 本身的问题。TPOT 为 None说明只收到了一个 token 或零个 token。检查 max_tokens 是不是设得太小或者 prompt 触发了模型的拒答。也可能是流式解析把内容过滤掉了。排查顺序建议先用 curl 确认单请求通再跑并发 1 的脚本最后上高并发。这样能把通道问题和并发问题分开定位。5. 把评测流程固化成可复现的基线测准一次不难难的是每次都能测出可对比的数据。建议把上面这套流程固化成三件事一份固定的 prompt 文件、一个记录实验参数的表格、一套统一的统计口径。prompt 文件存成 txt脚本读取保证每次输入完全一致。实验参数表格记录日期、Model ID、并发数、输入 token 数、max_tokens、TTFT P50/P95、TPOT P50、Throughput。统计口径统一用 P50 和 P95不要只看均值均值会被极端值带偏。每次换模型或换配置只改一个变量其他保持不变。这样你才能说清楚TTFT 涨了 200ms 是因为换了模型不是因为并发变了。如果你要长期做编码类或 Agent 类应用的性能跟踪可以考虑用 Coding Plan 把常用模型的调用额度固定下来避免每次实验都受额度波动影响。模型对话入口可以用来快速验证某个 Model ID 的可用性和大致响应速度确认没问题再写进压测脚本。最后提醒一点TTFT、TPOT、Throughput 三个指标没有哪个最重要只有哪个对你的场景最重要。在线聊天看 TTFT批量生成看 Throughput长文生成看 TPOT。把这三个数测准、记下来、能复现比追求某个绝对值更有意义。

相关新闻

Claude Code自定义配置指南:从记忆、命令到MCP与权限管理

Claude Code自定义配置指南:从记忆、命令到MCP与权限管理

说实话,Claude Code 装好就能跑,但“能跑”和“顺手”之间隔着一大截。我最开始用它改代码,几乎每开一个新会话都要重新解释一遍项目结构、代码风格、哪些文件不能动,甚至它写出来的提交信息格式每次都跟商量好了似的各不相同。浪…

2026/10/17 10:53:11 阅读更多 →
Java异步请求工具类设计与实现:CompletableFuture批量调用与超时控制

Java异步请求工具类设计与实现:CompletableFuture批量调用与超时控制

1. 为什么我们需要一个异步请求工具类做过微服务或者聚合类接口的兄弟应该都有体会,一个页面要展示的数据往往来自好几个下游服务。比如一个商品详情页,需要同时调商品基础信息、库存、价格、评价数、推荐列表,如果串行调用,每个接…

2026/10/17 10:53:11 阅读更多 →
Matlab实现吉布斯采样LDA主题模型:从原理到工程实践

Matlab实现吉布斯采样LDA主题模型:从原理到工程实践

简介:吉布斯采样是一种经典MCMC方法,适用于高维概率分布采样,与LDA主题模型结合常被用于文本主题推断。这份开源代码面向机器学习、文本挖掘研究者和相关开发者,给出了一套MATLAB下的GibbsLDA实现框架,包含主流程、单词…

2026/10/17 10:53:11 阅读更多 →

最新新闻

Vue el-input 输入限制全攻略:从字符集到光标修复与封装

Vue el-input 输入限制全攻略:从字符集到光标修复与封装

先讲一个我实际碰到的事。某后台管理系统要加一个注册用户名框,需求方原话只有一句:Vue 的 el-input 输入限制,只能输入数字、字母、下划线,其他配置照旧。我当时觉得这活儿五分钟就能干完,可真等写完丢给测试&#xf…

2026/10/17 11:46:34 阅读更多 →
Visual C++数字图像处理入门:从BMP解析到卷积滤波实战

Visual C++数字图像处理入门:从BMP解析到卷积滤波实战

1. 为什么机器视觉入门总卡在图像处理这一关很多人学机器视觉,第一反应是去搞深度学习、跑YOLO、调Transformer,结果连一张图怎么从磁盘读进内存、像素值怎么排列、灰度图为什么是单通道都说不清楚。我带过不少刚入行的朋友,十个里有八个卡在…

2026/10/17 11:46:34 阅读更多 →
C语言机试经典编程题:吃透六大考点与标准解法骨架

C语言机试经典编程题:吃透六大考点与标准解法骨架

简介:这是一份面向C语言初学者的机试经典编程题汇编,适合正在备考《程序设计基础》课程上机考试的学生使用。文档先明确了机试的组织形式、考核内容、考试规则与成绩占比,随后给出多道典型编程题及完整C语言参考代码,覆盖成绩等级…

2026/10/17 11:46:34 阅读更多 →
用策略模式替代繁琐if-else:实战重构与避坑指南

用策略模式替代繁琐if-else:实战重构与避坑指南

1. 从一坨“意大利面条”说起你有没有接手过那种一个方法写了三百行、里面套了七八层if-else的老代码?我最近就刚啃完一块这样的硬骨头。那是一个订单折扣计算模块,业务规则多到离谱:普通用户满减、会员折上折、新客首单立减、节日活动叠加、…

2026/10/17 11:46:33 阅读更多 →
网页背景音乐完整实现:跨浏览器自动播放与iOS兼容方案

网页背景音乐完整实现:跨浏览器自动播放与iOS兼容方案

1. 项目概述:为什么一个“网页播放背景音乐”的需求,值得花一整篇干货来拆解? “网页播放背景音乐实现完整代码”——这行标题看起来简单得像一句基础前端作业题,但我在过去十年带过的几十个前端项目里,它恰恰是 最容…

2026/10/17 11:46:33 阅读更多 →
大模型微调实战指南:LoRA参数高效微调的原理、策略与避坑技巧

大模型微调实战指南:LoRA参数高效微调的原理、策略与避坑技巧

大概两年前,我接手了一个企业内部知识助手项目,最初走的是纯检索增强加提示工程的路子,效果始终卡在“看起来能说,但关键数字总是一本正经胡说八道”的瓶颈上。后来把方案切换成对基座模型做针对性微调,才真正解决了领…

2026/10/17 11:45:33 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →