大模型性能指标TTFT与TPOT详解:从首字延迟到生成速度的优化实战 📅 发布时间:2026/9/18 18:01:09 👁 浏览次数: 前阵子帮一个做AI客服工具的朋友排查线上问题用户反馈很直接“我点完发送等了老半天才蹦出第一个字后面又一个字一个字往外吐急死人。”我们打开监控一看有点意思——服务端平均首字延迟只有800毫秒文档上也写着生成的token速度是“每秒5个”看起来不算离谱。但用户为什么会觉得慢问题就出在这两个指标上一个叫TTFTTime To First Token首token延迟一个叫TPOTTime Per Output Token单token生成耗时。它们一个管“第一个字什么时候来”一个管“后面的字多久能出来”合在一起才是大模型应用真正的“用户体感速度”。这篇文章我打算把这两件事彻底讲透。不管你是做AI应用开发、本地部署大模型还是纯粹想搞懂“为什么同样一个模型别人跑得那么快”都可以顺着往下看。我会把指标定义、生命周期、测试方法、优化手段、常见坑全部串起来尽量用我实际踩过的例子说话。1. 从用户体感说起为什么大模型应用的“快慢”不能只看一个数字1.1 两个典型的卡顿场景做AI应用的人一定遇到过两类完全不同的“慢”。第一类是“半天不出字”。用户输入问题点击发送然后界面一直在转圈等了三四秒才看到第一个字。这种慢最伤体验因为用户会怀疑服务是不是挂了。第二类是“首字秒出但越等越急”。比如输入问题之后几乎是秒回马上看到第一个字出来了但接下来的内容是一点一点往外冒每个字间隔明显一句话300个字能拖拉一分钟。用户觉得你在“挤牙膏”体验同样很差。这两类慢正好对应两个完全不同的性能指标。前者是TTFT太高后者是TPOT太高。很多团队上线大模型应用时只看一个平均首字延迟或者只盯着“完整响应时间”结果就是用户体感和监控数据严重脱节。1.2 TTFT与TPOT的直观定义TTFT全称Time To First Token指的是从客户端发出请求开始到客户端收到模型返回的第一个token所经过的时间。用吃饭来打比方这就好比你去餐厅坐下点菜从下单到第一道菜端上桌的间隔。这个时间越短用户越觉得“响应快”。TPOT全称Time Per Output Token是模型在生成阶段产出每一个token所消耗的平均时间。放到餐厅场景里就是第一道菜上来之后后续每道菜之间的上菜间隔。如果间隔太长你吃一顿饭会非常煎熬。这两个指标通常一起使用。TTFT决定了“能不能快速抓住用户注意力”TPOT决定了“后续内容能不能顺畅阅读”。两者相加再加上网络传输、前端渲染等开销才是一个用户的完整等待体验。1.3 为什么传统Web性能指标不够用做过Web开发的人都知道传统后端接口最关心的指标是“响应时间”也就是从请求发出到响应体完全返回的总耗时顶多再看一个“首字节时间”TTFB。但这个思路放到大模型应用上天然水土不服。原因在于大模型接口是流式输出的。正常情况下你不会等几百上千个token全部生成完才把结果推给用户而是用Server-Sent EventsSSE或者WebSocket把token一个个推给前端。用户看到的是“边生成边展示”不是等一个巨大的JSON包。这时候如果你还拿“完整响应时间”来衡量性能结果会非常极端生成长文可能要几十秒短回答可能只要一两秒。你不能说长文的性能就比短文差因为两者的输出长度根本不一样。更重要的是用户对“慢”的感知是分两段的第一段是“有没有反应”第二段是“速度顺不顺”。传统指标完全没法表达这种感受。所以TTFT和TPOT才会成为大模型应用性能评估的核心指标。后面我会拆开讲它们的本质、影响因素和优化思路。2. 核心指标拆解TTFT到底在衡量什么2.1 TTFT的完整生命周期从请求到第一个token别急着只看时间戳差值。TTFT不是一个简单的网络耗时它背后包含了好几个阶段。我按一个典型请求的路径拆给你看。客户端发起请求请求经过网络传输到达服务端。服务端网关、鉴权、路由等中间层处理。请求进入推理引擎的调度队列等待被某个GPU worker接收。GPU开始执行“预填充”阶段Prefill把用户输入的整个Prompt做一次前向计算生成第一个输出token同时把过程中产生的KV Cache写入显存。推理引擎把这个token通过网络返回给客户端。客户端收到第一个token。这里最关键的是第4步也就是Prefill阶段。它和我们通常理解的“生成”不太一样。在自回归大模型里生成第一个token时模型需要“看”完用户给的所有输入再做一次完整的Transformer前向推理。输入越长这一步的计算量就越大。我做一个粗略估算。假设你输入了1000个token模型是7B参数规模Prefill阶段大概需要执行次数为2乘以模型参数量再乘以输入长度的前向计算也就是约2乘以70亿再乘以1000等于1.4×10^13次浮点运算。如果用的是单张A100 80GFP16算力大约在312 TFLOPs理论上最快也要45毫秒左右。实际运行中还要算上显存读写、注意力计算、调度切换、网络开销所以拿到几百毫秒的TTFT是非常正常的。如果模型是70B输入还是1000token理论计算量直接涨到1.4×10^14次浮点运算单卡得跑近半秒还不包括多卡通信。所以你会发现很多大模型服务强调“我们TTFT低于1秒”听起来很轻松实际上对模型规模和硬件的要求相当高。2.2 影响TTFT的关键因素搞清楚生命周期之后TTFT的影响因素就很清楚了。我按重要程度列一下方便你排查时有个方向。第一模型规模和输入长度。模型参数越大单次Prefill的计算量就越大输入Prompt越长需要处理的数据越多。两者都是线性叠加的关系所以“用大模型处理长文档摘要”和“用大模型做一句话问答”TTFT完全不是一个量级。第二推理引擎和调度策略。同一张GPU你用原生HuggingFace Transformers跑和用vLLM、TensorRT-LLM这类带连续批处理和PagedAttention的框架跑TTFT可能差好几倍。原因很简单原生框架往往是一个请求占用整张卡别的请求来了只能排队而vLLM会把多个请求动态拼在一个batch里做Prefill显存利用率高排队时间就短。第三算力和显存带宽。Prefill阶段更吃算力GPU的FP16/BF16算力越高Prefill跑得越快。这也是为什么做在线大模型推理大家更愿意用A100、H100这类数据中心卡而不是普通游戏卡。第四队列和并发。请求多了之后即使单个Prefill计算量不大排队也会把TTFT拉高。实际生成场景中并发一旦上来TTFT的P95会快速上升这一条后面我会专门讲。第五网络RTT。如果你本地部署网络开销很小如果用API调用跨地域请求光网络往返就可能占掉TTFT的一半以上。测API的时候一定要把这个因素分开别把网络抖动算成服务端性能问题。2.3 怎么测TTFT才靠谱很多人测TTFT就是拿SDK简单记一下时间差。但有几个细节不处理好数据会非常虚。第一个细节是“起点”。TTFT的起点应该是客户端“真正发出请求”的时刻而不是你在代码里创建任务对象的时刻。如果用Python的openai库建议在调用stream接口之前记录时间戳而不是等到进入for循环再记录。第二个细节是“终点”。终点是客户端收到第一个数据块chunk里的第一个token的时刻。所以要确保你用的是流式接口并且解析的是第一个包含content增量的事件而不是建立连接的事件。第三个细节是“预热”。模型冷启动时权重还没加载到显存管线还没建立第一次请求会特别慢。测试之前至少要发几个请求让模型热起来不然你会把一个冷启动问题当成所有请求的典型表现。第四个细节是“统计口径”。TTFT受排队影响非常大单次测试不能说明问题。至少要压测几十上百个请求看P50、P95、P99而不是只报平均值。平均值很容易被大量短请求拉低长尾请求的实际体验往往更差。我常用的测量方式是这样的用Python写一个脚本通过OpenAI兼容的流式接口发送固定长度的Prompt记录“发送时间”和“第一个content增量到达时间”跑若干轮之后统一算百分位。代码很简单核心逻辑如下import time from openai import OpenAI client OpenAI(base_urlhttp://your-service/v1, api_keytest) def measure_ttft(prompt: str) - float: start time.perf_counter() stream client.chat.completions.create( modelyour-model, messages[{role: user, content: prompt}], streamTrue, max_tokens128, ) first_token_time None for chunk in stream: if chunk.choices and chunk.choices[0].delta.content: first_token_time time.perf_counter() break return first_token_time - start if first_token_time else None这里有个小技巧提前构造好一个固定长度的Prompt比如重复一段话凑成300个token这样每次测试的输入复杂度一致数据才有可比性。如果每次测试用的Prompt长度不一样TTFT根本没有横向对比的意义。3. 核心指标拆解TPOT、吞吐量与“每秒多少个字”的错觉3.1 TPOT的定义与单位TPOT的字面意思已经很清楚了。我习惯把它叫“单token延迟”单位通常是毫秒/token或者秒/token。但在实际项目里大家更常用它的倒数tokens per secondTPS也就是每秒能生成多少个token。比如TPOT是50毫秒那么TPS就是1秒除以0.05秒等于每秒20个token。这里必须提一个容易混淆的概念TPOT和“每字耗时”不一样。中文里一个汉字在分词后的token数不一定是一有时一个汉字可能对应一个token有时一个词两个汉字可能被拆成一个或多个token。所以你不能直接把TPS当“每秒多少个汉字”来用要结合具体分词器估算。粗略一点讲中文场景下一秒20个token大约相当于一秒十几个字到二十个字这不算快但已经能读了。自回归模型的生成机制决定了TPOT有它的特殊性模型在生成第N个token时必须把前N-1个token对应的KV Cache保留在显存里作为当前步的上下文。也就是说每一步都依赖于前面所有生成结果这是一个严格的串行过程没法像训练那样多个token并行计算。用写文章来打比方你只能一次写一个词写完第一个才能写第二个不能同时写两个词。3.2 影响TPOT的关键因素TPOT和TTFT的影响因素虽然都跟硬件、框架有关但侧重点很不一样。我总结成三句话TTFT看算力TPOT看显存带宽两者都怕显存不够。为什么TPOT看显存带宽因为在Decode阶段每一步生成一个token模型本身的计算量相对不大但GPU必须把整个模型的权重从显存里读一遍才能完成前向计算。这个“读权重”的时间往往比真正计算的时间还要长。举个具体例子。一个7B参数的模型如果权重是FP16精度占用显存大约是14GB。每一步生成token理论上都要把14GB权重从HBM显存读到计算单元。假设你用的GPU显存带宽是2TB/s那么单看读权重这一步理论下限就是14GB除以2TB/s等于7毫秒。这还没算KV Cache读取、中间激活、框架调度等开销。所以你会发现7B模型在高端卡上通常能做到每token二三十毫秒但在老显卡上可能跑到一两百毫秒差距就是这么来的。量化为什么对TPOT帮助巨大原因也在这里。模型从FP16变成INT8权重占用减半从INT8变成INT4权重占用再减半。同一个模型INT4量化后读权重的理论下限直接变成FP16的四分之一TPOT自然大幅下降。当然量化会带来一定的精度损失具体能不能接受要结合业务场景判断。除了硬件和量化Batch大小也是一个核心因素。GPU处理一个batch时如果batch里有多个请求那么读权重这件事是可以共用的同一个模型权重被多个请求同时使用显存带宽利用率更高整体吞吐上去了。但对单个请求来说因为计算资源被分摊了TPOT通常会变差。这就是在线服务和离线批处理在性能优化目标上的根本矛盾。3.3 从TPOT到TPS、吞吐量几个容易踩的换算坑测出TPOT之后很多同学会直接拿它的倒数当“最终速度”汇报但这里有几个坑。第一个坑是“单个用户的TPOT不等于服务端吞吐”。假设你并发100个请求每个请求的TPOT是200毫秒那么对单个用户来说每秒只有5个token。但服务端整体可能在同时处理多个不同的请求每秒产出的总token数可能是500个因为服务端在跑更大的batch。这里“单请求TPS”和“系统吞吐量”Throughput是两个概念。前者等于1000除以单请求TPOT后者等于batch中所有请求的token总数除以总耗时。做性能压测时一定要区分你是想评估用户体验还是评估系统容量。第二个坑是“用总生成时间除以token数量不等于TPOT”。因为总生成时间包含了首个token的Prefill时间。比如一个请求生成了100个token总耗时5秒平均每个token是50毫秒但实际TPOT可能更小因为5秒里还包括了Prefill的几百毫秒。更准确的做法是排除第一个token之前的时间只统计首token之后到结束token之前的平均间隔。这个才是稳定的Decode速度。第三个坑是“不考虑EOS停止”。模型生成到max_tokens上限时可能会被截断也可能提前输出结束符。如果你用总输出长度去除以总时间但输出长度没排除结束符精度会受影响。建议在流式接口里统计content增量的实际数量用它作为分子。第四个坑是“把TPOT和TTFT相加当作完整响应时间”。实际上完整响应时间还要算上生成最后一段后的结果整理和网络收尾时间。不过在大模型场景下用户通常不会等完整响应而是边接收边阅读所以“TTFT总生成时长”更适合作为“如果前端不做流式展示”时的最坏体验。3.4 为什么TPOT不可能是0有次评审会上产品经理问我“既然现在GPU这么强TPOT能不能做到0”我只能苦笑。不止他很多刚接触大模型的人都觉得生成速度应该快到无限。但自回归模型的每一步至少需要一次完整的Transformer前向计算哪怕是单层很小的模型也有数学运算和显存读写。只要不是“预先把所有答案背下来”TPOT就一定大于0。你可能会说那种“模板化回复”是不是TPOT接近0那是应用层直接返回固定字符串根本没走模型生成不算模型性能。真正的大模型应用只要走模型就得面对这个物理下限。我们在做架构设计时应该先接受这个约束然后再去追求“在合理成本下把TPOT压到可接受范围”。4. 评测环境与工具选型别让测试方法毁掉数据4.1 本地部署和API调用测法差在哪现在很多团队喜欢“本地部署AI大模型”自己做私有化推理服务。本地部署的好处是你能看到完整的日志、GPU监控、调度信息坏处则是配置复杂度高很容易测出一堆“看起来奇怪”的数据。本地部署时我最建议你用nvidia-smi或者DCGM持续监控显存、功耗、利用率。你会发现一个非常典型的现象Prefill阶段GPU算力利用率很高Decode阶段利用率可能不高但显存带宽占用很大。如果你看到Decode阶段GPU利用率一直在90%以上那说明当前batch已经非常大了单个请求的TPOT大概率已经很难看。API调用则完全是黑盒视角。你不能直接看GPU状态只能通过客户端时间戳计算TTFT和TPOT。这时候网络波动影响很大我建议至少分不同时段测多轮同时记录“请求到达服务端”这种服务端指标减少网络干扰。如果服务端不提供时间戳那只能在客户端多测几次取中位数。如果你想做本地部署配置上有一个容易被低估的点不要只看显存大小更要看显存带宽。同一家公司出的两张卡显存大小可能一样但带宽差一截跑大模型的速度会差很多。具体选择时可以把模型权重显存、KV Cache显存、中间激活显存都估一遍再拿带宽参数估算理论TPOT心里更有底。4.2 评测工具LLM Perf、vLLM benchmark、自建脚本该选哪个工具选型上我见过不少团队用自研脚本测也见过直接用框架自带benchmark的。我的建议是分层来看。如果你只是想快速评估一个推理框架的基线性能优先用框架自带的benchmark脚本。比如vLLM的benchmark_serving.py它会给你输出TTFT、TPOT、吞吐量等指标省去自己造轮子的时间。TensorRT-LLM也有类似的benchmark工具。这类工具的好处是测试方法和框架内置的trick保持了一致不容易踩到“框架实际支持但脚本没用到”的坑。如果你想做长期回归测试或者你们有自己的线上流量特征那我强烈建议写一套自己的评测脚本。原因很简单线上Prompt长度、并发模型、输出长度都有固定模式通用benchmark按固定参数测不一定符合你的真实场景。还有一个开源工具叫LLMPerf专门用来测大模型服务的SLO指标支持对TTFT、TPOT等做分布统计也很适合放在压测流程里。不过工具只是辅助最关键的是你要明确自己的测试目标是测延迟、测吞吐还是测稳定性测试目标不同脚本设计完全不同。4.3 请求并发怎么设计单路、并发、饱和度评测大模型性能并发设计是最容易草率的一步。很多人习惯“直接开100个并发跑一下”然后看平均指标发现TTFT很高就说服务不行。其实这个并发可能已经远远超过服务的合理水位。我更推荐“阶梯加压”的方式。从并发1开始测一组TTFT和TPOT然后并发4、8、16、32、64慢慢加压同时记录指标变化。你会看到一条曲线并发很低时TTFT和TPOT都很稳定因为每个请求都能立刻被处理。并发逐渐升高时TTFT开始缓慢上涨因为排队时间变长TPOT可能小幅上涨因为batch变大、单请求分到的资源变少。并发超过某个临界点后TTFT会快速上涨TPOT也可能恶化到完全不可用这时系统就已经“饱和”了。这条曲线非常有用。你可以根据业务预期的最大并发找到一个“既能满足TTFT/TPOT目标又能最大化吞吐”的并发水位。比如线上预期峰值并发20那么理想状态是并发20时TTFT的P95低于1.5秒TPOT的P95低于100毫秒。如果达不到要么加卡要么优化要么降低并发目标。还要注意客户端别成为瓶颈。压测脚本如果用单线程发请求瓶颈可能在Python的GIL不在服务端。建议用异步客户端或者多进程确保压测流量真正打到服务端。4.4 数据记录与统计P50、P95、P99别只报平均值“平均TTFT 800ms”这句话听起来不错但可能掩盖了10%的用户在等3秒的事实。平均值是很好看的汇报指标但做性能优化我必须看百分位。我习惯把压测结果整理成下面这种表格自己复盘也好跟团队汇报也好都很直观并发数TTFT P50TTFT P95TPOT P50TPOT P95吞吐 tokens/s1350ms400ms38ms42ms288520ms800ms55ms90ms14516750ms1500ms80ms130ms210321400ms3200ms120ms220ms260注意这个表格是示意数据不是某个固定模型的结果。但你可以看到只看平均值的话并发16似乎还能接受但如果你看一眼P95可能会发现已经有用户经历了1.5秒的首字延迟。做性能SLO时我更推荐以P95甚至P99作为硬性门槛比平均值可靠得多。还要统计时序趋势。压测持续10分钟后半段和前半段可能差别很大因为KV Cache碎片、显存占用、网络连接老化都会导致性能劣化。记录时间序列图能帮你提前发现这类隐患。5. 优化实战从TTFT和TPOT两个方向把应用调快5.1 降低TTFTPrefill提速、动态批处理、KV Cache优化聊完测试进入最实际的部分怎么把TTFT降下来。我的经验是先分清你现在的瓶颈在哪个环节再对症下药。如果是Prefill计算太慢优先考虑缩短输入长度。很多应用会把大量历史对话、系统提示词、检索结果全部塞进Prompt结果输入长度轻松超过2000token。同样的模型输入100token和输入2000tokenTTFT差出好几倍。建议做Prompt压缩、历史摘要、动态选择相关上下文能省一大截时间。我之前处理过一个检索增强生成RAG项目把Top-K文档从10个砍到4个输出质量几乎没下降TTFT却从2.8秒降到了1.2秒。如果是排队导致TTFT升高优先看推理框架是否支持连续批处理。vLLM默认支持continuous batching能把一个batch中已完成请求的算力立即让给新请求而不是等整个batch结束。如果你还在用老式的静态批处理并发一高TTFT必然爆炸。如果是KV Cache导致显存不足启用PagedAttention这类显存管理能力能显著减少显存碎片提升有效batch容量。另外主流框架支持KV Cache量化把KV Cache从FP16压到INT8显存占用直接减半能容纳更多并发请求间接降低排队时间和TTFT。最后别忘了模型预热和常驻。如果服务会自动缩容到0冷启动一次可能要几十秒第一个请求的TTFT自然惨不忍睹。线上服务至少要保持一个最小实例常驻才能给用户稳定的响应。5.2 降低TPOTDecode阶段优化、显存带宽、量化、并行策略降低TPOT的核心思路很直接减少每一步Decode需要读取的数据量或者提高单位时间的读取能力。我按见效快慢给你排个序。最立竿见影的是量化。把模型从FP16量化到INT8权重读取量直接减半TPOT通常也能近似减半。INT4效果更明显但精度风险更高。如果应用对输出质量敏感可以先试INT8再结合AWQ、GPTQ这类量化方法看效果。我自己的经验是7B模型INT8量化后在大部分任务上质量下降幅度很小但TPOT能提升30%到50%。其次是升级硬件换显存带宽更高的卡。这个不用多解释但要注意性价比。同样是跑7B模型消费级卡和数据中心卡的带宽差距很大如果是生产环境建议在预算允许的情况下选带宽高的型号。再次是投机解码Speculative Decoding。它的思路是用一个很小的草稿模型先快速生成几个token再由大模型一次性验证。验证通过就多跳了几步省去大模型逐步解码的时间。这个技术在小模型上用得越来越多但实现复杂且草稿模型和正式模型的分布要对齐否则收益可能为负。最后可以从应用层规避。有些场景不需要特别低的TPOT。比如用户阅读中文的速度大约每秒5到10个字如果你把TPOT优化到每秒50个token用户是感觉不出来的但成本可能翻了好几倍。所以TPOT不是越低越好够用就好。5.3 工程权衡TTFT和TPOT此消彼长怎么取舍做工程的人都明白系统优化永远是取舍。TTFT和TPOT虽然都是延迟指标但在高并发场景下它们通常会互相拉扯。一个典型矛盾是batch size。增大batch size能提升整体吞吐让服务在单位时间内处理更多请求但每个请求的TPOT会变差因为计算资源被摊薄了。同时增大batch也可能让排队长度变短因为请求被更快地吸收进批次TTFT反而可能下降。所以你会看到一个现象适度提高batch sizeTTFT降低TPOT升高过度提高TTFT和TPOT一起恶化。面对这种矛盾我的做法是给每个指标设定一个SLO上限然后在这个约束下最大化吞吐。比如聊天场景我要求TTFT的P95不超过2秒TPOT的P95不超过100毫秒也就是每秒至少10个token那么我会从并发1开始逐步加压找到同时满足这两个条件的最大并发。这个并发就是当前配置下的最优水位。超过它要么接受多花钱加卡要么接受降级。还有一个思路是把不同场景拆开部署。交互式聊天服务单独部署一批GPU走低延迟配置离线批处理任务比如批量文档总结用另一批GPU走超大batch和最高吞吐配置。两个场景的SLO完全不同混在一起只会互相拖累。5.4 真实项目中的优化优先级建议如果你看完前面的内容脑子里已经对优化方向有了很多想法但不知道从哪儿下手我按经验给你一个参考顺序。第一步先换推理框架。如果你还在用原生Transformers跑在线服务赶紧换成vLLM或者TensorRT-LLM。这一步通常能带来一到三倍的性能提升而且几乎没有风险。第二步做权重量化。结合精度评估把模型量化到INT8甚至INT4。这一步能同时降低TTFT和TPOT还能提高显存利用率支撑更多并发。第三步调并发和batch。给服务设置合理的最大并发数打开连续批处理然后压测找出SLO边界。第四步做Prompt优化。压缩输入长度、增加缓存把Prefill的负担降下来。第五步才考虑换卡或者加卡以及上投机解码这类高阶技术。前四步做好大多数项目的性能问题都能解决一大半。6. 常见问题与排查技巧实录6.1 本地部署配置到底怎么选才不踩坑很多同学对“本地部署AI大模型配置”很感兴趣但经常在选型时被显存吓住。其实只要记住一个粗略公式模型权重显存约等于参数量乘以每个参数的字节数。比如7B模型FP16精度权重大约是14GBINT8是7GBINT4大概3.5GB。你选显卡时显存至少要能放下权重还得给KV Cache留余地。KV Cache到底占多少它和模型层数、头数、单头维度、并发数、序列长度都有关系。粗略估算公式是2乘以层数乘以注意力头数乘以单头维度乘以batch大小乘以序列长度乘以每个字节数。7B模型一般有32层假设hidden size是4096那么每层KV Cache占用大约是4096乘以batch乘以序列长度乘以精度字节数具体数值不展开算但方向很清楚序列越长、并发越大KV Cache占用越夸张。选卡时不要只看显存够不够还要看显存带宽。我的经验是如果你主要做交互式聊天尽量选带宽高的卡如果你主要做离线批处理显存容量和算力更值得关注。同一预算下有时候两张中端卡比一张旗舰卡跑起来更稳因为可以分摊负载但也可能因为多卡通信带来额外开销具体要看模型拆分方式。6.2 并发一高TTFT就飙升怎么办这个问题几乎每个团队都会遇到。最直接的排查思路是先看是不是排队了。如果你用的是vLLM看日志里有没有很多请求在队列里等待以及max_num_seqs是不是设置得太小。如果请求已经进入GPU但TTFT还是高那就看Prefill阶段是不是被长Prompt拖累了。可以在请求进来前做一次Prompt长度分布统计看看有没有极端长尾。另一个容易忽略的地方是前端网关。有些团队在API网关层会做限流、鉴权、日志记录这些操作本身也会增加延迟。如果网关和推理服务不在同一个网络区域网络RTT也会算进TTFT。遇到并发一高TTFT就飙升记得把网关指标和推理服务指标分开看。实在不行就只能降并发或者加实例。这里我特别想说一句不要为了“看起来能扛高并发”而把最大并发数设得特别大那样只会让所有用户的TTFT和TPOT一起变差。设定一个合理的并发上限超过上限直接返回“系统繁忙”或者排队提示体验反而更好。6.3 首字挺快但生成越来越慢是怎么回事有一种很诡异的情况第一秒看起来还行TTFT只有几百毫秒但生成到一半速度肉眼可见地掉下来了。很多人以为是模型出问题了其实这大概率是长上下文导致的KV Cache膨胀。随着生成进行KV Cache会越来越大每一步Decode除了读模型权重还要读整段KV Cache。序列越长读KV Cache的时间越长TPOT自然越来越慢。更严重的是如果显存不够框架可能会把KV Cache换出到CPU或者重新计算recompute这时候生成速度会断崖式下跌。遇到这种情况我的建议是第一限制最大输出长度别让模型无限生成长文第二做显存监控看是不是KV Cache占满之后触发了换出第三如果应用场景必须长输出考虑滑动窗口注意力、稀疏注意力这类能控制KV Cache膨胀的模型架构。6.4 指标测出来很好看用户还是觉得慢这应该是最扎心的一种情况。服务端TTFT和TPOT都达标了用户还是觉得慢。这时候问题多半不在模型服务而在前后端链路和感知设计。先检查前端是否真的做好了流式渲染。有些前端框架默认是等接口全部返回再渲染就算服务端是流式输出用户还是什么都看不到。这种情况属于“后端快前端拖后腿”优化服务端没用得改前端。再检查网络链路。如果服务端和用户之间的网络RTT很高比如跨地域那就算服务端TPOT是20毫秒用户端看到的每token间隔也可能是50毫秒以上。这种问题只能通过边缘节点、CDN或者就近部署来解决。还有一个容易被忽略的因素是“心理感知”。当用户发出请求后如果界面上没有任何反应超过1秒就开始焦虑。就算你后面速度很快等待的焦虑感已经产生了。很多产品会在等待阶段安排一些轻量交互比如显示“正在思考中”或者让光标有呼吸效果这些设计虽然不算性能指标但能显著改善体验。做性能优化不能只盯着数字最终目标是让用户觉得“流畅”。我自己这些年做AI应用性能优化的体会是TTFT和TPOT不是两个孤立的技术指标它们背后是一整套工程链路的选择和取舍。你选择了多大的模型、用什么推理框架、怎么设置并发、怎么设计Prompt最后都会体现在这两个数字里。所以别把它们只当成监控面板上的数值而是当作用户体验的“翻译官”。最后再分享一个小经验做性能评估前先写下你业务场景的核心SLO。比如“聊天场景下TTFT P95小于2秒TPOT P95小于100毫秒”后面所有优化围绕这个目标做不要今天看TTFT不好就猛调TTFT明天看TPOT不好又推翻重来。稳定的指标口径和清晰的业务目标是少走弯路的关键。