大模型推理与 AI Infra · 0xWay1 Blog
夜晚游乐场里抱着吉他的少女

大模型推理与 AI Infra

“大模型真正跑起来以后,瓶颈往往不在“会不会算”,而在数据怎么搬、显存怎么用、请求怎么排。KV Cache、Prefill / Decode、PagedAttention、并行策略和推理引擎,看起来分散,其实都在解决同一件事:让有限的 GPU 资源支撑更长的上下文、更高的并发和更低的延迟。”

— 次阅读

1. 模型能跑,不等于服务能用
目录

1. 模型能跑,不等于服务能用

训练完成以后,模型已经具备了生成能力,但这距离真正上线还有一段距离。

训练更关心最终精度、总训练时间和大批次下的吞吐。一次训练可以持续几天甚至几周,数据也是提前准备好的。推理面对的是持续到来的真实请求,输入长度不同、输出长度不同、流量还会随时间变化。

因此生产环境里的目标不再只是“把一次前向计算跑完”,而是同时控制几件事:

  1. Latency(延迟):单个请求需要多久;
  2. Throughput(吞吐量):单位时间能处理多少请求或 Token;
  3. Concurrency(并发量):能够同时服务多少请求;
  4. Cost(成本):GPU 是否被有效利用;
  5. Reliability(可靠性):流量变化或部分故障时能否继续稳定工作。

这些指标经常互相牵制。为了提高吞吐量,可以把更多请求组成 Batch;但 Batch 等得太久,又会增加排队延迟。为了减少冷启动,可以提前保留已经加载模型的实例;这些实例空闲时又会产生额外成本。

所以大模型推理天然是一个系统问题:

Inference Performance=f(Compute,Memory,Communication,Scheduling,Software Stack)\text{Inference Performance}=f(\text{Compute},\text{Memory},\text{Communication},\text{Scheduling},\text{Software Stack})

这也是 AI Infra 和单纯“模型算法”开始分开的地方。


2. 推理性能指标

推理优化如果只看一个 tokens/s,很容易得出错误结论。在线服务至少要区分吞吐、首 Token 延迟和后续生成速度。

2.1 延迟与吞吐

Latency(延迟):关注一个请求从进入系统到得到结果需要多久。

Throughput(吞吐量):关注整个系统单位时间能处理多少请求或生成多少 Token。

两者不是同一个方向。某些优化可以提高总吞吐,但会让单请求多等一会儿;有些优化能让单请求更快,却可能降低 GPU 的整体利用率。

2.2 TTFT 与 TPOT

大模型是逐 Token 生成的,因此“总延迟”还可以继续拆开。

TTFT(Time To First Token,首词元延迟):表示请求到达以后,多久能看到第一个输出 Token。

它大致包括:

TTFT≈Queueing+Preprocess+Prefill+First Sampling\text{TTFT} \approx \text{Queueing}+\text{Preprocess}+\text{Prefill}+\text{First Sampling}

TPOT(Time Per Output Token,单输出词元时间):表示开始生成以后,平均生成一个新 Token 需要多久。

TTFT 更容易受到排队和 Prefill 影响,TPOT 则更接近 Decode 阶段的效率。

2.3 P99

平均延迟无法描述少量“特别慢”的请求。

P99 表示大约 99% 的请求延迟不超过这个值。P95、P99、P99.9 这类指标通常被称为 Tail Latency(尾延迟)。

线上服务真正容易影响体验的,往往不是平均值,而是高峰期突然出现的一批慢请求。SLA(Service Level Agreement,服务等级协议)因此通常会把可用性和尾延迟一起考虑。


3. 一次 LLM 请求的执行路径

一次文本请求进入系统后,大致经历下面几步:

Text
 ↓
Tokenizer
 ↓
Token IDs
 ↓
Prefill
 ↓
建立 KV Cache
 ↓
Decode:逐 Token 生成
 ↓
Sampling
 ↓
Streaming

多模态模型只是把前面的预处理变复杂了。图片可能经过 Resize、Normalize 和 Vision Encoder;音频可能经过 Resample、Feature Extraction 和 Audio Encoder。后面的核心推理问题仍然会落到计算、显存、调度和通信上。

Prefill 与 Decode 两阶段

图源:ZOMI / AIInfra《KV Cache 原理分析》

这张图真正需要区分的是两个阶段的输入规模和计算方式。Prefill 会一次处理整个 Prompt,同时为这些 Token 计算 K、V,并建立初始 KV Cache;Decode 每一步只接收一个新 Token,再读取前面已经保存的 KV Cache 完成注意力计算。

因此两者虽然都运行同一个 Transformer,负载特征却不同:Prefill 更容易形成大矩阵计算,并行度高;Decode 是逐 Token 推进,单步计算较小,却需要持续读取权重和越来越长的 KV Cache。后面 TTFT、TPOT、PD 分离以及调度策略的差异,都从这里开始。

3.1 输入预处理

文本需要先经过 Tokenizer(分词器):将文本转换成 Token ID,模型才能处理。

这一部分通常比 Transformer 本身轻得多,但当 GPU 计算越来越快、请求数量越来越大时,CPU 上的 Tokenization、图片预处理或音频特征提取也可能成为新的瓶颈。

常见优化包括批量处理、多线程、SIMD、缓存重复 Prompt,以及让 CPU、GPU 或其他加速器分担不同阶段。

3.2 Prefill

Prefill(预填充):一次处理整个输入 Prompt,并为后续生成建立 KV Cache。

长 Prompt 会形成较大的矩阵计算,因此 Prefill 往往具有较高并行度。在常见部署中,它更容易表现为 Compute-Bound(计算受限):主要时间花在矩阵乘法等计算上,而不是等待数据搬运。

这个判断不是绝对的。Prompt 长度、Batch Size、模型结构和硬件都会改变瓶颈,但它足够解释为什么 Prefill 的优化经常围绕算力利用率展开。

3.3 Decode

Prefill 完成以后,模型开始逐 Token 生成。

每生成一个新 Token,都需要读取模型权重,并访问前面已经保存的 KV Cache。单步计算规模不像 Prefill 那么大,但需要一遍又一遍读取大量数据。

因此 Decode 经常表现为 Memory-Bandwidth-Bound(显存带宽受限)。

Prefill 和 Decode 的差异可以压缩成一张表:

PrefillDecode
输入整个 Prompt每步新增 1 个 Token
并行度较高相对较低
常见瓶颈计算显存带宽
更直接影响TTFTTPOT

这个差异会一直影响后面的调度、硬件选择和 PD 分离。


4. GPU 的四个性能约束

判断一张 GPU 是否适合大模型推理,至少要同时看四件事:

  1. 计算能力;
  2. 显存容量;
  3. 显存带宽;
  4. GPU 之间的通信能力。

4.1 算力

GPU 是当前大模型训练和推理最常见的加速器,NPU、TPU 等设备也在不同平台承担类似的大规模张量计算。无论具体硬件是什么,Transformer 中大量计算最终都可以落到矩阵乘法,例如:

Y=XWY=XW

硬件宣传中常见 FLOPS、TFLOPS、PFLOPS 或 TOPS。

FLOPS(Floating Point Operations Per Second,每秒浮点运算次数):描述浮点计算能力;TOPS(Tera Operations Per Second):常见于 INT8、INT4 等低精度计算指标。

不同精度、不同算子下的峰值数字不能直接横向比较。FP16 的 100 TFLOPS 和 INT8 的 100 TOPS 并不代表相同的真实推理速度。模型精度、Tensor Core 支持、Kernel 实现和显存带宽都会改变最后的结果。

4.2 显存容量

显存里不只有模型权重。

一次推理通常还需要容纳 KV Cache、中间 Activation 和运行时 Buffer:

MGPU=Mweights+MKV+Mactivation+MbufferM_{GPU}=M_{weights}+M_{KV}+M_{activation}+M_{buffer}

以 7B 模型为例,只计算权重的理论体积:

精度每参数字节数7B 权重大小
FP324 B约 28 GB
FP16 / BF162 B约 14 GB
INT81 B约 7 GB
INT40.5 B约 3.5 GB

这里的 7B 指约 70 亿个参数,不是 7 GB。

权重能够放进显存,也不代表一定能承受高并发。大量长上下文请求会继续吃掉 KV Cache 空间。

4.3 显存带宽

显存容量决定“能放多少”,显存带宽决定“数据能多快送到计算单元”。

Decode 经常需要反复读取权重和历史 KV Cache,因此算力还没吃满,带宽可能已经先到上限。

可以用一个很粗的关系描述真实上限:

Actual Performance≤min⁡(Compute Limit,Memory Limit,Communication Limit)\text{Actual Performance}\leq \min(\text{Compute Limit},\text{Memory Limit},\text{Communication Limit})

这也是为什么换一张峰值 FLOPS 更高的 GPU,不一定能按比例提高 Decode 速度。

4.4 多卡通信

模型一张卡放不下以后,计算会被拆到多张 GPU。

常见链路包括:

  • PCIe:CPU、GPU 等设备之间常见的通用互联;
  • NVLink / NVSwitch:同机多 GPU 的高速互联;
  • InfiniBand:多机训练和推理集群常见的高速网络;
  • RDMA(Remote Direct Memory Access,远程直接内存访问):跨机器传输数据时尽量减少 CPU 参与;
  • RoCE(RDMA over Converged Ethernet):在以太网环境中提供 RDMA 能力。

多卡并行越频繁,通信越容易进入关键路径。算得很快但卡间同步很慢,整体性能仍然上不去。

NVLink 多 GPU 互联

图源:ZOMI / AIInfra《大模型推理与 AI Infra》

多 GPU 以后,计算不再只发生在单卡内部,卡与卡之间的数据交换也进入执行路径。例如 Tensor Parallelism 会把同一层的矩阵计算拆到多张 GPU,局部结果需要频繁同步;这时互联带宽和延迟会直接影响这一层多久能够结束。

所以这张图的重点不是记住 NVLink 的连接形状,而是理解一件事:模型拆得越细、跨卡同步越频繁,通信越可能从辅助开销变成真正的瓶颈。


5. 存储层次与 KV Cache

GPU 附近的数据不是全部放在同一种存储里。更快的存储通常容量更小、成本也更高。

推理存储层次

图源:ZOMI / AIInfra《大模型推理与 AI Infra》

这张图可以沿着“速度越来越慢,容量越来越大,单位成本越来越低”来读。HBM 离 GPU 最近,适合模型当前正在反复访问的权重和活跃 KV Cache;DRAM 可以承接 Offload 或较冷的数据;NVMe 和对象存储继续用访问速度换取更大的容量。

分层存储并不是要求一次部署必须把四层全部用上,而是在说明数据放置的基本原则:访问越频繁、越影响当前计算的数据,越应该留在靠近 GPU 的高速存储里。显存不够以后,问题就从“放不下”变成了“哪些数据值得留在 HBM,哪些可以暂时搬走”。

速度更快 / 容量更小
        ↑
       HBM
        ↓
       DRAM
        ↓
       NVMe
        ↓
    Object Storage
        ↓
速度更慢 / 容量更大

HBM(High Bandwidth Memory,高带宽内存):通常存放当前模型权重、活跃请求的 KV Cache 和当前计算需要的 Activation。

DRAM(Dynamic Random Access Memory,动态随机存取内存):容量更大,可以承接 Offload 的权重、较冷的 KV Cache 或预处理结果。

NVMe SSD 继续用速度换容量,适合冷模型、Checkpoint 或低频数据。

对象存储如 S3、OSS、COS、MinIO 更适合长期保存模型权重、数据集、日志和归档。

这里的基本原则很直接:访问越频繁的数据,越应该靠近 GPU。

5.1 KV Cache 的增长

自回归生成时,每个历史 Token 都会产生 Key 和 Value。后续生成还要继续使用这些结果,如果每一步都重新计算,成本会非常高。

因此历史 K/V 会被保存成 KV Cache(键值缓存)。

它的规模可以概念化为:

MKV∝B×S×L×NKV−head×Dhead×2M_{KV}\propto B\times S\times L\times N_{KV-head}\times D_{head}\times 2

其中:

  • B:Batch Size;
  • S:序列长度;
  • L:Transformer 层数;
  • N_KV-head:KV Head 数量;
  • D_head:每个 Head 的维度;
  • 2:同时保存 Key 和 Value。

序列越长、并发越高,KV Cache 就越大。

这解释了一个常见现象:模型权重明明已经能放进 GPU,服务一多还是会 OOM。真正挤占剩余显存的往往是不断增长的 KV Cache。

5.2 PagedAttention

传统 KV Cache 如果为每个请求预留大块连续显存,容易产生内存碎片,还可能因为提前预留而浪费空间。

PagedAttention(分页注意力):借鉴操作系统分页的思路,把逻辑上的 KV Cache 拆成 Block,再映射到不同的物理显存块:

PagedAttention 的块映射

图源:ZOMI / AIInfra《Paged Attention 原理》

这张图的关键在于逻辑连续和物理连续被分开了。对一条序列来说,KV Cache 仍然按 Token 顺序组织成连续的 Logical Block;真正放进显存时,这些 Block 可以落到完全不同的 Physical Block,再由 Block Table 保存两者之间的映射。

这样序列继续生成时,不需要提前预留一整段可能用不到的连续显存,只需要在现有 Block 快满时再申请新的物理块。请求结束后,对应的物理块也能直接归还并被其他请求复用。PagedAttention 优化的是这套 KV Cache 的内存管理方式,Attention 的数学公式本身没有改变。

Logical KV Blocks
       ↓
   Block Mapping
       ↓
Physical GPU Blocks

这样做的重点不是修改 Attention 公式,而是改变 KV Cache 的显存管理方式,使分配、复用和回收更灵活。

这也是 vLLM 早期最有代表性的设计之一。


6. 推理引擎:资源管理与调度

模型真正执行时,中间还隔着一整套软件层:

Model
  ↓
Inference Engine
  ↓
Compiler / Graph Optimization
  ↓
Operator Library
  ↓
GPU Kernel
  ↓
GPU

上层模型只描述需要完成什么计算,越往下越接近“这些计算具体怎样映射到 GPU”。

6.1 cuBLAS / CUTLASS

cuBLAS 是 NVIDIA 的高性能线性代数库,Transformer 中大量线性层最终都会落到 GEMM(General Matrix Multiplication,通用矩阵乘法)一类操作上。

它更适合直接调用成熟实现。

CUTLASS 也是 NVIDIA 提供的 CUDA 线性代数库,但更强调可定制性。Tile、Thread Block、数据布局、精度和 Tensor Core 使用方式都可以进一步调整。

两者的区别不在“一个快、一个慢”,而在控制粒度:cuBLAS 更接近成熟通用实现,CUTLASS 更适合需要自己深入 Kernel 结构的场景。

6.2 vLLM

vLLM 主要解决高吞吐 LLM Serving 中的资源管理和调度问题,包括:

  • KV Cache 管理;
  • PagedAttention;
  • Continuous Batching;
  • 多请求调度。

它关注的不是某一个矩阵乘法怎样写,而是很多不同长度的请求怎样更有效率地共享 GPU。

6.3 SGLang

SGLang 同样关注高效推理,但更进一步把结构化生成、Prompt 复用、Agent / Tool Calling 和多阶段生成程序纳入运行时调度。

这类系统的目标已经不只是“执行一次模型调用”,而是让复杂的生成程序也能复用前缀、缓存和计算资源。

6.4 TensorRT-LLM

TensorRT-LLM 更靠近 NVIDIA GPU 的深度优化,包括量化、Kernel 优化、多 GPU 并行和针对硬件特性的专门实现。

如果说 vLLM 更容易让人看到“请求调度和 KV Cache 管理”,TensorRT-LLM 更容易看到“为了把 NVIDIA GPU 性能吃满,软件栈能向下做到什么程度”。


7. Batching 与吞吐

GPU 擅长一次处理大量并行计算。如果一个请求一个请求地跑,很多计算资源会闲着,因此推理系统会把多个请求组合成 Batch。

Batch Size 增大通常会提高吞吐:

Batch Size↑⇒Throughput↑\text{Batch Size}\uparrow \Rightarrow \text{Throughput}\uparrow

但为了凑 Batch 等待太久,又会增加 Queueing Latency。

因此在线推理中的 Batch 不是越大越好,而是延迟和吞吐之间的动态平衡。

7.1 连续批处理

传统静态 Batch 的问题在于,不同请求的输出长度并不一样。

[A B C]
A 已结束,但 Batch 仍在等待 B、C

Continuous Batching(连续批处理):允许已经结束的请求立即退出,新的请求补进空位:

时刻 1:[A B C]
A 结束

时刻 2:[D B C]
B 结束

时刻 3:[D E C]

这样 GPU 不需要等整个 Batch 一起结束,在线服务的利用率会明显更高。

PagedAttention 解决 KV Cache 怎么更灵活地放;Continuous Batching 解决请求怎么更灵活地进出。两者都在服务同一个目标:减少 GPU 被无效占用的时间和空间。


8. PD 分离

前面已经看到,Prefill 更偏计算密集,Decode 更偏显存带宽和逐步生成。

如果两类负载混在同一批 GPU 上,它们会争抢资源,调度也更难稳定。

PD Disaggregation(Prefill-Decode 分离):把两个阶段拆到不同资源上:

Request
  ↓
Prefill GPU
  ↓
KV Cache Transfer
  ↓
Decode GPU
  ↓
Output

这样可以分别为 Prefill 和 Decode 选择更合适的硬件和扩缩容策略,也减少两类负载之间的干扰。

代价是 KV Cache 必须从 Prefill 节点传到 Decode 节点。

因此 PD 分离不是天然更快,它成立的条件是:

Resource Isolation Benefit>KV Transfer Cost\text{Resource Isolation Benefit} > \text{KV Transfer Cost}

这会继续把问题推向高速互联:NVLink、InfiniBand、RoCE、RDMA 都可能进入关键路径。

一个看起来属于“推理引擎调度”的设计,最后又回到了网络和硬件,这就是 AI Infra 很典型的跨层问题。


9. Kernel 与数据搬运

大模型的数学公式不变,执行速度仍然可能差很多,因为 GPU 真正运行的是底层 Kernel。

9.1 GPU 内部的存储层次

GPU 内部的数据大致沿着下面的层次移动:

HBM / Global Memory
        ↓
Shared Memory
        ↓
Register
        ↓
CUDA Core / Tensor Core

HBM 容量大,但离计算单元更远;Shared Memory 更快,由同一 Thread Block 内的线程共享;Register 最靠近计算单元,但数量非常有限。

很多 GPU 优化最后都在做同一件事:减少对 HBM 的重复访问,让已经搬进片上存储的数据尽可能多复用几次。

9.2 算子融合

连续执行多个小算子时,中间结果可能不断写回 HBM,再被下一个 Kernel 重新读取:

A
↓ 写回 HBM
B
↓ 再写回 HBM
C

Operator Fusion(算子融合):尝试把多个操作合进一个 Fused Kernel:

A + B + C
    ↓
Fused Kernel

收益主要来自两部分:减少 Kernel Launch 次数,以及减少中间数据的显存读写。

融合也不是越多越好。Kernel 过大以后,Register 和 Shared Memory 压力会上升,反而可能降低 Occupancy(占用率)和并行度。

9.3 内核调优

GPU Kernel 的执行效率和线程组织、Tile 大小、Shared Memory、Register 使用量、Memory Alignment(内存对齐)等因素有关。

NVIDIA GPU 中常见的层次包括:

  • Thread(线程):基本执行单元;
  • Warp(线程束):通常由 32 个线程组成;
  • Block(线程块):一组可以共享 Shared Memory 的线程;
  • Grid(网格):一次 Kernel Launch 中所有 Block 的集合。

Kernel Tuning 的难点不是单独把某一项资源用到最大,而是在并行度、Register、Shared Memory 和计算单元利用率之间找到平衡。

例如一个线程占用过多 Register,单个线程可能跑得很舒服,但同一时刻能驻留在 GPU 上的线程数量会下降。

9.4 FlashAttention

普通 Attention 的数学形式为:

Attention(Q,K,V)=Softmax(QKTd)V\text{Attention}(Q,K,V)=\text{Softmax}\left(\frac{QK^T}{\sqrt d}\right)V

FlashAttention 没有改变这个公式,它改变的是数据怎么在 HBM 和片上存储之间移动。

FlashAttention 分块计算

图源:Tri Dao,FlashAttention Recap

图中的蓝色块位于 HBM,橙色虚线框表示在更快的片上 SRAM 中完成的局部计算。FlashAttention 会把 K、V 按块读入 SRAM,每次只处理一部分 Attention,而不是先生成完整的 QKᵀ 矩阵再写回 HBM。

右侧的 l 和 O 用来记录当前分块计算中的 Softmax 归一化信息和部分输出。新的 K/V 块读入后,已有结果会按新的归一化系数重新缩放,再和当前块的结果合并。最终结果仍然与标准 Attention 一致,变化的是计算顺序和数据存放位置。

这也是 FlashAttention 最核心的优化:通过 Tiling(分块) 和中间结果重组,减少 HBM 与片上 SRAM 之间的数据搬运。它被称为 I/O-aware Algorithm(I/O 感知算法),这里的 I/O 指 GPU 不同存储层次之间的数据读写。


10. 模型压缩

推理系统面对的第一个硬限制通常是模型放不下,第二个才是模型跑得不够快。

因此一部分方法在减少单个模型的资源需求,另一部分方法则把模型拆到更多 GPU。

10.1 量化

Quantization(量化):用更少的 Bit 表示权重或 Activation。

常见精度路径包括:

FP32 → FP16 / BF16 → FP8 → INT8 → INT4

例如从 FP32 权重变成 INT8,理论权重体积可以降到原来的四分之一。

但权重缩小 4 倍,不代表推理一定快 4 倍。真实收益还取决于硬件是否支持对应低精度计算、Kernel 是否成熟、是否存在 Dequantization(反量化)开销,以及当前任务到底是 Compute-Bound 还是 Memory-Bound。

量化在 Decode 阶段尤其有吸引力,因为更小的权重意味着更低的显存容量和带宽压力。

10.2 混合精度

Mixed Precision(混合精度):并不要求整个模型使用同一种精度。

对数值更敏感的部分可以保留较高精度,其他部分使用 FP8、INT8 或 INT4,在模型质量、速度和显存之间折中。

10.3 蒸馏

Knowledge Distillation(知识蒸馏):让小模型学习大模型的输出分布、中间特征或生成结果。

它不是在现有大模型上单纯“省显存”,而是在模型层面换成更小的 Student Model,从根源上降低部署成本。

10.4 剪枝

Pruning(剪枝):通过删除不重要的参数或结构减少计算。

非结构化剪枝会得到稀疏但不规则的权重,GPU 未必能直接从这种稀疏性中获得同等比例的加速。

结构化剪枝直接删除 Head、Channel、FFN 单元或 Transformer Layer,结构更规则,因此通常更容易映射到实际硬件加速。


11. 多 GPU 并行

多 GPU 推理主要在解决两类问题:请求太多,或者模型太大。前者通常用 Data Parallelism 扩展服务能力,后者则需要 Model Parallelism(模型并行),继续拆成 TP、PP、EP 等方式。

11.1 数据并行

DP(Data Parallelism,数据并行):复制完整模型,把不同请求分给不同 GPU。

GPU0:完整模型 → 请求 A
GPU1:完整模型 → 请求 B
GPU2:完整模型 → 请求 C

它更适合扩大总吞吐和并发能力,但不能解决“单个模型本身放不下一张卡”的问题。

11.2 张量并行

TP(Tensor Parallelism,张量并行):在同一层内部拆矩阵。

        X
      /   \
   GPU0   GPU1
    W0     W1
      \   /
      合并

同一层需要多张 GPU 协作,因此通信非常频繁。NVLink、NVSwitch 一类高速互联会直接影响实际收益。

11.3 流水线并行

PP(Pipeline Parallelism,流水线并行):按照模型层切分:

GPU0:Layer 1~10
  ↓
GPU1:Layer 11~20
  ↓
GPU2:Layer 21~30

不同 Stage 之间会产生等待,形成 Pipeline Bubble(流水线气泡)。Micro Batch(微批次)可以提高流水线重叠程度,但也让调度更复杂。

11.4 专家并行与 MoE

EP(Expert Parallelism,专家并行):主要用于 MoE(Mixture of Experts,混合专家)模型。

MoE 不会让每个 Token 经过所有 Expert,而是由 Router 只选择少量 Expert:

Token
 ↓
Router
 ↓
Top-K Experts
 ↓
Selected Experts

这使总参数量可以很大,而单个 Token 真正激活的参数保持在较低水平。

如果不同 Expert 分布在不同 GPU,上游 Token 需要被发送到对应设备,因此 EP 会引入大量 All-to-All Communication(全互联通信)。

另一个问题是负载不均。如果大量 Token 都被 Router 送到同一个 Expert,其他 GPU 即使空闲,系统仍然要等最忙的 Expert。

因此 MoE Serving 还会继续遇到负载感知路由、Expert Capacity、Expert Replication 和动态扩缩容等问题。

11.5 长上下文

上下文特别长时,单张 GPU 可能放不下完整 Attention 计算和 KV Cache。

Sequence Parallelism、Context Parallelism、Ring Attention、Ulysses 等方法会沿序列或上下文维度继续切分。

难点在于 Attention 中不同 Token 之间存在依赖。序列被拆开以后,K/V 或中间结果仍需要跨 GPU 交换。

因此长上下文并行始终是在“把序列拆开”和“别让通信成本吃掉收益”之间找平衡。


12. 采样与流式输出

12.1 采样

模型每一步先输出对整个词表的 Logits,再由 Sampling 决定下一个 Token。

常见策略包括:

  • Greedy Decoding:直接选择概率最高的 Token;
  • Top-K Sampling:只保留概率最高的 K 个候选;
  • Top-p / Nucleus Sampling:保留累计概率达到阈值 p 的最小候选集合;
  • Beam Search:同时维护多条候选序列,代价是额外计算和 KV Cache。

聊天模型更常见的是 Temperature、Top-p、Top-k 等组合,而不是大规模 Beam Search。

12.2 流式输出

非流式输出会等完整结果生成以后一次性返回;Streaming(流式输出):Token 一生成就开始发送。

Token 1 → 返回
Token 2 → 返回
Token 3 → 返回

Streaming 不一定提高模型真实的 Token/s,但会明显改善用户感知延迟。

文本生成中常见协议包括 SSE(Server-Sent Events)和 WebSocket。对于单向持续返回文本的场景,SSE 很常见。


13. 从推理引擎到在线服务

推理引擎解决的是“这一批模型请求怎样在 GPU 上更高效地执行”。真正上线以后,还要处理请求路由、实例扩缩容、故障恢复和版本管理。

大模型推理服务化部署

图源:ZOMI / AIInfra《大模型推理与 AI Infra》

到了这一层,关注点已经从“单个模型怎样在 GPU 上跑快”扩展到“很多模型实例怎样长期对外提供服务”。底层仍然是 GPU 和推理引擎,但它们外面还需要实例管理、请求路由、负载均衡、扩缩容、监控和故障恢复。

因此 KServe、Ray Serve 这类系统并不是 vLLM、SGLang 的替代品,它们解决的是更外层的问题。推理引擎负责把一批请求高效地送进 GPU,服务层负责决定请求送到哪个实例、实例什么时候扩容,以及某个实例失效后由谁接管。

一条常见服务链路可以写成:

Client
  ↓
API Gateway
  ↓
Router / Load Balancer
  ↓
Model Instance
  ↓
vLLM / SGLang / TensorRT-LLM
  ↓
GPU

外层通常还有 Kubernetes、KServe、Ray Serve 等系统负责实例生命周期和分布式编排。

13.1 预热池

模型实例从启动到真正能够服务请求,需要加载权重、初始化 GPU 和建立运行时环境。

流量突然上升时再从零启动,容易形成明显的 Cold Start(冷启动)。

Warm Pool(预热池):提前保留一部分已经加载好的实例,用空闲资源换更低的扩容延迟。

这不是免费的优化:预热实例越多,资源浪费也越大。

13.2 自动伸缩

Autoscaling(自动伸缩):根据流量和资源状态增减实例数量。

Reactive Autoscaling 在检测到负载升高以后再扩容;Predictive Autoscaling 尝试在高峰到来之前提前准备资源。

LLM 模型启动和加载比较慢,因此预测式扩容比普通无状态 Web 服务更有价值,同时也更难做准。

13.3 请求路由

传统服务可以按 Round Robin、Least Connections、Geo Routing 或 Version Routing 等策略分配请求。

LLM 请求的成本差异更大。两个请求虽然都是“一条请求”,一个可能只有几十个 Prompt Token,另一个可能带着上万 Token 的上下文。

因此更合适的路由可能继续考虑:

  • Prompt Token 数;
  • 预测输出长度;
  • KV Cache 占用;
  • GPU 利用率;
  • 当前队列长度;
  • Prefill / Decode 负载。

这也是为什么 LLM Serving 的负载均衡不能简单照搬普通 Web 服务。

13.4 KServe / Triton / Ray

KServe 更偏 Kubernetes 原生的模型服务管理,关注部署、扩缩容、路由和版本生命周期。

Triton Inference Server 是 NVIDIA 的推理服务器,提供 HTTP / gRPC 接口、动态批处理、多模型管理、后端管理和性能指标采集。

它和用于编写 GPU Kernel 的 Triton Language 不是同一个项目,名字很像,但所在层次完全不同。

Ray / Ray Serve 更适合分布式任务和多阶段 AI Workflow,例如模型、Agent、Tool 之间存在复杂调用关系时,需要跨节点调度不同组件。


14. 完整推理栈

从上到下看,LLM Serving 大致可以分成这些层:

┌────────────────────────────────────┐
│ Client / API                       │
├────────────────────────────────────┤
│ Routing / SLA / Load Balancing     │
├────────────────────────────────────┤
│ KServe / Ray Serve                 │
├────────────────────────────────────┤
│ vLLM / SGLang / TensorRT-LLM      │
├────────────────────────────────────┤
│ Batching / KV Cache / TP / PP / EP│
├────────────────────────────────────┤
│ Compiler / Fusion / Triton Kernel  │
├────────────────────────────────────┤
│ cuBLAS / CUTLASS / CUDA Kernel     │
├────────────────────────────────────┤
│ GPU / HBM / NVLink / RDMA          │
└────────────────────────────────────┘

最开始学习这些名词时,很容易把它们当成平行的技术点。真正连起来以后,它们其实分别在处理不同层次的瓶颈。

模型放不下,会碰到量化、TP、PP、EP 和 KV Cache 管理;模型跑不快,会继续碰到 Kernel、FlashAttention、Fusion 和带宽;请求一多,又会进入 Continuous Batching、Routing、Autoscaling 和 SLA。

所以推理优化最重要的习惯不是看到一个新技术就往系统里加,而是先确定瓶颈到底在哪一层。


15. 知识总结

  1. LLM 推理的目标不是单次前向最快,而是在有限资源下同时控制延迟、吞吐、并发、成本和稳定性。
  2. Prefill 和 Decode 的负载特征不同。 Prefill 往往更偏计算密集,Decode 更容易受到显存带宽和 KV Cache 影响。
  3. KV Cache 是在线推理里非常核心的资源。 上下文越长、并发越高,占用越大;PagedAttention 本质上是在改进它的显存管理。
  4. 推理引擎的价值在调度。 vLLM、SGLang 等系统不仅执行模型,还要决定请求怎么组成 Batch、KV Cache 怎么放、资源怎样复用。
  5. 很多 GPU 优化本质上是在减少数据搬运。 Operator Fusion、Tiling、FlashAttention 都和 HBM 访问成本密切相关。
  6. 多 GPU 以后,通信会进入关键路径。 TP、EP、长上下文并行和 PD 分离都可能因为通信成本失去收益。
  7. 模型服务化以后,问题从 GPU 扩展到整个系统。 Routing、Autoscaling、Warm Pool、SLA 决定模型能不能长期稳定地服务真实流量。
  8. 优化之前先定位瓶颈。 算力、容量、带宽、通信、调度可能分别成为限制,单纯换更强硬件并不能保证问题消失。

参考资料

  1. ZOMI / Infrasys-AI, AIInfra — 05. 大模型推理与 AI Infra
    https://github.com/Infrasys-AI/AIInfra/blob/main/00Summary/05InferStack.md

  2. ZOMI / Infrasys-AI, AIInfra
    https://github.com/Infrasys-AI/AIInfra

  3. Kwon et al., Efficient Memory Management for Large Language Model Serving with PagedAttention, SOSP 2023.
    https://arxiv.org/abs/2309.06180

  4. Kwon et al., vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention, vLLM Official Blog.
    https://vllm.ai/blog/2023-06-20-vllm

  5. Dao et al., FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness, NeurIPS 2022.
    https://arxiv.org/abs/2205.14135

  6. Tri Dao, FlashAttention-3: Fast and Accurate Attention with Asynchrony and Low-precision, official blog (FlashAttention Recap figure).
    https://tridao.me/blog/2024/flash3/

  7. Zheng et al., SGLang: Efficient Execution of Structured Language Model Programs.
    https://arxiv.org/abs/2312.07104

  8. NVIDIA, TensorRT-LLM Documentation
    https://nvidia.github.io/TensorRT-LLM/

  9. KServe Documentation
    https://kserve.github.io/website/

  10. Ray Serve Documentation
    https://docs.ray.io/en/latest/serve/

← 返回博客English →
Discussion

评论

欢迎交流想法,也欢迎留下问题。

正在加载评论…

无需登录,昵称和邮箱为必填项。邮箱不会公开,仅用于身份区分与回复通知;服务端会保留必要的请求时间、IP 和设备信息,用于反垃圾、限流、封禁与安全审计。