# 大模型系列:深度解析 Prefill-Decode 分离式部署架构 > **来源**:知乎专栏 > **作者**:猫先生 > **发布日期**:2025-06-17 > **原文链接**:https://zhuanlan.zhihu.com/p/1918334902492963669 --- 〔更多精彩AI内容,尽在「魔方AI空间」,引领AIGC科技时代〕 > 本文作者:猫先生 > 【从零走向AGI】旨在深入了解通用人工智能(AGI)的发展路径,从最基础的概念起,逐步构建完整的知识体系。 > 项目地址 : --- 在上一篇文章中,我们介绍了NVIDIA 发布的Dynamo框架及其PD分离式部署技术,旨在优化大语言模型(LLM)推理过程中的资源利用和推理效率。 《大模型系列:NVIDIA Dynamo框架详解——PD分离式部署技术解析》 Dynamo的PD分离式部署技术通过优化资源分配和推理流程,显著提升了LLM推理的效率和资源利用率,有望成为未来AI推理服务的重要架构。 那么,本文将深度解析 Prefill-Decode 分离式部署架构的原理!! 我们开始吧!! ## 一、什么是Prefill-Decode分离架构 **预填充-解码阶段分离**是一种用于处理长上下文大型语言模型(LLMs)的方法,旨在通过将推理过程分为两个主要阶段——**预填充(Prefill)和解码(Decoding)**,这两个阶段被拆分到不同的 GPU 实例上独立运行。如下图所示,DistServe论文中的架构图。 ### 预填充阶段(Prefill Phase) - **目标**:预填充阶段的主要目标是处理输入序列的所有输入token,以构建键值缓存(KV Cache)。这个缓存用于存储中间计算结果,以便在后续的解码阶段重用。 - **特点**:预填充阶段通常是**计算密集型的**,因为它需要处理整个输入序列,并生成初始的输出标记。由于注意力机制的计算复杂度与**输入序列长度的平方**成正比,因此**长序列的处理需要更多的计算资源。** ### 解码阶段(Decoding Phase) - **目标**:解码阶段的任务是**基于预填充阶段构建的键值缓存**,逐个生成输出token。由于每个新生成的token只需要计算与之相关的键值缓存,因此解码阶段的计算负载相对较轻。 - **特点**:**解码阶段通常需要较少的计算资源**,但仍然需要**频繁访问键值缓存**。为了减少干扰,PDD将解码阶段与预填充阶段**分离到不同的GPU组。** ## 二、为什么LLM推理分成两个阶段:Prefill 和 Decode? 要想回答这个**"为什么"**,我们需要首先搞懂 **prefill 阶段的内部机制,attention 的计算细节、KV Cache 是如何初始化的、为什么 prefill 计算量这么大。** **在传统集成式推理流水线中**,LLM的Prefill和Decode阶段往往被置于同一GPU上运行,导致资源需求不匹配,资源利用率不高。例如,当用户请求的Prefill长度和Decode长度非常不匹配时,同一GPU需要同时处理高算力需求和高内存带宽需求的任务,难以发挥最佳性能。 **一句话简单理解**:LLM生成文本的过程本质上是**给定上下文,逐词预测下一个词**。但在实现上,这个过程被明确地**分成两个阶段:** | 阶段 | 资源需求特性 | 计算模式 | 显存占用模式 | 目的 | | --- | --- | --- | --- | --- | | Prefill | 计算密集型 | 高并行度,矩阵乘法为主 | 低,固定规模 | 模型读取并"理解"你输入的所有上下文 | | Decode | 内存密集型 | 顺序生成,访存为主 | 随上下文增长指数级上升 | 模型基于已有信息逐步生成回复 | Prefill 是用户输入完 prompt 到生成首个 token 的过程,Decode 则为生成首个 token 到推理停止的过程。 那么,这样我们就很好理解, **为什么不能一个阶段,而必须拆分成两个阶段进行:** - 输入 prompt 是完整的、一次性提供的,**适合并行计算。** - 输出 token 是未知的,只能**一个一个推理,必须串行。** **在Prefill阶段**,大模型一次性对prompt中所有token进行计算QKV,由于不同token的计算是独立的,因此该过程可以并行。**在Attention部分**,计算得到的QKV进一步计算出Output矩阵,再经过后续的FFN层和解码**得到首字母token。** **在Decode阶段**,计算原理和 Prefill 完全相同,但计算方式却不能一样。**原因有两个:** **第一:随着序列长度的增加**,Attention 计算复杂度平方级增长,直接计算代价很大,导致长序列的推理时间极慢,甚至不可行。 **第二:对Decode阶段**的计算过程简单分析发现,该过程可以复用 Prefill 阶段的KV结果,也可以复用Decode阶段已经产生的KV结果。 **综上,可以把已产生的KV存起来**,不必重新计算,这就是KV Cache。对于Q矩阵,每次需要计算的只是Q的最后一行q,计算关于**qKV的attention**,而不是关于**QKV的attention**,这样**复杂度降低了一个量级,实现以存换算。** ## 三、Prefill 内部运行机制 > **Prefill 阶段是语言模型推理中的第一个步骤**,它负责处理你输入的所有上下文内容(prompt),为后续生成打下基础。 比如你问模型一句话: "请解释一下 Transformer 的原理。" 这句话会被 tokenizer 编码为一串 token,比如 `["请", "解释", "一下", "Trans", "##former", "的", "原理", "。"]`。 然后这些 token 会进入 Transformer 模型进行前向传播。想要更详细了解Transformer的运行原理,可以参考这篇文章《新手必看 | 44张图带您极简学习Transformer | 分步数学示例(建议收藏)》 **重点来了** **Prefill 中模型内部到底发生了什么?** **Step 1:Embedding 输入** - 每个 token 会映射成一个向量(embedding),形状为 `[batch_size, seq_len, hidden_dim]` **Step 2:Self-Attention 的全量计算** - 输入是完整的上下文,因此模型会执行一次完整的 masked self-attention。对于位置 i 的 token,会计算它和前面所有位置的注意力(包括自己): **Step 3:生成 KV Cache** - 每层 Transformer 都会把每个 token 的 K 和 V 存下来,形成 KV Cache: ``` KV Cache = [K₁, K₂, ..., Kₙ], [V₁, V₂, ..., Vₙ] ``` 这个 Cache 会在 decode 阶段被反复使用,避免重复计算。 ## 四、为什么 prefill 的计算成本那么高? 让我们做个简单对比: | | Prefill | Decode(单步) | | --- | --- | --- | | 处理 token 数 | 全部 prompt(如几百) | 1 个 | | Attention 计算 | 全 attention matrix | 只看已有 KV | | 是否可并行 | ✅ 是 | ❌ 否(必须串行) | | 计算资源 | 重 | 轻 | > Prefill 最大的特点是: - 需要 **"每个 token 与前面所有 token 做 attention"** - 不能复用 KV Cache(因为是第一次建立) **Prefill 是典型的 compute-bound 阶段**: - 大量矩阵乘法和 attention 计算主导性能瓶颈 - GPU 的算力利用率很高,但内存带宽压力较小 因此如果你的 prompt 很长,Prefill 阶段就会非常耗时。很多模型响应慢,不是生成慢,而是 prompt 处理慢。 ## 五、Decode:token-by-token 地生成输出 在 prefill 之后,模型已经建立了一个完整的 KV Cache,可以开始逐步生成 token。 每次 decode 只需要: - 把最新生成的 token 输入进去 - 拿之前的 KV Cache 来做 attention - 预测下一个 token **Decode 是典型的 memory-bound 阶段**: - 每生成一个 token,都需要访问所有历史的 KV Cache(多层、多头) - 计算量小,但内存带宽压力大。 - 特别在 batch size 小、生成序列长的场景,GPU 利用率会很低。 ## 六、Prefill vs Decode 的性能瓶颈差异 由于Prefill、Decode这两个阶段的输入特性和计算方式**本质不同,**所以将其拆分成两个阶段是**为了精准优化每一步的计算路径**,比如: - Prefill 可用 FlashAttention 等并行技术提升性能 - Decode 可用 KV Cache、speculative decoding 等加速生成 在推理过程中,**Prefill 和 Decode 阶段不仅在结构上不同,在性能瓶颈上也大相径庭**: | 阶段 | 特点 | 性能瓶颈 | 原因 | | --- | --- | --- | --- | | Prefill | 一次处理整个输入序列 | Compute-bound | 多 token 并行计算,Attention + MLP 计算密集 | | Decode | 每次生成一个 token,逐步执行 | Bandwidth-bound | 每次要读取大量 KV Cache,但计算量小,等数据成为瓶颈 | ### 为什么 Decode 会是 Bandwidth-bound? 在 Decode 阶段,虽然只生成一个新 token,但为了计算它的注意力得分,需要加载 **全部历史 token 的** **KV** **Cache**。这意味着: - 每层都要从 GPU 内存中读取大量数据; - 实际计算(比如 Q × K^T)规模却很小; - 导致 GPU 大量时间都在等内存传输,**而不是在计算**。 这就是典型的 **Bandwidth-bound** 场景 —— **内存带宽**成为限制性能的关键因素,而不是算力本身。 | 类型 | 具体含义 | 常见表现 | | --- | --- | --- | | Compute-bound | 受限于计算单元(ALU、CUDA 核心等) | GPU 计算占满 | | Bandwidth-bound | 受限于 访问速度:内存太慢,等数据成为瓶颈 | GPU 闲着在等内存 | | Memory-bound | 受限于 内存容量,模型或缓存太大放不下 | OOM / 频繁调度数据 | ## 七、PD分离原理 通过以上内容的分析,我们就能够很容易的理解PD分离式部署的原理了。**简单来说**,将Prefill(预填充)和Decode(解码)这两个推理阶段分开处理的技术,通常适用于对时延有严格要求的场景。 **将Prefill实例和Decode实例分开部署**,减少Prefill阶段和Decode阶段分时复用在时延上造成的互相干扰,实现同等时延下,提升吞吐量。 **PD分离工作原理如下图所示。** **PD分离部署的优势:** - **资源利用优化**:由于Prefill阶段计算密集,而Decode阶段计算较为稀疏,将这**两个阶段分离可以更好的利用GPU的计算资源。** - **提高吞吐量**:分离后的Prefill和Decode可以同时处理不同的请求,这意味着在Prefill阶段处理新请求的同时,Decode阶段可以继续**处理之前请求的解码任务**,从而提高了整体的处理能力。 - **降低延迟**:由于Prefill和Decode分别在不同的阶段进行,**可以减少等待时间**,特别是当有多个请求并发到达时。 ## 八、PD分离通信协议 在大模型推理中: - **Prefill 阶段**:一次性处理输入 prompt(比如几千个 token),计算代价大、计算密集、通信密集; - **Decode 阶段**:逐 token 生成输出,计算相对轻量,但延迟敏感。 **PD 分离** 的思路是: **让 prefill 与 decode 阶段分别运行在不同的 worker 上(甚至不同节点上),形成更灵活的资源编排。** 这样可以让大模型推理 pipeline 化,提高吞吐量(Throughput)和利用率。 但 PD 分离带来的挑战是:prefill 输出的 **KV Cache(注意力缓存)** 要传递给 decode worker,这就需要高效的 **跨设备通信协议**。 ### 1、NCCL **NCCL (NVIDIA Collective Communication Library)** 是 NVIDIA 官方推出的 **GPU 间高性能通信库**,广泛用于分布式训练和推理。 它为深度学习框架(如 PyTorch、Megatron、vLLM、DeepSpeed 等)提供高效的 **collective communication primitives**:AllReduce、AllGather、ReduceScatter、Broadcast、Send/Recv。 | 特性 | 说明 | | --- | --- | | 底层协议 | 基于 NVLink / NVSwitch / PCIe / InfiniBand / RoCE | | 通信模式 | 点对点(P2P)与集合通信(collective)均支持 | | 典型用途 | 模型并行(Tensor/Sequence Parallel)、梯度同步、KV Cache 共享 | | 性能特征 | 延迟低、带宽高,尤其适合单机多卡或同集群高带宽环境 | | 限制 | 主要用于 GPU–GPU 间通信,不适合 CPU 或异构网络场景 | 在 PD 分离架构中,**如果 prefill worker 与 decode worker 处于同一 GPU 集群中(如同机或同网段 NVLink 环境)**, NCCL 是最常用的通信方式: - Prefill 阶段完成后,将 KV Cache tensor 通过 NCCL 的 `Send/Recv` 或 `AllGather` 传给 Decode worker; - Decode worker 接收并继续推理。 **优点**:传输快、延迟低。 **缺点**:只能在 GPU 直连或高速互联环境下使用(如 NVLink、IB/RoCE)。 ### 2、NIXL > **NIXL (NVIDIA Interconnect eXtension Layer)** 是 NVIDIA 新一代跨节点通信层,用于支持 **异构节点间的高效推理通信**,尤其是 **PD 分离架构下的远程 Prefill–Decode 数据传递**。 它是一个抽象通信层,位于 NCCL 和更高层推理框架(如 **Dynamo Inference Framework**, **TensorRT-LLM**, **vLLM**) 之间。 > 可以理解为:**NIXL = 面向推理系统的"远程 NCCL"** | 特性 | 说明 | | --- | --- | | 定位 | NCCL 的扩展层,支持跨节点 / 跨网络传输 | | 通信语义 | 统一封装 Send/Recv、RDMA、ZeroCopy 等接口 | | 支持硬件 | 支持 NVLink、NVSwitch、InfiniBand、Ethernet | | 优化目标 | 降低跨节点 Prefill→Decode KV 传输延迟 | | 使用场景 | PD 分离架构、异构 GPU 集群、解耦式推理管线 | - **NCCL**:适合 **单机或高带宽集群内** 的 GPU–GPU 通信; - **NIXL**:是 **NCCL 的远程扩展层**,用于 **跨节点 / 异构环境** 的高性能通信,特别针对 **Prefill–Decode 分离架构** 的 KV Cache 远程传输场景。 ## 九、追溯PD分离技术 ### (一)论文《SARATHI: Efficient LLM Inference by Piggybacking Decodes with Chunked Prefills[1]》 时间:2023.8 提出了SARATHI技术来解决**LLM推理效率低下**的问题。 **随着语言模型的规模不断扩大**,推理所需的GPU计算资源显著增加,尤其是在小批量情况下,解码阶段的计算利用率较低,导致整体推理效率低下。 **通过改进预填充(prefill)和解码(decode)阶段的调度策略来提高LLM推理的效率。**具体来说,SARATHI通过使用**分块预填充和最大解码批处理**来解决这些问题。 - **分块预填充(Chunked-prefills)**: - 将一个预填充请求分割成多个等大小的块,以最大化GPU的计算利用率。 - 通过分割预填充请求,可以在单个预填充请求中构建多个解码最大批次,从而提高解码的覆盖范围。 - **最大解码批处理(Decode-maximal batching)**: - 使用单个预填充块构建一个批次,并用解码请求填充剩余的槽位。 - 这种混合批处理提供了既计算饱和又均匀的工作单元,解决了低效解码和管道气泡的问题。 ### (二)论文《DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving[2]》 时间:2024.1月 https://github.com/LLMServe/DistServe 提出DistServe,一种通过解耦预填充和解码计算来优化LLM服务性能的系统。 **现有系统将预填充和解码阶段合并处理**,导致强烈的预填充-解码干扰和资源分配与并行计划的耦合;不同应用对每个阶段的延迟要求不同,如实时聊天机器人强调低首次token时间(TTFT),而文档摘要则强调低每个输出token的耗时(TPOT)。 **相关工作**:该问题的研究相关工作有:**vLLM和DeepSpeed-MII**等系统采用了**批处理和模型并行**策略来提高整体系统吞吐量,但这些方法未能有效解决预填充和解码阶段的干扰问题。 **DistServe**将预填充和解码阶段的**计算分配到不同的GPU上**,从而**消除预填充-解码干扰**。预填充阶段处理用户提示以生成响应的第一个token,而解码阶段则逐步生成后续token。 ### (三)论文《LoongServe: Efficiently Serving Long-Context Large Language Models with Elastic Sequence Parallelism[3]》 时间:2024.4月 https://github.com/LoongServe/LoongServe 提出LoongServe系统,通过**弹性序列并行性(ESP)**来高效地服务长上下文LLMs。 **大语言模型的上下文窗口迅速增加**,导致不同请求和同一请求的不同阶段之间的资源使用差异巨大。现有的静态并行策略无法有效利用底层资源来处理可变长度的请求。 弹性序列并行性(ESP),以适应不同请求和阶段的动态变化。基于ESP,设计了LoongServe系统,旨在提高计算效率、通信效率和GPU内存效率。 ESP动态调整每个迭代的并行度(Degree of Parallelism, DoP),**以适应不同请求和阶段的资源需求**。在预填充阶段,**ESP可以设置较高的DoP以快速处理请求**;**在解码阶段,ESP可以降低DoP以减少通信开销并释放资源。** ### (四)论文《Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving[4]》 时间:2024.6月 https://github.com/kvcache-ai/Mooncake https://github.com/vllm-project/vllm/pull/10502 Mooncake,一种以KVCache为中心的分散化架构,用于大语言模型(LLM)的推理服务。 这篇文章要解决的问题是如何在LLM服务中,特别是处理长上下文和过载场景时,提高整体有效吞吐量并满足延迟相关的服务水平目标(SLOs)。 该问题的研究难点包括:如何在过载场景下预测未来的负载并提前拒绝某些请求以节省计算资源;如何有效地分离预填充和解码阶段以提高缓存利用率;如何在保证延迟要求的前提下最大化吞吐量。 该问题的研究相关工作有:Orca使用迭代级调度以实现各阶段的并发处理;vLLM利用动态KV缓存管理优化内存;FlexGen、SARATHI和FastServe结合创新的调度和交换策略以有效分配工作负载。此外,Splitwise提出了分离预填充和解码阶段的分解架构,DistServe优化了每阶段的资源分配和并行策略,TetraInfer结合了分块预填充和两级分解以及预测的两级调度算法。 ### (五)论文《Speculative Prefill: Turbocharging TTFT with Lightweight and Training-Free Token Importance Estimation[5]》 时间:2025.2.5日 SPECPREFILL的框架,旨在通过**轻量级和无需训练**的标记重要性估计来加速大语言模型(LLM)的推理时间。 这篇文章的研究背景是提高时间到第一个标记(TTFT)在现代大型语言模型(LLM)推理引擎中至关重要。优化TTFT可以直接提高最大每秒查询数(QPS),满足许多关键应用的需求。然而,提升TTFT极具挑战性,因为它是计算受限的,并且性能瓶颈从自注意力转移到了多层感知机(MLP)部分。 预填充阶段主要是计算受限的,且瓶颈可能会随着提示长度和批量大小的变化而变化;直接优化TTFT会导致自注意力部分向MLP部分转移,从而增加计算复杂度。 ### (六)论文《LServe: Efficient Long-sequence LLM Serving with Unified Sparse Attention[6]》 时间:2025.2.20日 LServe的系统,旨在通过混合稀疏注意力机制来高效地服务长序列大型语言模型(LLMs)。该系统通过统一块稀疏注意力框架来加速长序列LLM的预填充和解码阶段。 **背景:** - 长序列LLMs在处理复杂任务时表现出色,但其在预填充和解码阶段的效率问题仍然存在。预填充阶段的注意力计算复杂度为二次,而解码阶段的内存占用较大。 - 现有的加速方法主要集中在KV缓存的量化或静态稀疏注意力上,但这些方法在保持长上下文能力方面存在不足。 **LServe系统**: - LServe通过引入混合稀疏注意力机制来解决这些问题。它将不同的硬件友好的结构化稀疏模式统一到一个框架中,通过在块级别跳过不重要的计算来加速注意力计算。 - 在预填充阶段,LServe将一半的注意力头转换为几乎免费的流式头,并在解码阶段使用查询为中心的动态稀疏性来优化KV缓存。 实验表明,LServe在预填充阶段比现有的vLLM系统快2.9倍,在解码阶段平均快1.3到2.1倍,同时保持了长上下文的准确性。 ## 十、vLLM中的PD分离架构 vLLM的PD分离架构主要由三个组件构成:Proxy API server、vLLM prefill和vLLM decode。以下是它们的工作原理: 1️⃣ 当请求到来时,首先会进入Proxy API server。Proxy API server会将请求转发给vLLM prefill。 2️⃣ vLLM prefill负责进行prefill操作,生成kv cache,并将这个缓存转发给vLLM decode。 3️⃣ Proxy API server继续将请求发送给vLLM decode。vLLM decode会执行drop_select操作,这个操作主要是获取kv和跳过prefill。完成drop_select后,vLLM decode会生成First token。 4️⃣ vLLM decode阶段也会生成First token。Proxy API server最终获取的所有token都是从vLLM decode获取的。vLLM prefill只负责生成kv cache。 通过这种方式,vLLM的PD分离架构能够实现高效的请求处理和缓存管理。 ## 参考资料 > [1] SARATHI: Efficient LLM Inference by Piggybacking Decodes with Chunked Prefills: _https://arxiv.org/pdf/2308.16369v1.pdf_ > [2] DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving: _https://arxiv.org/pdf/2401.09670v3.pdf_ > [3] LoongServe: Efficiently Serving Long-Context Large Language Models with Elastic Sequence Parallelism: _https://arxiv.org/pdf/2404.09526v2.pdf_ > [4] Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving: _https://arxiv.org/pdf/2407.00079v3.pdf_ > [5] Speculative Prefill: Turbocharging TTFT with Lightweight and Training-Free Token Importance Estimation: _https://arxiv.org/pdf/2502.02789v2.pdf_ > [6] LServe: Efficient Long-sequence LLM Serving with Unified Sparse Attention: _https://arxiv.org/pdf/2502.14866v2.pdf_