> For the complete documentation index, see [llms.txt](https://yeasy.gitbook.io/llm_internals/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yeasy.gitbook.io/llm_internals/di-san-bu-fen-tui-li-yu-bu-shu-pian/11_serving/summary.md).

# 本章小结

在[技术全景图](/llm_internals/di-yi-bu-fen-ji-chu-pian/01_introduction/1.0_technology_map.md)中，本章连接模型执行与在线服务。底层还需区分两组边界：GPU、服务器、集群和数据中心是资源及设施的不同组织尺度；CUDA、Triton 和 NCCL 分别承担 GPU 平台、内核编写编译及通信职责。[11.14 节](/llm_internals/di-san-bu-fen-tui-li-yu-bu-shu-pian/11_serving/11.14_gpu_software.md)的融合算例说明，减少中间读写与减少提交开销是不同优化，最终都要回到端到端收益。

**推理引擎**是把第十章的单项优化组织成一次次前向的运行时。`model.generate()` 缺四样东西：迭代级的批处理、KV 缓存的生命周期管理、调度策略、服务层治理。第一样值多少可以直接算：Llama 3 8B 在 H100 上每步要读 `16.06 + 0.131 × B` GB，`B = 32` 时下界 6.05 ms、吞吐上界约 5,293 词元/秒，`B = 128` 时每步 9.80 ms。批越大每步越慢，总吞吐仍在涨，本章的每个部件都在这条曲线上做文章。

**连续批处理**把调度粒度从一批请求降到一步。已结束的请求立即移出，等待队列里的请求在词元预算和空闲块之内立即放行。8 个请求的例子里，静态批处理要 14 步、有效位置占 64%，连续批处理只要 12 步、占 75%；折算到 11.2.1 的 4 请求例子，同样步数下多产出约 3.5 倍的词元。前提是队列不空、显存够用，两者都不成立时仍要抢占。

**调度循环**只认一个量：这一步给多少词元。请求在 `WAITING`、`RUNNING`、`PREEMPTED`、`FINISHED` 之间转移，Prefill 与 Decode 不再是两种任务，只是分到几个词元的差别。词元预算两头受限：低于约 340 个词元（Llama 3 8B 在 H100 上读权重 4.79 ms 与每词元 14.1 µs 的交点）时，一步的时间白白花在读权重上；预算太大则同批的 Decode 陪着长块变慢，**分块 Prefill** 正是在这两端之间取值。显存用尽时调度器**抢占**：整条序列释放，`num_computed_tokens` 归零回到队首，用户看到的是这条流停住而不是变慢。

**KV 显存管理**把池子切成等长的**物理块**，用**块表**把逻辑位置映射到物理槽位。一张 80 GB 的 H100 上，Llama 3 8B 扣掉 16.06 GB 权重和 2 GB 开销，KV 池 53.94 GB，合 411,525 个词元。按最大长度 8,192 预分配只能放 50 个请求，块大小 16、按需分配能放 408 个，是 8.2 倍，浪费降到 `7.5 ÷ 1,000 = 0.75%`。块表还带来**写时复制**：并行采样与束搜索共用 Prompt 的满块，只复制末尾那个不满的块。抢占后的恢复有两条路，`T = 2,000` 的 Llama 3 8B 换出加换入在 PCIe 5.0 下 8.2 ms，重算按 0.5 的利用率是 58.5 ms，序列越长重算越不划算。

**前缀复用**把“相同的前缀只算一次”做成跨请求的索引，两条路线是按块链式哈希与**前缀树**（RadixAttention）。2,210 个词元的 Prompt 命中 2,000 个时，Prefill 计算量降到 9.8%，按 40% 的利用率折合 81 ms 降到 8 ms；显存一侧，100 个并发从 27.0 GiB 降到 2.8 GiB。收益有天花板：后缀读前缀的那一项省不掉，前缀超过约 26,624 个词元后它就超过后缀自己过一遍权重的开销；命中后计算强度跌到约 200，低于 295 的拐点，时间不再按比例缩短。SGLang 论文给出的线上命中率是 52.4% 与 74.1%，远低于算例的理想值。

**多 LoRA 服务**让一个基座带上几十个变体。`r = 16` 覆盖七个投影时，Llama 3 8B 的一个适配器是 83.9 MB，只有基座的 0.52%；合并进权重则每个变体各占一份 16.06 GB，80 GB 的卡放四份就没了 KV 空间，而且不同 `W'` 的请求无法合批。不合并的做法是**分段内核**（SGMV 一类）：大矩阵乘照常走基座一遍，增量一路按适配器分段，各段只算自己的 `xAB`；代价是秩与目标模块不齐时要填充到槽位的最大秩。

**约束解码**加在 logits 上：词表 128,256 行压成 4,008 个 int32、约 16 KB 的位图，每请求每步一行。朴素实现每张掩码 3.21 ms，`B = 32` 时 103 ms，是 4.8 ms 前向的 20 多倍；有索引与缓存后降到每张几十微秒，再与前向重叠，GPU 一侧几乎不受影响。掩码必须先于 Top-p 截断施加，否则核内可能一个合法词元都不剩。

**多卡推理**有两个理由：Llama 3 70B 的 BF16 权重 141.1 GB 装不进 80 GB，读一遍也要 42.1 ms。**张量并行**在层内先列切后行切，每层两次 all-reduce；Prefill 的消息 128 MiB 看带宽，Decode 的消息只有 1 MiB，耗时几乎全是通信步数的固定开销，`t = 8` 时环形算法一个 Decode 步有 2,240 个串行通信步，换成步数恒定的算法降到 320 步。**流水线并行**通信最少却不降单词元时延；**专家并行**只用于 MoE，每层两次 All-to-All。**分离式架构**（Disaggregated Prefill-Decode）再把两个阶段分到两组实例：32 条 4K 序列的纯 Decode 一步 13.7 ms，掺进一个 2,048 词元的 Prefill 块就成了 184 ms。分开之后两侧各选并行度、各选卡，代价是 KV 要过网络，配比随流量形态变化（算例里从 6 : 2 翻成 1 : 2），固定配比迟早失衡。

**两个引擎的源码**把上面的机制一一对上。vLLM 分三类进程，调度器不分阶段、只问“还差几个词元”，块池用一条空闲队列兼做分配器与 LRU，满块按内容哈希共用；SGLang 把同一件事组织成三张表加重叠调度，前缀树是它的核心。两节都提醒同一点：论文的加速比带着条件，SGLang 论文的“吞吐最高 6.4 倍”出自多调用、高共享的程序，多轮对话输出较长时几乎没有加速。**硬件选型**按三个问题落到规格表上：单流速度看显存带宽，并发数看显存容量，成本看吞吐除以价格。H100 与 H200 的稠密算力同为约 990 TFLOPS，差别全在显存的 80 GB、3.35 TB/s 与 141 GB、4.8 TB/s；这笔溢价对 Prefill 几乎不兑现，对 Decode 直接兑现。

**生产部署**以 **Goodput** 为准：SLO 达标率不低于目标值时每张卡能服务的最大到达率，而不是原始吞吐。SLO 的数值随应用而定，常见的示例是 TTFT 几百毫秒到 1 秒、TPOT 50 ms，后者对应每流每秒 20 个词元；输出交给程序消费时可以放宽，换更大的批和更低的成本。其余工程面包括词元感知的网关路由、流式输出、按病症选指标的可观测性、单词元成本的核算，以及长上下文带来的额外一笔：Llama 3 70B 每词元 320 KiB，100 万词元的 KV 约 328 GB，单个请求就超过任何单卡。

至此，第三部分“推理与部署篇”结束。本章的每个部件和每个指标都架在“模型逐词元地把回答生成出来”这个前提上；而文本分类、关系抽取、语义相似度这类任务根本不需要生成，只需要一份好的文本表示。

***

> 📝 **发现错误或有改进建议？** 欢迎提交 [Issue](https://github.com/yeasy/llm_internals/issues) 或 [PR](https://github.com/yeasy/llm_internals/pulls)。
