完整文档索引见 llms.txt。 在任意 URL 后追加 `.md` 即可查看该页面的 Markdown 版本。
预填充-解码分离
预填充-解码(PD)分离,也叫分离式推理,是一种服务架构,它会将 LLM 推理的两个主要阶段,即预填充和解码,运行在分开的硬件资源上。“分离式预填充”和“分离式服务”这两个术语通常指的都是同一个核心思想:为每个阶段提供专用资源,以匹配它们在计算和内存需求上的差异。
将预填充和解码放在一起会带来什么问题
为了理解为什么共置会带来问题,我们先简要回顾一下 LLM 推理是如何工作的:
- 预填充:并行处理整个序列,并把注意力层中的 key 和 value 向量存入 KV 缓存。由于它会一次性处理所有 token,并执行大型矩阵运算,因此预填充是计算受限的,但对 GPU 内存的要求没有那么高。
- 解码:通过复用先前构建好的 KV 缓存,一次生成一个输出 token。每生成一个 token,都需要反复加载模型权重并访问不断增长的 KV 缓存。因此,解码需要快速的内存访问,但计算需求较低。
很长一段时间以来,标准的推理方式都是把这两个步骤放在一起运行。表面上看,这似乎很直接。
但在实际中,你往往会遇到多个请求同时到达。每个请求都有自己的预填充和解码需求,但同一时刻只能运行一个阶段。当 GPU 正忙于计算密集型的预填充任务时,解码任务就必须等待,这会增加 ITL;反之亦然。
由于预填充主要决定 TTFT,而解码会影响 ITL,把它们共置在一起会让你很难同时优化这两个指标。

预填充和解码共置带来的延迟上升。图片来源
为什么分离是合理的
PD 分离的思路很简单:把这两种差异很大的任务拆开,让它们不再互相干扰。下面是一个架构示例:
主要收益包括:
- 专用资源分配:预填充和解码可以在不同硬件上独立调度和扩展。例如,如果你的工作负载中存在大量提示重叠(如多轮对话或 agentic workflow),就意味着你的许多 KV 缓存都可以被复用。这样一来,预填充侧的计算需求就会更低,你可以把更多资源放到解码侧。
- 并行执行:预填充和解码阶段不再互相干扰。你可以更高效地并行运行它们,从而获得更好的并发能力和吞吐量。这种分离还可以改善尾延迟。在共置模式下,一个很长的预填充就可能让其后的所有飞行中解码请求都被阻塞,从而抬高 P95 和 P99 延迟。
- 独立调优:你可以对预填充和解码分别实现不同的优化技术(如张量并行或流水线并行),以更好地满足你对 TTFT 和 ITL 的目标。
多个开源框架和项目已经加入了对 PD 分离的支持,包括 SGLang、vLLM、Dynamo 和 llm-d。
分离并不总是银弹
尽管 PD 分离听起来很有前景,但它并不是一种放之四海而皆准的修复方案。
-
阈值很关键:如果你的工作负载太小,或者 GPU 配置并未针对这种方式做好调优,性能反而可能下降(在我们的测试中,可能下降 20-30%)。
-
本地预填充可能更快:对于较短的提示,或者当解码引擎具有较高前缀缓存 命中率时,在解码 worker 本地运行预填充通常更快也更简单。
-
数据传输成本:分离要求在预填充 worker 和解码 worker 之间快速且可靠地移动 KV 缓存。这意味着你的方案必须支持快速、低延迟、同时兼容不同硬件和网络环境的 通信协议。除非分离带来的性能收益超过数据传输成本,否则整体性能实际上可能 变差。供你参考的现有数据传输方式包括: NVIDIA Inference Xfer Library (NIXL)、 CXL、NVMe-oF。
在生产中,请考虑以下设计问题:
- 解码 worker 应该直接从预填充 worker 拉取 KV 块,还是双方都应该使用共享缓存层?
- KV 块应该在预填充结束后立即主动传输,还是等到解码真正需要时再惰性传输?
- 路由器应该如何决定是复用已有缓存、在本地执行预填充,还是把请求发送到独立的预填充池?
这些问题会把 PD 分离与 KV 缓存卸载 和 前缀缓存 连接起来。应当把它们视为同一套服务架构的组成部分,而不是彼此独立的调优旋钮。
-
缓存兼容性很重要:预填充 worker 和解码 worker 必须在 KV 布局、页大小、dtype、注意力变体以及任何额外缓存元数据上保持一致。异构 KV 类型(例如量化 KV 缓存、VLM encoder state,以及推测解码缓存)会让这种交接比传输一个标准的完整注意力 KV 张量更加复杂。
跨集群预填充-解码分离
在许多分离式系统中,预填充和解码机器位于同一个集群中,相互之间通过高速、低延迟互连连接。
跨集群(或跨数据中心)PD 分离意味着你会把工作流拆开,让预填充和解码阶段运行在完全不同的集群中,有时甚至位于不同的数据中心或区域。
为什么要跨集群拆分预填充和解码?
有两个主要驱动因素正在推动基础设施走向这种分布式模型:
-
合适的芯片做合适的事。预填充是计算密集型的,而解码更依赖内存带宽。芯片设计正在分化,以匹配这两种不同需求:
-
NVIDIA Rubin CPX 专为最大化预填充吞吐量而构建。
-
Groq LPU 则专门针对快速解码带宽进行设计。
问题在于,这些芯片并不总是部署在同一个地方。它们往往分布在不同集群中,并按硬件类型分组。如果你强行让预填充和解码待在一起,就无法充分利用每个阶段最合适的硬件。将它们拆开后,你就可以在计算优化型机器上运行长预填充,同时把解码保留在带宽优化型机器上。
-
-
灵活性。在生产环境中,预填充和解码的扩展速度并不均衡。流量会变化。提示长度会变化。前缀缓存命中率会变化。有时候预填充会成为瓶颈;有时候则是解码。
如果两个阶段被锁在同一个集群里,你就只能接受固定比例的资源配置。这可能导致一侧过度预配,另一侧却成为瓶颈。把两个阶段拆到不同集群后,你就能分别扩展它们。
核心问题:KV 缓存的移动
在预填充完成后,KV 缓存必须被发送到解码集群。在同一个集群内部,这件事成本很低;跨集群时,它可能代价高昂。之所以棘手,主要有两个原因:
- KV 缓存可能很大。通过网络传输它,可能会抵消更快预填充所带来的任何收益。
- 并非所有请求都能获益。短提示或已缓存提示几乎无法从远程预填充中获益,但你依然要承担网络成本。
因此,如果你天真地把所有请求都发往远程预填充集群,性能实际上可能会变得更差。
Prefill-as-a-Service
这篇论文 提出了 Prefill-as-a-Service(PrfaaS),作为一种让这种架构真正可行的实用方法。核心思路很简单:不要把所有请求都跨集群发送,而是有选择地发送。
- 将短请求或已缓存请求保留在本地
- 只把长的、未缓存的预填充发送到远程计算集群
这会把跨集群 PD 变成一个路由问题。调度器会基于提示长度(特别是未缓存 token 数)、前缀缓存局部性、预填充队列压力、解码容量以及可用网络带宽,来决定每个请求应该去哪里。
论文报告称,与标准 PD 基线相比,这种选择性方法取得了明显收益:
- 吞吐量提高 54%
- P90 TTFT 降低 64%
这些收益来自更好的资源利用率,而不只是更快的硬件。
你应该在什么时候使用跨集群 PD 分离?
这种部署方式最适合以下情况:
- 你的工作负载包含大量长的、未缓存的提示
- 你拥有一个理解缓存局部性、排队情况和带宽的调度器
如果你的大多数请求都很短,或者高度依赖缓存,那么通常更简单也更快的做法,仍然是把所有东西都保留在同一个集群里。