LLM System: PD 分离 00 - 学习地图

这篇文章是 LLM System 系列里 PD 分离子专题的第 0 篇,也是这个主题的学习入口。是笔者让gpt-5.5通过联网搜索帮自己制定的系统性学习方案。笔者会根据这个方案来确定如何学习PD分离的整套机制。目标不是先把所有论文细节读完,而是先建立一张可以持续填充的地图:该读什么、该推导什么、该写什么代码、最后应该能回答什么问题。 这个系列暂时围绕一个问题展开:为什么现代 LLM serving 系统越来越关心 prefill/decode disaggregation,也就是 PD 分离? 我希望自己最后能回答四个问题: 1. 为什么 prefill 和 decode 要分离? 2. 一个 workload 到底该配多少 P worker、多少 D worker? 3. KV cache 从 P 到 D 传输到底传了什么、代价多大? 4. vLLM / SGLang / Mooncake 里这件事具体怎么落地? 先说一个结论:**PD 分离不是一个“拆进程就能变快”的魔法优化。**它真正解决的是服务系统里的资源解耦问题:prefill compute、decode iteration、KV cache 生命周期、网络传输和调度策略,本来在 colocated serving 里被绑在一起;PD 分离试图把它们拆开,让不同阶段按照不同目标优化。 0. 心智模型 LLM 推理一个请求大致分成两段。 Prefill:一次性吃掉 prompt,生成整段 prompt 的 KV cache,并产出第一个 token。长输入时它更像大 GEMM,通常更容易把 GPU 算力吃满。它最直接影响的是 TTFT,也就是 time to first token。 ...

May 5, 2026 · 10 min

LLM System: KV Cache 查询 01 - PagedAttention 原理

TODO: 这里写 PagedAttention 的核心抽象:block/page、block table、逻辑 token 到物理 KV block 的映射。 基础:tensor 级拆请求的形状(大量细节) 定义符号:$B$ 是 batch size,$T$ 是 seq_len,$D$ 是 token_dim,$d_q$ 是把 embedding token 投影到 $Q$ 后的维度。 推理框架拿到的请求是:\(R \in \mathbb{R}^{B \times T}\)。 $R_{b,t}$ 是一个最最基本的 token id 标量。 raw 请求经过 embedding lookup,做的操作是把这个 token 标量映射成一个高维向量。假设原先 token 是 1234 这个标量,现在就把 token 映射成 [0.1, 0.2, 0.3, 0.4] 这样的向量。 所以 $R$ 经过 embedding lookup 之后,得到:\(X \in \mathbb{R}^{B \times T \times D}\)。 因为我们目前只考虑推理场景,所以把 $W_Q$、$W_K$、$W_V$ 之类的矩阵当成固定的模型参数。 然后很多博客会直接写:\(Q = XW_Q\)。 ...

May 10, 2026 · 5 min

为什么 vLLM 和 SGLang 在生成式搜推场景如此废柴?

workload的区别 推理的类型是非常多的,RL rollout,在线服务,推荐……这些workload都不一样,虽然说推理框架这一层原则上是一个runtime的workload调度层,但是随着不断的发展,每个推理框架也并不能做到对任意的workload都有一套好的runtime策略,最终这几个框架的优化还是固化到了某几个场景,比如高贵的RL后训练,比如最主流的Serving,然后一些类似于广告推荐的边缘场景就被一脚踢死了(笑。 这他吗就很尴尬呀,现状就是典型场景已经穷尽了可能性,没东西做了,非典型的场景又没好的实现,导致必须从头开始吃屎,不过这里不吐槽这种极度的不均衡,只谈谈为什么知名的v和s两家推理框架换个场景就不行了,本质上是在讨论workload。 v和s两家框架面向的是在线序列的批处理,也就是一下QPS来了很多,然后以一个很高效的调度方式让这些任务都能被调度起来。框架层只是下发,实际的工作都在算子队列里面。而GR显然不一样,作为推荐输入的embedding是共享的,推理出来的东西是一个多级索引,这个多级索引被硬编码为token,输出token只能从这里挑选,一般叫Sematic ID(所以也得小小扩充一下词表)。然后一般的GR还会做beam search,类似于给非top的输出一次参与后续自回归生成机会,以增加结果的diversity。这个操作对于传统llm来说是很少见的。 做beam的时候虽然kvcache解决了重计算的问题,prefix sharing或copyonwrite解决了重复存储的问题,但是beam阶段load同一kv的操作依然是问题。算子上这是很多次重复没必要的G2S。如果要改这个算子的话,会更麻烦。 beam导致的kv重排 beam因为在自回归这一层做了分叉,原先设计的那种纯顺序化的kvcache就很容易出问题了,beam会主动更新自己候选的beam,也就是说他的batch来自于beam主动的而不是外界来的很多共同前缀的请求。beam能主动产生batch也能修改他们的顺序关系(熵之源说是),一旦修改了,就和顺序化的自回归假设不一样了,就得重新换block/radix treenode顺序。beam的候选+淘汰对传统自回归的范式设计影响太大了,必须得侵入式修改算子+框架。 其他调度 gr还会有很多奇奇怪怪的前处理后处理,这些都没被v和s优化过,所以自然性能也不行。

July 16, 2026 · 1 min