超越预填充税:在独立的GPU池上运行预填充和解码意味着什么,谁在生产环境中这样做,以及何时值得这种复杂性。
想象一个周六晚上8点的餐厅厨房。一位厨师正在为十二道菜的品尝菜单切菜,已经切了二十分钟,而三十桌在一个小时前下单的顾客,每次厨师转身回到砧板时,都看着他们吃到一半的盘子变凉。没有真正的厨房会这样运作:备菜厨师在后厨负责切菜,流水线厨师在前台负责摆盘。两种不同的工作,两个不同的岗位。
然而,这正是今天大多数团队服务大型语言模型的方式。一个GPU同时承担繁重的准备工作(读取和处理你的提示)和精细的摆盘工作(逐字生成响应)。每一个大型准备工作都会让其他人的响应延迟。
这种情况正在改变。一些生产环境中最先进的推理系统,包括Moonshot AI、DeepSeek以及NVIDIA最新的服务堆栈内部,都悄然做出了一个极具战略意义的决定:将这两项工作拆分到物理上独立的硬件上。本文解释了原因、工作原理,以及何时你不必费心。
预填充/解码分离是一种服务架构,它在独立的GPU池上运行LLM推理的两个阶段。预填充(处理输入提示)在一组GPU上运行,解码(逐词元生成响应)在另一组上运行。当预填充完成后,模型对提示的记忆(KV缓存)通过网络发送到解码GPU,然后由后者生成响应。

这种分离之所以存在,是因为两个阶段面临不同的硬件瓶颈:预填充受限于计算能力,解码受限于内存带宽。将它们分离可以防止长提示干扰其他人的词元生成。代价是额外的硬件、网络传输和运维复杂性。目前使用它的生产系统包括Moonshot AI的Mooncake、DeepSeek的推理集群和NVIDIA的Dynamo框架。
我们之前写过关于预填充税的文章,但如果你刚接触,这里是简短版本。每个LLM请求有两个阶段:模型首先读取并处理你的完整提示(预填充),然后开始逐个词元生成答案(解码)。第一阶段就是那笔税。这是你在得到第一个字之前支付的延迟,并且随着提示中的每个词元而增加。
更深层的问题是——预填充税只是暗示了这一点——这两个阶段对硬件的要求截然不同。
预填充发生在模型读取你的提示时。它一次并行处理所有词元,以一次大规模的矩阵计算爆发进行。GPU很喜欢这样;这正是它们被设计来做的。计算核心高强度运行,内存系统几乎无压力,任务相对于其规模完成得很快。

解码发生在模型写出答案时。它每次生成一个词元,对于每个新词元,GPU必须重新读取大量存储数据:模型的权重,以及它目前记住的关于对话的所有内容(KV缓存)。每个词元的计算量很小。大部分时间都花在数据进出内存上,而GPU的计算核心大部分时间处于空闲状态。

| 预填充(读取提示) | 解码(写出答案) | |
|---|---|---|
| 工作原理 | 所有提示词元一次并行处理 | 每次一个词元,每个词元依赖于上一个 |
| 限制因素 | 计算能力(原始处理能力) | 内存带宽(数据移动速度) |
| GPU行为 | 计算核心饱和,内存轻度使用 | 内存总线饱和,计算核心大部分空闲 |
| 工作负载形态 | 每个请求一次短暂而密集的爆发 | 每个请求一次持续而稳定的滴流 |
| 用户感受 | 首个词元时间 | 词元流式输出的流畅度 |
因此,这两个阶段需要截然不同的资源——一个缺乏计算,另一个缺乏内存带宽——而我们一直要求单个GPU同时提供两者。
下面是它在现实生活中的运作方式。现代服务引擎将许多用户的请求批处理到同一个GPU池上,以保持高利用率。解码步骤小且快,因此GPU一遍又一遍地轮流处理每个人的下一个词元,一切感觉都很流畅。然后,一个带有长提示的请求出现了。
假设有人将一份60页的合同粘贴到你的文档分析应用中。GPU会放下一切来处理这个长提示,而其他所有用户都必须等待。他们的词元就这么停止了流式输出。服务领域称此为“队头阻塞”,这也是为什么一个在测试中感觉很快的聊天机器人在生产环境中,一旦真实流量带着短问题和大量粘贴文档的混杂组合出现,就会变得缓慢。
这不是边缘情况;这是生产流量的默认形态。可以说这是当前推理服务中悬而未决的问题,每个大规模运行LLM的团队都会遇到。人们首先尝试的软件修复方案(分块预填充、更智能的调度器、优先级队列)能缓解打击,但它们都撞上了同样的天花板:只要预填充和解码在同一个GPU上竞争,就必有一方受损。
解决方案出奇地简单:不再让它们共享资源。分离式服务(你可能也见过“P/D分离”的叫法)将推理过程拆分到两个独立的GPU池中:
请求到达后,预填充GPU全速处理提示词,然后将请求交给解码GPU,由后者逐token地流式输出响应。长提示词不再阻塞任何人的生成过程,因为负责生成的机器根本不会看到提示词。每个资源池还可以根据其实际职责进行规模调整、调度,甚至选择硬件:预填充需要更多原始算力,解码需要更多内存带宽。
不过这里有一个障碍,正是这个障碍使其成为一个工程问题,而不是一个配置开关。
当模型读完你的提示词后,它会为读到的所有内容构建一份工作记忆。这就是KV缓存。在传统架构中,这份记忆就存放在将要生成响应的同一块GPU上。而在分离式架构中,在生成第一个token之前,它必须通过网络从预填充机器物理传输到解码机器。对于大模型上的长提示词,KV缓存可能达到数十GB。移动它并非四舍五入能忽略的小误差,而是你需要管理的新瓶颈。任何把这一传输过程当作已解决的小细节的文章,都在误导你。
有必要明确分离式服务放弃了什么。当前的标准做法——在统一GPU池上使用原生vLLM——是连续批处理:每块GPU同时处理两个阶段,调度器尽可能紧密地将新提示词与进行中的生成编织在一起。它简单、成熟,对于许多工作负载来说表现优异。每块GPU都保持繁忙,没有数据跨网络传输,而且只需要运维一个系统,而不是三个(预填充池、解码池以及两者之间的传输层)。分离式服务刻意用这种简单性来换取可预测的延迟。这笔交易是否值得,完全取决于你的工作负载,我们稍后会讲到。
这并非纸上谈兵。已有多个真实系统将其投入生产,它们值得你逐个了解:一方面是整个领域的参照,另一方面它们之间的差异揭示了难点所在。
DistServe(Zhong等人,OSDI 2024)。提出这一概念的学术论文对此解释得最清楚。核心洞见在于:当预填充和解码共享一块GPU时,你无法独立优化“首个token的时间”和“每个生成token的时间”。改进其中一个会损害另一个。而将它们分开后,你可以为每个池分别调优其延迟目标。DistServe报告称,与共置服务相比,在相同延迟目标下它能服务数倍于后者的请求量。
Mooncake是Moonshot AI旗下助手Kimi背后的服务平台,也是迄今为止最具说服力的生产环境实证。Mooncake不只是拆分资源池,它把KV缓存本身视为整个设计的核心,将集群中空闲的CPU内存和SSD存储汇集为一个巨大的共享缓存,因此重复或重叠的提示词根本不需要从头开始预填充。Moonshot发表了这篇架构论文,并报告该系统正在处理大规模真实流量。这不是实验室演示。
DeepSeek在发布的技术报告中披露,DeepSeek-V3和R1的生产服务在独立的GPU集群上分别运行预填充和解码,且每个阶段采用不同的并行策略。当全球最具成本效率的推理服务之一告诉你它如何服务自家模型时,这绝对值得再读一遍。
NVIDIA Dynamo是最能说明这一趋势正走向主流的信号。Dynamo是NVIDIA的开源分布式推理框架,是Triton在LLM工作负载上的继任者,而分离式服务是它的主打特性,而非注脚。它位于vLLM、TensorRT-LLM和SGLang等引擎之上,将预填充和解码路由到专用工作池,并附带一个专用传输库(NIXL),其唯一任务就是尽可能快地在机器之间搬移KV缓存。NVIDIA报告称,在延迟约束下大型模型吞吐量可提升数倍。vLLM本身也一直在构建原生的预填充/解码分离支持,因此这一能力即将出现在默认开源技术栈中。
这些框架仍然相对较新,目前可用的实践指南不多。在生产中使用分离式推理的团队大多是大型组织,它们从头构建自己的基础设施和调度系统。这也是为什么你很难看到云服务商写出详细文章的原因——许多厂商仍在探索或逐步推出这些能力。
最难的部分是这样的:一旦你采用分离式架构,互连带宽就决定了整个方案是否可行。70B级模型上单个长上下文请求的KV缓存可达到数十GB。如果通过普通数据中心以太网传输,传输时间长到足以抵消你拆分阶段所获得的一切。但如果你使用NVLink、InfiniBand或高带宽支持RDMA的以太网,交接过程就能隐藏在解码GPU本来就要花费的时间内。这正是上面列出的每一个严肃系统都在传输层上投入巨大的原因(Mooncake以缓存为中心的设计、Dynamo的NIXL),也是为什么不考虑中间网络的“直接拆分资源池”通常会产生一个比原来更慢的系统。

许多文章让分离式推理听起来像是理所当然的下一步。但现实要微妙得多。
首先,它可能需要更多的硬件。在传统设置中,每个GPU既可以处理预填充工作,也可以处理解码工作,因此资源可以被更高效地共享。而采用分离式架构后,一些GPU专门用于预填充,另一些则只负责解码。如果你的工作负载在一天中发生变化,例如早上处理长文档,晚上处理简短的聊天请求,那么一组GPU可能会闲置,而另一组则过载。这意味着你最终可能会为不经常使用的额外容量付费。
其次,它使系统变得更加复杂。请求不再从头到尾只在一台机器上运行,而是在多台机器之间移动。这带来了更多出错的可能性,例如网络延迟、解码工作节点过载,或者机器故障导致请求中断。因此,监控、调试和运维系统变得更加困难。
最后,这种优势只有在非常大的规模下才会显现。如果你服务的是一个中小型应用,分离式架构通常不会带来显著差异。像vLLM这样的现代推理引擎已经采用了连续批处理和分块预填充等技术来提高GPU利用率,而无需将工作负载拆分到不同的GPU池中。对许多团队来说,这些优化在保持系统简单的同时提供了大部分性能提升。
我们的观点很明确:分离式推理是大规模AI服务未来的重要方向,尤其是对于运行数千个并发请求的组织而言。但这并不意味着每个团队现在都应该采用它。对于许多部署场景,一个优化良好的统一推理系统更易于运维、成本更低,并且能提供出色的性能。最好的做法是理解分离式架构在什么时候能解决实际问题,并在达到那个临界点时才引入它。
在开始之前先说明一点:本节介绍的是分离式架构如何在DigitalOcean基础设施上运行。这些不是基准测试结果,也不是DigitalOcean产品。
从概念上讲,这种映射是清晰的。DigitalOcean的GPU Droplets提供H100和H200配置。H100提供预填充所需的原始计算能力。H200在提供相似计算能力的同时,配备了更大且更快的内存——141 GB的HBM3e,带宽约为4.8 TB/s,而H100为80 GB,带宽约为3.35 TB/s——这正是解码所需的特征:更大的KV缓存空间,每个生成token读取速度更快。使用H100预填充池向H200解码池提供数据是一个可行的设计,而且坦率地说,这是解释异构池为何是分离式架构最有趣承诺之一的教科书式例证。
决定因素一如既往是池之间的网络连接。DigitalOcean的多节点GPU配置通过支持RDMA的专用高速结构连接8-GPU节点,Bare Metal GPU产品列出了高达400 Gbps的东西向带宽以及高达3.2 Tbps的GPU互连速度——这正是KV缓存传输所需的网络等级。(DigitalOcean自己的服务平台已经开始使用这种模式:Inference Tax文章描述了作为Serverless Inference堆栈一部分的、基于高速RoCE网络的分离式服务。)任何架构师都应该做一个粗略估算:取每个请求的典型KV缓存大小(它随上下文长度以及模型的大小和架构而增长——70B类模型每个token大约存储三分之一兆字节),除以节点之间现实可持续的带宽,然后将结果与你的首token时间预算进行比较。如果传输时间能够轻松容纳在你本来就为预填充支付的延迟内,那么分离式架构就有发挥的空间。如果不能,任何编排框架都救不了你。像vLLM的分离式模式或NVIDIA Dynamo这样的框架是自然的上层软件层;两者都是开源的,都可以在这类标准的NVIDIA硬件上运行。
分离式推理并不是每个AI应用都需要的东西。你的工作负载的三个属性在很大程度上决定了这一点。
分离式架构最大的优势出现在你的GPU持续繁忙时。
如果你运行的是一个只有几块GPU的小型部署,并且请求是偶尔到达的,那么传统设置——每个GPU同时处理预填充和解码——通常是更好的选择。它更简单、更便宜,也更容易管理。
然而,如果你同时服务数千用户,且GPU始终在处理请求,那么预填充和解码就会开始争夺GPU资源。在这种情况下,将它们分离到专用的GPU池中可以提高整体吞吐量并降低延迟。
并不是每个应用都需要在不到一秒的时间内得到响应。
对于批处理、文档分析或内部工具等工作负载,用户通常不会注意到某个请求比另一个请求耗时更长。小幅延迟并不是主要问题。
但对于交互式应用,如聊天机器人、AI编程助手或语音助手,用户希望响应几乎立即开始并流畅地持续输出。一个过长的提示词可能会延迟共享同一GPU的所有其他请求,从而造成不一致的用户体验。
如果可预测的延迟是优先考虑的因素,那么分离式架构就会变得更有价值。
提示词长度通常是决定因素。
如果你的应用主要处理短提示词,预填充阶段会很快,因此将其与解码分离几乎没有什么好处。
另一方面,处理长文档、执行检索增强生成(RAG)或维护较长对话历史的应用会在预填充上花费更多时间。由于提示词长度在不同请求之间可能差异巨大,这类工作负载从分离中受益最大。
如果你的工作负载介于两者之间——真实流量、中等延迟敏感度、混合提示词长度——请先尝试更简单的优化。分块预填充、更好的调度和连续批处理往往能在不重新设计服务架构的情况下带来大部分改进。当这些方法在三个信号上都没有提升空间时,分离架构才是你下一步的选择。
分离式推理并非银弹。它只是改进LLM服务的众多技术之一。
其他优化解决不同的瓶颈。例如,投机解码通过更高效地生成token来加速解码阶段,而量化减少内存使用,连续批处理提高GPU利用率。
在实践中,生产级推理系统会结合使用其中多种技术,而不是仅仅依赖一种。将分离架构视为你优化工具箱中的另一个工具——它对于大规模、延迟敏感的工作负载尤其有用,但对于许多小型部署则并非必需。
——
一个热爱技术的程序员,喜欢分享前沿AI知识和开发经验。