LLM延迟:TTFT与token间隔
流式回答很快出现第一句话,后面却停顿;另一个服务开始得慢,开始以后却输出得很顺。只看总耗时,很难区分这两种体验。首token延迟与后续token间隔应分开记录。
先把测量边界写清楚
在客户端,设发出请求的时间为t0,第一个真实内容token到达时间为t1,最后一个为tn。我们定义TTFT=t1−t0,末token延迟=tn−t0,后续平均间隔=(tn−t1)/(n−1),要求n至少为2。这里只有一个token时,后续间隔没有定义,不应伪造为0。
这是本文的客户端定义,并不自动等于推理服务器内部的计时口径。vLLM官方指标分别提供首token、token间隔和端到端延迟统计。接入监控前应确认版本与测量边界,包括排队、网络和响应结束事件是否被计算。
平均值怎样掩盖停顿
图中TTFT是0.6秒,末token延迟1.5秒。后续间隔约为0.2、0.2、0.5秒,平均0.3秒。平均数看起来稳定,却掩盖了最后一次更长的等待;因此还要看单次请求的间隔和整体分布。
from math import isclose
def measure(start, arrivals):
if not arrivals or arrivals[0] < start or any(b<a for a,b in zip(arrivals,arrivals[1:])):
raise ValueError('invalid timestamps')
gaps = [b-a for a,b in zip(arrivals,arrivals[1:])]
return arrivals[0]-start, arrivals[-1]-start, gaps, (sum(gaps)/len(gaps) if gaps else None)
ttft, end, gaps, mean_gap = measure(0, [.6,.8,1.,1.5])
assert isclose(ttft,.6) and isclose(end,1.5)
assert isclose(mean_gap,.3) and isclose(max(gaps),.5)
assert measure(0,[.6])[3] is None
print('TTFT:', ttft, 'last-token latency:',end)
print('gaps:',gaps, 'mean:',mean_gap)
代码已经执行,验证首token、末token、平均间隔、最大间隔与单token边界。实际网络数据块可能包含多个token,不能把一次流式回调天然当成一个token。若只有数据块时间,应明确命名为块间隔,避免伪装成token指标。
优化要对应等待发生的位置
首token慢,可以继续分解排队、输入处理和传输;后续间隔长,则检查生成过程、调度与客户端缓冲。不能仅凭这两个数字就断定某个组件故障,还需要服务端证据。
比较部署方案时固定输入长度、输出长度、并发与缓存状态,并报告尾部延迟及失败请求,避免只挑成功的短回答。端到端时间也可能包含末token之后的收尾工作,和本例的“末token延迟”要区分。
前缀缓存可能改善输入阶段,但不会自动消除每一次输出停顿。先确定改善的是哪个指标,再讨论用户体验是否变好。
参考资料
补发说明:实际补发日期为北京时间2026年10月10日,文章日期保留原计划2026年10月10日14:00。代码为原创教学验证,没有运行真实模型性能测试。
支持
如果这篇文章对你有帮助,欢迎支持本站。
二维码可点击放大。更多支持方式见支持页面。


