首 token 为什么这么慢:TTFT 的构成与优化清单
分清首事件、首 token 与首字上屏,拆解检索、排队、prefill 和渲染的延迟;用分阶段埋点、缓存对照与峰值压测找到真正瓶颈。
更新与核对 · 2026-10-11
点击“讲解”,三秒后才出现第一个字。这三秒可能花在检索、排队、长输入,也可能是代理缓冲住了流。先测时间花在哪里,再选择优化项,比直接换模型或 GPU 更可靠。
TTFT(Time To First Token)描述首 token 延迟;TPOT(Time Per Output Token)描述后续输出 token 的平均耗时。前者影响多久看到答案,后者影响答案是否持续卡顿。
三种“开始响应”要分开统计
| 指标 | 起止点 | 能解释什么 |
|---|---|---|
| 模型侧 TTFT | 推理服务收到请求 → 生成首 token | 排队和模型执行 |
| 客户端首内容延迟 | 发出模型请求 → 收到首个内容增量 | 网络、网关和模型 |
| 首字上屏 | 用户提交 → 有意义文字完成渲染 | 用户真实等待 |
SSE 心跳、连接确认、空增量不算“首字”。推理或工具事件可能早于自然语言回答,应分开记录首事件与首个可展示内容。
图 1 · 缓存主要影响输入处理阶段,整个链路的其他部分仍需测量。
模型调用前还有鉴权、OCR、检索与重排。排查时可近似分解:
首字上屏 ≈ 业务准备 + 请求传输 + 排队
+ 输入处理与首个可展示输出生成 + 流传输与渲染
阶段可能重叠,实际用时间戳测量,不能机械累加各服务总耗时。普通逐 token 文本生成的端到端时间约为 TTFT + (输出 token 数 - 1) × TPOT;工具循环与隐藏推理需要分轮计时。
Prefill 和 decode:理解方向,别背吞吐数字
Prefill 处理输入并建立后续生成状态,decode 在此基础上逐步产生输出。常规自回归 Transformer 的 prefill 往往更易并行,低批量 decode 往往更受内存带宽制约;长上下文注意力、大批量、量化、硬件和调度都能改变瓶颈。
“某显卡每秒固定多少 token”不是可移植常数。基准比较至少要同模型、精度、输入输出长度、并发和缓存条件。缩短输入通常有助于 TTFT,不能保证时间严格线性缩短。
KV cache 保存之前 token 的注意力键值,避免生成每个新 token 时重复计算。跨请求前缀缓存进一步复用重复输入;它与单请求内部缓存有关,但不是“开流式就自动缓存”。
缓存收益要放进整条链路看
固定提示、工具定义、文档前缀适合置于变化内容之前。命中取决于模型、配置、寿命和路由;文字看起来相同不代表完整前缀相同。OpenAI 缓存文档[4]与 Claude 缓存文档[5]说明各自条件。
假设测到如下耗时,仅作计算示例:
| 阶段 | 冷请求 | 缓存命中 |
|---|---|---|
| 检索与重排 | 300 ms | 300 ms |
| 网络与网关 | 100 ms | 100 ms |
| 排队 | 400 ms | 400 ms |
| 输入处理与首输出 | 800 ms | 300 ms |
| 流传输与渲染 | 100 ms | 100 ms |
| 总计 | 1700 ms | 1200 ms |
输入处理减少 62.5%,总等待只减少约 29%。若高峰排队达两秒,缓存更不能单独解决问题。不要用“缓存了四分之三输入”推断“总耗时减少四分之三”。
自建推理:调度有收益,也有取舍
Continuous batching 会持续加入和移出请求,并非必须等固定批次全部结束。并发有助于吞吐,也可能增加排队或 token 间隔,需用实际负载压测。
Chunked prefill 将长输入分块,减少对正在 decode 请求的干扰;较小的块也可能让新请求完成 prefill 更晚。因此它在首字、卡顿与吞吐之间取舍。vLLM 调优文档[1]
Prefill/decode 分离适合部分大规模部署,但有 KV 传输、调度和容量配比成本,先确认瓶颈。Speculative decoding 主要加速输出阶段,收益依赖草稿接受率,不能作为首字优化的通用答案。
一套能定位问题的实验
每次任务关联 trace_id,记录提交、检索结束、模型发起、首事件、首内容、首帧与完成。服务端用单调时钟测阶段时长,跨端关联考虑时钟偏差。
至少比较短输入冷缓存、长输入冷缓存、长输入热缓存、真实峰值并发四组。固定输出上限和配置,分别看 p50/p95/p99、错误率、缓存命中和费用,不能混成一个均值。
首内容到达却不上屏,检查代理缓冲、SSE 读取和渲染;低并发快而峰值慢,检查队列和容量;长输入慢,检查工具结果和历史;首字快后续卡,检查 token 间隔。
优化顺序与产品目标
- 修无意的串行等待、代理缓冲和重复检索。
- 通过质量回归后裁剪历史与工具结果。
- 稳定可缓存前缀,分别测冷暖请求收益。
- 路由模型、限制输出长度,为交互请求保留容量。
- 自建服务再评估调度、量化和部署分离。
“两秒”可作某个交互场景的初始目标,并非人类感知硬边界。短问答、长报告和语音应有不同 SLO。等待时展示真实进度、允许取消,不能用伪造“思考过程”掩盖延迟。取消也应传到上游,尽量停止无用计算。
参考资料
正文中的编号可跳转至对应来源。工程报告、官方文档与研究论文分别标注;支撑范围说明该资料能证明什么,以及不能推导什么。
- [1]官方文档vLLM — Optimization and Tuning
支撑范围: 自部署推理的吞吐与延迟配置;配置需匹配模型、硬件和负载。
- [2]官方文档vLLM — Metrics
支撑范围: 推理指标及其起止口径;端到端用户延迟需另行测量。
- [3]官方文档OpenAI — Latency optimization
支撑范围: 减少请求、输入输出与等待的延迟方法;收益随任务和模型变化。
- [4]官方文档OpenAI — Prompt caching
支撑范围: OpenAI 提示缓存条件与 usage 语义;缓存不等于答案缓存或零费用。
- [5]官方文档Claude — Prompt caching
支撑范围: Claude 缓存读取、写入与生命周期;计费字段不能与其他厂商直接互换。