跳到内容

分段预填充(实验性)

本页将向您介绍 vLLM 中的分段预填充特性。

注意

此特性为实验性,可能随时更改。

为什么选择分段预填充?

两个主要原因

  • 分别调优首个 token 生成时间 (TTFT) 和 token 间延迟 (ITL)。分段预填充将 LLM 推理的预填充和解码阶段放在不同的 vLLM 实例中。这让您可以灵活地分配不同的并行策略(例如 tppp),以在不影响 ITL 的情况下调优 TTFT,或在不影响 TTFT 的情况下调优 ITL。
  • 控制尾部 ITL。如果不使用分段预填充,vLLM 可能会在一个请求的解码过程中插入一些预填充作业。这会导致更高的尾部延迟。分段预填充有助于解决此问题并控制尾部 ITL。使用适当块大小的分块预填充也可以达到同样的目的,但在实践中很难确定正确的块大小值。因此,分段预填充是控制尾部 ITL 更可靠的方法。

注意

分段预填充不会提高吞吐量。

使用示例

请参阅 examples/online_serving/disaggregated_prefill.sh以获取分段预填充的使用示例。

基准测试

请参阅 benchmarks/disagg_benchmarks以获取分段预填充的基准测试信息。

开发

我们通过运行两个 vLLM 实例来实现分段预填充。一个用于预填充(我们称之为预填充实例),另一个用于解码(我们称之为解码实例),然后使用一个连接器将预填充 KV 缓存和结果从预填充实例传输到解码实例。

所有分段预填充的实现代码都在 vllm/distributed/kv_transfer 下。

分段预填充的关键抽象

  • 连接器(Connector):连接器允许 KV 消费者(kv consumer)KV 生产者(kv producer) 获取一批请求的 KV 缓存。
  • 查找缓冲区(LookupBuffer):查找缓冲区提供两个 API:insert KV 缓存和 drop_select KV 缓存。insertdrop_select 的语义类似于 SQL,其中 insert 将一个 KV 缓存插入到缓冲区中,而 drop_select 返回匹配给定条件的 KV 缓存并将其从缓冲区中删除。
  • 管道(Pipe):一个用于张量传输的单向 FIFO 管道。它支持 send_tensorrecv_tensor

注意

insert 是非阻塞操作,而 drop_select 是阻塞操作。

下图展示了上述三个抽象的组织方式

Disaggregated prefilling abstractions

分段预填充的工作流程如下

Disaggregated prefilling workflow

buffer 对应于 LookupBuffer 中的 insert API,而 drop_select 对应于 LookupBuffer 中的 drop_select API。

第三方贡献

分段预填充与基础设施高度相关,因此 vLLM 依赖于第三方连接器来实现生产级别的分段预填充(vLLM 团队将积极审查并合并第三方连接器的新 PR)。

我们推荐三种实现方式

  • 完全自定义连接器:实现您自己的 Connector,并调用第三方库来发送和接收 KV 缓存,以及更多其他操作(例如编辑 vLLM 的模型输入以执行自定义预填充等)。这种方法提供了最大的控制权,但也存在与未来 vLLM 版本不兼容的风险。
  • 类数据库连接器:实现您自己的 LookupBuffer,并像 SQL 一样支持 insertdrop_select API。
  • 分布式点对点连接器:实现您自己的 Pipe,并像 torch.distributed 一样支持 send_tensorrecv_tensor API。