CHAPTER 08 / 推理与系统
从模型调用到推理服务
沿着一个请求,读懂 prefill、decode 与延迟指标。
- 区分 prefill 和 decode,定位首 token 与后续 token 的等待
- 从时间戳计算 TTFT、ITL、TPOT 和端到端延迟
- 规划可复现的本地服务实验并记录硬件与软件条件
一个请求经过哪些地方
模型文件能够生成文本,不代表它已经是一项稳定服务。一次请求通常经过 HTTP 接入、鉴权与输入校验、聊天模板渲染、分词、排队、模型执行、结果解码和流式传输。Agent 还可能在两次模型调用之间等待工具。用户感到“慢”,既可能来自 GPU,也可能来自网络、排队或检索。先画出请求路径,再给关键边界打时间戳。
服务端负责模型权重、执行计划和 KV cache,客户端负责构造请求、消费流与处理超时。部署前先确认模型许可证、所需内存、上下文长度和聊天模板。能够加载权重只是第一步,仍需为缓存和运行时临时空间留出余量。不要把下载大小直接当作峰值显存需求。
两种阶段,两种工作形态
prefill 处理输入序列,为各层建立可复用的历史状态,并得到用于生成首个输出 token 的信息。已知的输入 token 可以在因果掩码约束下并行计算,因此长输入常形成较大的矩阵运算。decode 则把新生成 token 加入序列,继续预测下一个 token;后一个 token 依赖前一个结果,单条序列具有串行链。
在常见负载中,长 prefill 更容易受计算吞吐限制,低并发 decode 更容易受内存带宽限制,但这只是判断假设。模型结构、上下文长度、批大小和设备都会改变瓶颈。增大输出长度主要增加 decode 轮次;增大输入长度会增加 prefill 工作,也会让后续 attention 读取更多历史。不能用一个固定“每秒 token 数”覆盖所有输入输出组合。
让时间指标有一致口径
TTFT 是从发送请求到收到第一个有效输出 token 的时间,客户端口径通常包含网络与排队。ITL 是相邻输出 token 之间的时间间隔;TPOT 常按首 token 之后的平均输出时间计算,即 (末 token 时刻 − 首 token 时刻) ÷ (输出 token 数 − 1)。只有一个 token 时该公式没有定义。端到端延迟则从发送请求到完整响应结束。
例如请求在 0 秒发出,三个 token 在 0.8、0.9、1.2 秒到达,则 TTFT 为 0.8 秒,ITL 为 0.1 与 0.3 秒,TPOT 为 0.2 秒。若响应在 1.25 秒结束,端到端延迟为 1.25 秒。平均流速会掩盖中间的停顿,因此既要看平均值,也要看分布。实际网络流的一个 chunk 可能含多个 token,不能把 chunk 间隔自动当作逐 token ITL。
本机实验:从时间戳重建体验
下面是合成时间戳实验,单位都是秒。它不依赖真实网络,因此每次运行结果一致。保存为 latency_lab.py 后运行 python3 latency_lab.py,先手算再对照输出。
from statistics import mean
sent = 0.0
tokens = [0.8, 0.9, 1.2]
finished = 1.25
itl = [b - a for a, b in zip(tokens, tokens[1:])]
metrics = {
"TTFT": tokens[0] - sent,
"ITL": itl,
"TPOT": mean(itl) if itl else None,
"E2E": finished - sent,
}
for key, value in metrics.items():
print(key, value)
assert abs(metrics["TPOT"] - 0.2) < 1e-9
# An extra second of queueing shifts every response event.
shifted = [t + 1.0 for t in tokens]
assert abs((shifted[0] - sent) - 1.8) < 1e-9
assert all(abs((b-a) - d) < 1e-9
for (a, b), d in zip(zip(shifted, shifted[1:]), itl))额外排队让 TTFT 增加一秒,ITL 却不变。接着把最后一个 token 推迟半秒,同时把 finished 更新为不早于最后一个 token 的时刻,例如把 tokens[-1] 改为 1.7、finished 改为 1.75。检查 TTFT 保持原值,而 TPOT 与端到端延迟上升;响应结束时间不能早于最后一个 token 到达时间。这个区分会直接决定下一步检查队列,还是检查 decode 与传输。
接入 vLLM 时先建立最小基线
有合适设备时,按下方 vLLM 官方 Quickstart 与安装页面选择与你的操作系统、加速器和驱动相匹配的环境。本教程不固定 CUDA 版本或默认启动参数,这些随版本与平台变化。先选官方支持且放得进设备的模型,记录模型完整名称、revision、vLLM 版本、硬件和启动参数,然后按官方在线服务示例发送一个短请求。
依次验证非流式返回、流式输出、异常输入和客户端取消。随后固定提示词与输出上限,先测并发一,再逐步增加并发。将服务启动、模型加载、首次内核编译等冷启动时间单独记录,预热后的结果另成一组。没有 GPU 也能完成本章时间戳实验;不要把模拟数据包装为真实推理性能。
客户端超时与服务端取消也应分开验证。客户端不再等待,并不一定意味着后台生成已经停止;持续浪费的请求会占用后续用户的排队位置。给请求保存唯一编号,检查取消后资源是否释放。设置长度上限和合理超时,既帮助建立明确容量边界,也让失败能够被解释为输入超限、排队超时或执行错误。
吞吐量和体验需要同时报告
吞吐量要写清分母与统计对象。输出 tokens/s、输入加输出 tokens/s、完成请求数/s 是不同指标;长答案可能提高 token 吞吐,却让每个用户等待更久。报告时固定输入长度、输出长度、到达模式和并发范围,包含错误数及超时数。仅统计成功且快速完成的请求,会把过载服务伪装成高性能服务。
观察到 TTFT 高、ITL 稳定时,先检查队列和 prefill;两者同时升高时再查资源争用、内存压力与调度。服务端指标和客户端时间戳必须分别标明测量位置。不同机器的时钟不能随意相减,分段耗时应尽量在同一单调时钟上计算。这些记录能让一次“感觉快了”变成可以复核的实验。
LEARN BY DOING
为一条流式响应建立延迟报告
- 运行标准库实验,并画出发送、首 token、后续 token、响应结束的时间线。
- 构造仅增加排队时间、仅增加后续 token 间隔两种变体。
- 有设备时按照 vLLM 官方文档启动服务;无设备时提供明确标记的模拟事件记录。
- 整理一张表,分别列出 TTFT、TPOT、端到端延迟、输出 token 数和测量位置。
验收标准
- 基线计算出 TTFT 0.8 秒、TPOT 0.2 秒和 E2E 1.25 秒。
- 能够说明网络 chunk 与 token 的差异,单 token 情况不会除以零。
- 真实实验记录模型、版本、硬件、预热方式与失败请求数;模拟实验明确注明未运行模型。
合上书,检查一下
先作答,再看解释。答错的地方,正好是值得再读一遍的地方。
配合本章看视频
下面按本站章节主题选配。为什么没有采用原课录播 →
大模型推理-KV cache高效推理必备技术 ↗
简介明确围绕自回归解码冗余、KV cache 显存和计算量展开,与推理服务及 KV cache 章节直接对应。
带着问题看 · 区分 Prefill 与 Decode;理解缓存的是哪些中间结果;用本平台 KV cache 计算器检查序列长度、层数与并发数如何改变显存需求。
查看来源与观看说明 →Stanford CS336 · Lecture 10: Inference (Spring 2025) ↗
用同一套性能模型串起推理成本、KV cache 与批处理,是系统部分的主参考课。对应第 7 章时只补充服务侧成本取舍,不代替模型路由策略。
带着问题看 · prefill 与逐 token 解码的计算/内存差异;TTFT、延迟、吞吐之间的取舍;KV cache 大小、continuous batching 与 PagedAttention;量化和 speculative sampling 的不同精度保证。
查看来源与观看说明 →vLLM: Easy, Fast, and Cheap LLM Serving ↗
由 vLLM 共同作者讲解推理服务;Stanford CS336 官方推理讲义也直接推荐这条演讲。
带着问题看 · 将单模型生成转变为面向多用户的服务;KV cache 的内存浪费与分页管理;从内存管理理解批量吞吐收益。
查看来源与观看说明 →MIT 6.5940 · Lecture 13: LLM Deployment Techniques (Fall 2024) ↗
用高校公开课补充大模型部署与压缩优化的背景,配合本站量化章节理解资源约束。
带着问题看 · 对比 SmoothQuant、AWQ 等量化方法;区分低比特量化与推测解码的机制;结合官方讲义中的 speculative decoding 和 batching,检查加速的硬件、负载和质量前提。
查看来源与观看说明 →