从理论到实践:理解 LLM 推理与推理引擎设计

导读:LLM 推理是一个横跨算法、系统和硬件的复杂领域。本文试图以三个层次串联起一条学习路径:首先理解推理过程的基本原理与性能模型(Prerequisite),然后通过一个极简实现(nano-vLLM)看清推理引擎的核心骨架(Learning),最后眺望工业级系统(vLLM/SGLang)如何在这些基础上解决真实世界的工程挑战(Debug)。希望这篇导读能成为你进入 LLM 推理世界的索引地图。


引言:为什么我们需要这样一份导读?

如果你曾试图阅读 vLLM 的源码,或者研究过 Transformer 推理的加速技巧,很可能被大量概念淹没:KV Cache、PagedAttention、Continuous Batching、Chunked Prefill、Prefix Caching、Speculative Decoding。它们像一座迷宫,每一条路径都通向更深的优化细节。

但所有复杂系统背后,都有一条简洁的主线。我们依然可以把推理引擎拆成三个层次:

  1. 基础层:LLM 推理的基本运行机制(Prefill/Generate)和性能瓶颈的数学语言(算术强度、Roofline 模型)。这一层回答“问题是什么”。
  2. 设计层:一个推理引擎如何用模块化的方式管理请求、调度计算、组织 KV 缓存。这一层回答“核心骨架怎么搭”。
  3. 工程层:工业级系统在骨架之上添加了哪些血肉,以应对高并发、低延迟、长上下文等现实需求。这一层回答“复杂系统如何演进”。

本文正是沿着这三个层次展开的导读。我们会从你或许已经熟悉的 KV Cache 出发,一步步走到分布式推理的宏大图景,并始终指向更详细的参考资料。无论你是想搭建自己的推理服务,还是想理解现有框架的设计哲学,这篇文章都希望能成为一张不错的地图。


第一章:Prerequisite – LLM 推理的核心过程与性能模型

在深入任何推理引擎之前,我们先把 Transformer 在“生成”时的独特行为讲清楚:Prefill 与 Generate(也常被称为 Decode)在同一套硬件上呈现出完全不同的瓶颈,这会决定后续所有“引擎设计”的出发点。

这部分内容建议以 All About LLM Inference 为主线阅读,本文只保留一条能继续往下走的叙事骨架。

1.1 从朴素循环到 KV Cache

最直观的生成方式是:每生成一个新 token,就把整个输入序列(prompt + 已生成 token)重新送入模型。直觉上它很简单,但代价是重复计算历史 token 的投影与注意力中间量,长上下文下很快变得不可承受。

KV Cache 的思想是:在第 i 步,我们只需要当前 token 的 Query 与历史 token 的 Key/Value 交互;因此历史 token 的 Key/Value 投影可以被缓存起来,后续每步只读缓存并追加增量。

于是推理过程被清晰地划分为两个阶段:

  • Prefill(预填充):一次性处理整个 prompt,建立初始 KV Cache,并输出第一个 token。
  • Generate(生成):每步加载 KV Cache,用当前 token 的 Query 与缓存中的 Key 计算 Attention,采样下一个 token,并将新 token 的 Key/Value 追加到缓存。

也正是在这里,我们会看到一个决定性的差异:Prefill 更偏计算密集,天然拥抱大 batch;Generate 更偏访存与同步密集,常常受限于从 HBM 加载权重与 KV Cache 的速度。

1.2 性能瓶颈的数学语言

为了更严谨地谈“瓶颈”,我们需要引入算术强度(Arithmetic Intensity):计算量(FLOPs)与访存量(Bytes)的比值。它与 Roofline 模型一起,能帮我们判断一个算子究竟处于计算受限还是访存受限。

当我们把这套语言带到 Transformer 推理里,就会得到一个非常实用的直觉:Generate 阶段很难轻易把硬件吃满。很多线性层需要足够大的 token 并行度才会进入计算受限,但生成时的 token 并行度往往就是并发请求数;而 Attention 在生成阶段的算术强度更苛刻,常常天然处于访存受限。

这也解释了为什么推理系统的优化会不断绕回同一些问题:如何稳定提升有效 batch?如何减少无谓的访存与同步?如何让 decode 的快路径更干净?

1.3 KV Cache:性能与容量的博弈

KV Cache 的大小随序列长度线性增长。随着上下文拉长,KV Cache 很快会从“优化手段”变成“主要内存消费者”,并成为推理系统中真正的瓶颈。

缓解 KV 压力的手段大致分为两类:

  • 架构优化:例如通过减少 KV 头数量来压缩 KV Cache,或更激进地改变注意力结构。
  • 运行时优化:例如 PagedAttention 借鉴操作系统的分页思想,将 KV Cache 划分为固定大小的块,通过页表(block table)实现逻辑连续到物理离散的映射,从而减少碎片并提升并发度。

1.4 分布式推理的基本法则

当单芯片无法满足需求时,我们需要把推理扩展到多芯片。Prefill 阶段与训练更接近,可以沿用张量并行等成熟策略;但 Generate 阶段更像一条对延迟高度敏感、且访存受限的流水线,通信与同步成本会被无限放大。

一个非常实用的经验法则是:在生成阶段,尽量只移动激活值,而不要移动大块权重或大块 KV。围绕这个法则,系统会自然演化出各种模型并行与 KV 分片策略,也会自然逼近“架构拆分”(例如把 prefill 与 generate 拆到不同集群)的方向。

对这部分的公式推导、实测数据与更多案例,建议直接阅读 All About LLM Inference


第二章:Learning – 从 nano-vLLM 看推理引擎设计

理论告诉我们“问题是什么”,但引擎设计真正可迁移的部分,往往藏在“代码骨架与接口契约”里。nano-vLLM 之所以是一个好入口,是因为它足够小,小到你不会被工业级优化淹没;又足够完整,完整到你能在一个闭环里看清推理引擎到底在干什么。

建议你按这个顺序阅读:先用叙事把矛盾与骨架立住(nano-vLLM-0),再把抽象对照到实现与接口契约(nano-vLLM-1)。

2.1 引擎循环:永不停止的节拍

任何推理引擎的核心都是一个 step 循环,它把无限的时间序列切割成离散的“步”。用更抽象的语言讲,这个循环通常由三段构成:

  • schedule:在资源约束下决定本轮执行哪些请求,以及它们处于 prefill 还是 decode 阶段。
  • run:执行器将请求列表转换为张量,运行模型,返回本轮生成的 token。
  • postprocess:将 token 写回请求状态,判断是否完成,并回收资源。

这个循环定义了整个系统的接口契约:Scheduler 负责策略,Runner 负责机制,Engine 负责串联。一旦契约稳定,策略和机制就可以独立演进。

如果你想把这段抽象对照到 nano-vLLM 的具体实现,直接从 Engine 实现细节 开始读会最快。

2.2 调度器:在硬约束中做选择

调度器是系统的“政策制定者”。它面对的不是某个理想化最优,而是硬约束下的现实取舍,最常见的硬约束至少来自两类预算:

  • token 预算:每步最多处理的 token 数,主要约束 prefill。
  • KV 预算:显存中可用的物理块数,决定了能否为新请求分配/为运行请求追加。

nano-vLLM 的策略很朴素,所以它更像一面镜子:我们能在最小系统里看清“调度器必须同时管理逻辑队列与物理资源”的核心矛盾。之后你在工业级系统里看到的 continuous batching、chunked prefill,本质上都是在这对矛盾上做更细的权衡。

对应的实现拆解可以从 调度器设计 一节一路读下去。

2.3 BlockManager:虚拟内存的翻版

KV Cache 的管理是推理引擎里最像操作系统的部分。关键思想不是“用不用缓存”,而是“如何把缓存变成可会计的资源”。分页式 KV 管理把这件事做成了一个闭环:

  • 显存被划分为固定大小的 block(页)。
  • 每个请求维护自己的 block table(页表),把逻辑连续映射到物理离散。
  • 在此基础上叠加共享、引用计数、回收与抢占,就能从“显存碎片”与“并发不可控”里解套。

如果你想看这套机制如何落地为接口与数据结构,直接读 Block Manager 会最直观。

2.4 Sequence 与 ModelRunner:请求状态与数据面抽象

一个推理引擎要能跑起来,除了“调度”与“内存”,还需要两类抽象:

  • Sequence:请求从生到死的唯一载体,承载 token 列表、停止条件、缓存映射与推进状态。
  • ModelRunner:数据面的执行抽象,负责把请求列表打包成张量,驱动模型计算,再把结果吐回控制面。

把这两者的边界想清楚,你再去读多进程/多卡、IPC、CUDA Graph、分桶等优化时,会更容易分辨哪些属于“契约”,哪些属于“优化”。对应实现可以继续沿着 nano-vLLM-1 往下读。

2.5 我们从 nano-vLLM 里真正学到什么?

我们最终想拿到的不是“这个项目怎么写”,而是一套可迁移的系统直觉:

  • 我们如何切控制面与数据面,才能让调度策略与执行优化独立演进。
  • 我们如何把 KV cache 变成可分页、可分配、可回收的资源,而不是一团显存黑箱。
  • 我们如何理解 prefill/decode 的结构性矛盾,并把它翻译成调度与执行的接口契约。

当我们带着这些直觉去读工业级系统时,很多“看似新颖”的模块,会突然变得顺理成章。


第三章:Debug – 工业级系统的演进与工程权衡

有了理论基础与最小实现,我们终于可以站到工业级系统(vLLM、SGLang)的面前,审视它们如何在 nano 的骨架上长出血肉。这些演进并非无中生有,而是为了解决真实世界中的工程挑战。

为了给后续实践留空间,这一章先写“演进方向与问题清单”,把真正的 debug 经验留给你之后的 vLLM/SGLang 实践笔记来填。

3.1 调度策略的精细化

nano-vLLM 的二值调度(要么全 prefill,要么全 decode)在低并发时可行,但在高并发下会引发两个典型问题:

  • prefill 阻塞 decode:长 prompt 的 prefill 会长时间占据 GPU,导致正在运行的 decode 请求尾延迟抖动。
  • 请求长短不一:短序列完成后留下的 batch slot 难以及时填满,造成算力浪费。

工业界常用 continuous batching 与 chunked prefill 来平衡这些矛盾:让 decode 的流水线尽量连续滚动,同时避免长 prefill 独占硬件。这也会反向要求执行器能处理更混合、更动态的输入形态,从而推高系统复杂度。

3.2 缓存管理的规模化

nano-vLLM 的分页 + 基础共享足以建立直觉,但在成千上万的并发与长上下文场景下,我们往往需要更强的结构与语义:

  • 更高效的前缀索引结构(例如树结构)以提升命中与管理效率。
  • copy-on-write 等更严格的一致性语义,以支撑共享与分叉并存。
  • 分层存储与 swap/offload,以把 HBM 的紧张变成可调度的系统资源。

3.3 执行优化的多样化

nano-vLLM 可以用极简的方式展示“快路径”的存在,但工业级系统要面对连续批处理带来的动态形状、不同算子与不同精度组合、以及更复杂的通信与同步图。

因此我们会看到分桶(bucketing)、算子融合(例如 FlashAttention)、量化推理(int8/fp8)等更系统化的执行优化手段被叠加进来。

3.4 架构扩展的体系化

当单机多卡仍不足以支撑大规模服务时,系统会自然走向“更强的并行”与“更清晰的服务拆分”。其中一个重要方向是把 prefill 与 generate 分离部署,让两类工作负载在不同资源形态上各取所长,并把 KV 的传输、命中与亲和性路由变成系统级问题。

3.5 前沿:Speculative Decoding

如果说前面的优化大多是在“压榨硬件”,那么 speculative decoding 则更像是“用计算换延迟”:引入草稿模型一次生成多个候选 token,再由目标模型并行验证。它对调度器、执行器、以及状态推进语义都会提出更高要求,也往往是工业级系统进入前沿优化区的一个分水岭。

3.6 vLLM / SGLang 实践坑位(留空)

这一节先只建目录,不写结论,等待补上“真实踩坑经验 + 指标复盘 + 代码定位方式”。

vLLM 实践(TODO)

  • (留空)核心链路与调试地图
  • (留空)调度策略的实际表现与指标(TTFT/TPOT/尾延迟)
  • (留空)KV/显存压力下的行为:抢占、碎片、长上下文
  • (留空)工程优化:算子、graph、通信、量化等

SGLang 实践(TODO)

  • (留空)编程模型与调度抽象
  • (留空)与 vLLM 的差异点:哪些是“哲学差异”,哪些是“场景差异”

结语:地图在手,路在脚下

我们从推理的基础性能模型出发,理解了 KV Cache 如何把生成复杂度“降维”;接着在 nano-vLLM 的极简实现中,看见了分页、调度、执行这些核心模块如何协作;最后眺望工业级系统,理解了它们如何在骨架之上解决真实世界的复杂性。

这张地图的价值在于,它揭示了所有推理引擎共同的“道”:管理 prefill 与 decode 的冲突,在资源约束下做决策,将 KV cache 虚拟化,用预编译换取运行时效率。当你下次阅读 vLLM、SGLang 或 TensorRT-LLM 的源码时,不妨回想这三层结构:先问基础原理,再看核心骨架,最后理解工程权衡。你会发现,那些看似复杂的代码,不过是同一套思想的自然延伸。

如果你希望深入理论推导与性能模型,回到 All About LLM Inference 会更系统;如果你希望深入 nano-vLLM 的模块与接口契约,沿着 nano-vLLM-0nano-vLLM-1 逐篇读下去会更顺。

工业级系统的奥秘,则需要我们在 vLLM、SGLang 的源码、论文与实践指标里亲自探索。


延伸阅读