PD 分离:大模型推理的第一步优化
是什么:PD 分离的定义
大模型推理分为两个阶段:
输入 token: ["今天", "天气", "怎么样"]
═══════ Prefill(预填充)═══════
一次性把 ["今天", "天气", "怎么样"] 送进模型
→ 输出每个 token 的 hidden state + 第一个生成 token
─────── Decode(逐token解码)───────
用上一步的输出 token 逐个生成后续 token
"今天天气怎么样" → "还" → "不" → "错" → ...
直到生成结束符 <eos>
PD 分离:把 Prefill 和 Decode 部署在不同实例上,各自优化。
为什么需要 PD 分离?
先看两个阶段的资源需求差异:
| Prefill | Decode | |
|---|---|---|
| 计算模式 | 批处理,并行处理所有输入 token | 串行,一次只处理 1 个 token |
| 瓶颈 | 计算密集型(compute-bound) | 内存带宽型(memory-bound) |
| 计算量/token | 高(Self-Attention O(n²)) | 低(每次只算一个新 token 的 Attention) |
| GPU 利用率 | 可达 80-90% | 通常 10-30% |
| 延迟特征 | 一次性较大延迟 | 每 token 固定小延迟 |
本质问题:Prefill 和 Decode 用同一张卡跑,资源需求完全相反——Prefill 要算力,Decode 要带宽,卡在中间谁也发挥不好。
广告系统类比
这就像把广告检索和精排打分跑在同一台机器上:
检索(召回+粗排):大量候选,计算密集,可以并行
vs
精排打分:少量候选,需要复杂模型,延迟敏感
你不会把召回和精排混在一起——召回用高性能批量引擎,精排用低延迟排序引擎。PD 分离完全一样的逻辑。
去掉 PD 分离的代价
混合部署(Prefill 和 Decode 同一实例)的典型灾难场景:
时刻 1: Prefill 任务进来,GPU 算力拉到 90%
时刻 2: Prefill 任务完成,进入 Decode → GPU 利用率骤降到 15%
时刻 3: 新用户请求进来,需要 Prefill → 但实例在跑 Decode,要等
冲突结果:Prefill 被 Decode 阻塞(延迟飙升),Decode 被 Prefill 抢占(抖动)
这就像你的广告检索系统里,一个耗时的复杂 query 把整个倒排引擎卡住了,后面 100 个简单 query 排队等着。你会怎么做?当然是拆成独立通道。
PD 分离后:
- Prefill 实例:只管吃输入、吐 KV Cache,GPU 利用率持续 80%+
- Decode 实例:只管逐 token 输出,内存带宽利用率持续拉满
- 两者互不干扰,各司其职
覆盖多少场景?
PD 分离不是银弹,适用场景取决于请求特征:
| 场景 | Prefill 占比 | Decode 占比 | PD 分离收益 |
|---|---|---|---|
| 对话机器人 | 低(prompt 短) | 高(回复长) | 中等,Decode 优化收益大 |
| 长文档摘要 | 高(几万字输入) | 低(摘要几百字) | 大,Prefill 独立扩展 |
| 代码生成 | 中等 | 高 | 大,两个阶段特征差异明显 |
| 多轮对话 | 高(累积历史) | 高 | 最大,两个阶段都重 |
判断标准:当 Prefill 延迟 > Decode 每 token 延迟的 5 倍以上,或者 GPU 利用率长期 < 50%,就需要 PD 分离。
工程实践:几 P 几 D?
“几 P 几 D” 就是 Prefill 和 Decode 实例的配比。以 vLLM/SGLang 为例:
场景一:短 prompt,长输出(对话)
用户输入: "你好" (2 tokens)
模型输出: "你好!今天想聊什么..." (200 tokens)
Prefill 轻 / Decode 重
配比: 1P : 3D 或 1P : 4D
场景二:长文档处理
用户输入: 上传一篇论文 (20000 tokens)
模型输出: 摘要 (500 tokens)
Prefill 重 / Decode 轻
配比: 3P : 1D 或 4P : 1D
场景三:混合流量
系统中两种类型都有
配比: 2P : 2D (平均)
动态调整: 根据实时负载,自动增减 P 或 D 实例
广告系统类比
这和广告集群资源分配一模一样:
广告系统问题:
召回集群:召回量大 → 多给机器
精排集群:延迟敏感 → 用高性能机器
流量峰谷:晚高峰召回激增 → 动态扩召回集群
PD 分离的对应:
Prefill 重(长文档)→ 多给 P 实例
Decode 重(对话)→ 多给 D 实例
动态调整 → 自动扩缩容
不变的本质
PD 分离背后的三条元原理:
1. 异质计算要分开优化
不同计算特征的阶段,用不同的硬件/配置。这和广告漏斗一样——召回层用倒排索引(IO 密集),精排层用 GPU 跑模型(计算密集)。
2. 队列分离避免 Head-of-Line Blocking
一个慢任务堵住整个队列。PD 分离本质上是拆队列——快队列和慢队列分开,互不影响。
3. 资源利用率 = 系统吞吐的天花板
混合部署的 GPU 利用率可能只有 30%,PD 分离后可以做到 70%+。这和你的索引压缩项目节省 1750 台机器一样——利用率提升就是成本下降。
元结构映射
广告检索系统 LLM 推理
──────── ──────
倒排检索 (IO 密集) → Prefill (计算密集)
精排打分 (计算密集) → Decode (IO 密集)
触发匹配 → 召回集群 → Prefill 实例
粗排+精排 → 排序集群 → Decode 实例
动态截断策略 → KV Cache 管理
L1/L2/L3 数据分层 → 显存层次 (HBM/SRAM)
请求批处理 → 合并打分 → Continuous Batching
漏斗逐层过滤 → PD 两阶段流水线
关联我的经验
我在广告系统做了十年的漏斗优化,PD 分离让我感到非常熟悉:
-
召回和精排的物理隔离:2018 年我们把召回和精排拆成独立集群,延迟直接降了 50%。PD 分离是同一个思路在推理领域的应用。
-
动态资源分配:广告系统的机器配比根据时间动态调整(晚高峰多给召回、凌晨多给线下训练)。PD 分离的 “几 P 几 D” 完全一样——根据流量特征动态调整配比。
-
性能模型 = 预估 + 实测:广告系统优化第一步是建立延迟模型(这个模块吃多少 ms),推理优化也一样——先用 roofline model 理论分析瓶颈,再实测验证。
-
客户沟通语言:向芯片客户解释 PD 分离的价值——“让你的卡在 Prefill 阶段算力利用率从 30% 提升到 80%,等效于用更少的卡跑更多的 token”。这和告诉广告主“智能出价让你的 ROI 从 2 提升到 3”是同一种思维。
一句话总结本质
PD 分离就是把广告检索的召回/排序分离搬到了大模型推理:不同阶段不同瓶颈,物理隔离各司其职,动态配比随需而变。