系统学习 AI 学习路径:从 GPU 运行时到推理、微调与 RAG 评估

版本信息最后核对:2026-10-25

inference-latency

推理延迟变高的定位与修复:把 TTFT、TPOT、排队、KV Cache、网络和 GPU 分开看。

现象

用户感觉“回答变慢了”,可能表现为首字迟迟不出现、流式输出中间卡顿、整体生成时间变长,或者吞吐没有明显下降但 P95/P99 延迟变差。监控上常见 num_requests_waiting 上升、KV Cache 使用率接近上限、GPU 利用率忽高忽低,也可能一切指标都正常,只有客户端观测到延迟。

先把三个量分开:TTFT 是从请求发出到收到第一个输出 token 的时间,包含排队、预处理和 prefill;TPOT 或 ITL 描述首 token 之后每个输出 token 的间隔,主要反映 decode 与批处理调度;端到端时延还受输出长度、网络和客户端解析影响。一个指标变差不代表同一根因。

同一服务可能对不同请求表现不同:短提示长输出慢,通常看 decode;长提示短输出慢,通常看 prefill 和 tokenizer;高峰期集体变慢,优先看排队与容量;只有远端客户端慢而服务端指标正常,重点查网络、代理缓冲和流式解析。

快速判断

用相同模型、相同提示、相同输出上限和相同并发复现一次,分别记录客户端与服务端时间。压测时固定数据集和请求速率,不要用一条随手请求的体感代替基线。

curl -N -sS http://<host>:<port>/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{"model":"<served-name>","messages":[{"role":"user","content":"<prompt>"}],"max_tokens":128,"stream":true}'

查看服务端指标。不同 vLLM 版本的指标名可能变化,先列出实际存在的名称:

curl -s http://localhost:8000/metrics \
  | grep -Ei 'vllm|ttft|tpot|itl|e2e|queue|waiting|running|kv_cache|prefix|spec_decode'

观察点:

同时看 GPU 和主机:

nvidia-smi --query-gpu=index,utilization.gpu,memory.used,memory.total,clocks.sm,power.draw,temperature.gpu --format=csv -l 1
nvidia-smi topo -m
top -H
vmstat 1

核对输入 token 数,而不是只看字符数。聊天模板、系统提示和工具定义都会增加 token:

python - <<'PY'
from transformers import AutoTokenizer
tok = AutoTokenizer.from_pretrained("<model-dir>")
messages = [{"role": "user", "content": "<prompt>"}]
ids = tok.apply_chat_template(messages, tokenize=True, add_generation_prompt=True)
print("tokens:", len(ids))
PY

常见原因

  1. 流量超过副本处理能力:请求到达速率、并发数或输出长度超过当前副本容量,请求在队列里等待。表现为 TTFT 先变差,随后整体时延升高;继续加压还会触发超时和重试,进一步放大负载。
  2. 批处理参数与负载不匹配:并发上限过低时 GPU 吃不满;过高时 KV Cache 紧张、请求互相抢占,TPOT 抖动。批 token 上限、chunked prefill 等设置也改变 prefill 与 decode 的资源分配。
  3. KV Cache 压力过大:上下文太长、并发请求太多或前缀缓存命中率低,都会让缓存更快达到上限。发生换出或重算时,单次请求的 TPOT 可能突然变大,日志与指标里能看到抢占或等待。
  4. 长提示与 prefill 阻塞:一个很长的 prefill 可能占住计算资源,使同一批次里的其他请求首 token 延后。chunked prefill 能降低阻塞,但切分方式和批大小会影响 TPOT 的平稳性。
  5. 网络、TLS 或代理缓冲:跨地域调用、丢包、重传、TLS 握手和反向代理缓冲都会拉大客户端时延。代理如果把流式响应攒成整包再转发,服务端早已生成,客户端仍会觉得首字很慢。
  6. tokenizer 与 CPU 预处理:提示很长、聊天模板复杂、工具 schema 很大,或 tokenizer 在 CPU 上与其他进程争抢时,预处理会拖慢首 token。对比字符数和 token 数可以快速判断输入是否被低估。
  7. GPU 争用与运行状态:同卡还有训练或其他推理进程、MIG 或时间片共享、温度或功耗限制、SM 时钟下降,都会让利用率看起来不低但实际变慢。张量并行的跨卡通信也会影响 TPOT。
  8. 投机解码开销:投机解码先让草稿模型或 n-gram 生成候选,接受率低时会增加计算与显存压力。它主要有机会改善 decode 吞吐,不保证改善 TTFT,低并发或短输出时甚至可能更慢。
  9. 冷启动、模型或版本变化:副本刚启动时的权重加载、编译和缓存预热会让前几个请求偏慢;升级引擎、修改聊天模板或更换模型 revision 后,输入长度分布和内核效率都可能变化。
  10. 测量口径不一致:把客户端网络时间当成服务端推理时间,或比较了不同输入输出长度、不同并发、不同流式设置的压测结果,会把正常差异误判为性能回退。

排查步骤

  1. 建立可比基线。固定提示集、输出上限、并发和流式开关,记录 P50/P95/P99 的 TTFT、TPOT 和端到端时延,同时保留吞吐与错误率。冷启动与稳定运行分开记录;不要拿空闲时的一次请求和高负载时的平均值直接比较。

  2. 先判断瓶颈阶段。用短输出测首 token,用固定较短提示测长时间 decode;再逐步增加提示长度和输出长度。若延迟随提示长度增长明显,重点查 prefill、tokenizer 和长请求调度;若随输出长度增长,重点查 decode、KV Cache 与批处理。

  3. 检查队列和缓存。观察等待请求、运行中请求、KV Cache 使用率与抢占迹象。若等待请求持续增长,先确认总容量和输入输出长度;若缓存压力高但 GPU 计算利用率不高,检查批大小、上下文上限和前缀复用策略,而不是只增加并发上限。

  4. 验证 tokenizer 成本。在服务所在主机测一次 tokenize 与聊天模板耗时,并统计输入 token 分布。如果客户端发来的提示远比基准长,问题可能是提示构造、系统消息膨胀或检索结果拼接过多,而不是引擎退化。

  5. 分别测本机与远端。在服务所在主机直连一次,再通过网关或公网调用一次,比较首字节、token 间隔和总时长。若本机快、远端慢,检查 DNS、TCP 重传、TLS、反向代理缓冲、连接复用和客户端是否启用了流式读取。

  6. 观察 GPU 的实际状态。确认是否有其他进程、是否发生降频或温度限制、是否存在跨 NUMA 或跨节点通信。GPU 利用率只是一个信号:利用率低可能是 CPU 或调度受限,利用率高也可能只是大量低效小批次在空转。

  7. 核对批处理与上下文参数。一次只改一个参数,并用同一负载复测。减少上下文或并发可能改善时延,但也会降低吞吐;开启 chunked prefill 或前缀缓存前,先确认请求是否共享前缀、长提示占比是否足够。参数名和默认行为随版本变化,以当前引擎文档为准。

  8. 单独评估投机解码。在同一模型、同一数据集上分别关闭和开启投机,比较 TTFT、TPOT、吞吐和接受率。只有接受率足够高且 decode 是主要瓶颈时,收益才可能出现;低并发和短输出要充分测试,避免用更复杂的配置换来更差的首字延迟。

  9. 排除版本和配置漂移。对比最近变更:引擎版本、驱动、CUDA、模型 revision、tokenizer、聊天模板、代理配置、副本数和资源限制。把基线负载在旧版本上重跑一次,确认是代码变化还是环境变化。

修复与验证

预防

为不同模型和接口分别定义 TTFT、TPOT 与端到端时延目标,按输入输出长度和流式模式拆分看板。持续记录排队数、KV Cache、GPU 时钟与利用率、tokenizer CPU、代理延迟和客户端首字节时间,避免只看一张 GPU 利用率图。

上线前用真实提示分布压测并保留容量余量,在引擎升级、模型更换和提示模板修改后重跑基线。给长上下文入口设置配额,限制无界输出;把代理缓冲、流式转发和客户端读取方式纳入联调。把性能回退与版本、配置、流量变化放在同一时间线上。

相关命令

参考链接

读完自测

合上页面,先回答,再展开对照。

  1. TTFT 变高而 TPOT 正常,和 TTFT 正常而 TPOT 变高,排查方向有什么不同?
  2. 等待请求很多、KV Cache 使用率很高时,为什么不能只调大并发上限?
  3. 投机解码为什么可能让延迟变差?应该怎样验证是否值得开启?
答案
  1. TTFT 主要由排队、预处理和 prefill 决定,应先看到达速率、长提示、tokenizer 和首 token 前的代理延迟;TPOT 主要由 decode 和批处理调度决定,应看 KV Cache 压力、批大小、GPU 争用、通信和投机开销。两者同时变差时先处理排队和容量,再细分。
  2. 并发上限只是允许更多请求进入运行状态,并不增加显存和计算能力。KV Cache 已接近上限时继续提高并发,可能触发抢占、换出或重算,使 TTFT 和 TPOT 更差。应先根据上下文长度和显存调整容量,或减少长请求、增加副本。
  3. 草稿模型或候选生成本身要占用计算和显存,接受率低时这些工作被浪费,首 token 和并发延迟都可能变差。应在相同数据集、相同并发下分别关闭和开启投机,比较 TTFT、TPOT、吞吐与接受率,而不是只看一次生成的体感。
微信小程序码:扫码打开命令速查小程序

小程序版

微信扫码,随时查命令