大模型收到提示词后,要先处理完整输入并建立 KV 缓存,随后才开始逐 Token 生成。这个前半段叫预填充。一个很长的提示词若整段占住 GPU,其他已经开始回答的请求就可能停在那里,等它处理完输入。

我核对了 Sarathi 论文、vLLM 调度器文档和 NVIDIA 的推理指标说明。分块预填充把长输入拆成几次计算,让调度器在块与块之间安排解码工作。原提示词没有被截短,变化的是计算日程。

长预填充会撞上短解码

预填充可以并行处理许多输入 Token,容易把 GPU 算力用满。解码每一步通常只为每个请求生成少量 Token,更受内存读取和调度影响。两种工作放在同一服务里,长预填充会形成一次很大的计算任务,正在流式输出的用户可能突然等得更久。

Sarathi 将预填充请求切成等长块,并提出 decode-maximal batching。调度器每轮放入一个预填充块,再用尽量多的解码请求填满剩余预算。论文关注两项后果,一是减少不同微批次工作量不齐造成的流水线空档,二是让预填充和解码能够共同利用 GPU。

vLLM 的当前调度配置会依据一轮中剩余的 max_num_batched_tokens 切预填充。它还允许给长预填充设置每轮上限,避免一条超长输入一次吃掉全部预算。多模态请求包含整块图像嵌入时,框架还要决定这些输入能否从中间切开,调度边界并不总能随意放。这个 Token 预算比只数请求更接近真实负载。一条两万 Token 的输入和一条两百 Token 的输入都算一个请求,占用却完全不同。等待会立刻显出来,调度也必须按实际 Token 数做决定。

块大小在两种延迟之间取舍

块较小,解码请求更快获得下一次运行机会,逐词间隔通常更稳。长输入要经过更多轮调度,完成全部预填充的时间可能增加,首词元也会来得更晚。块较大时,长输入更快推进,某一轮留给解码的空间却更少。

vLLM 关于预填充拆分的文档也承认,合适的块大小能够控制尾部逐词延迟,实际参数不容易一次猜中。输入长度分布、并发、模型大小和 GPU 都会改变平衡点。只拿一条固定短提示词跑吞吐,几乎看不到这项调度在生产中的作用。

验收时可以准备短问答、长文档和长输出三组请求,按真实比例混合到达。每个块大小都记录首词元延迟的中位数与 P99,再看逐词间隔和总吞吐。某项平均值变好时,还要确认长请求有没有被一再推后。调度器服务的是一批同时等待的人,不能只让最好测的那类请求赢。

参考资料