vLLM系统拆解-18-通用LLM推理系统设计:从vLLM出发建立框架
vLLM系统拆解-18-通用LLM推理系统设计:从vLLM出发建立框架
前面十几篇把 vLLM 的核心机制都拆解过了:PagedAttention、prefix caching、unified scheduler、chunked prefill、speculative decoding。但有一个问题没正面回答:这些设计里,哪些是 vLLM 独有的,哪些其实是任何成熟推理系统都绕不开的?
这篇文章换一个视角——不再盯着 vLLM 的实现细节,而是把它当作一个具体案例,用来拼出一套通用 LLM 推理系统的设计框架。
读完这篇,你应该能做到:
- 把 vLLM 的各个机制放进更大的系统分层里定位
- 区分 LLM 推理系统的共性设计问题与 vLLM 的特定选择
- 在面试里把"会讲 vLLM"升级为"能讲清通用推理系统设计"
推理系统解决什么问题
用 Transformers 的 model.generate() 跑一个 prompt,这是"单请求、单次调用"视角——模型加载、forward、输出 token,完事。
真正的线上推理系统面对的是另一个问题空间:
- 请求持续流入,长度各不相同
- 显存有限,KV Cache 会随着生成持续增长
- 系统必须同时照顾吞吐、延迟、成本和稳定性
- 不是一批请求来了处理完再等下一批,而是新请求随时加入、已有请求随时结束
推理系统的本质不是"让模型能生成",而是"在资源受限、请求动态变化的条件下,让模型稳定且高效地持续生成"。
把这个问题展开,任何推理系统都必须同时做好五件事:
| 目标 | 含义 |
|---|---|
| 算得动 | 模型能在目标硬件上运行,权重加载、精度、量化、并行都要支持 |
| 装得下 | 权重和 KV Cache 共存于有限显存,不 OOM,不频繁抢占 |
| 调得好 | 动态到来的请求能被高效组织,prefill/decode 混排,资源分配合理 |
| 回得快 | 首 token 延迟(TTFT)和后续 token 间隔(ITL)都在 SLA 以内 |
| 扩得开 | 能从单卡走向多卡、多机,满足规模增长 |
六层结构
把一个成熟的 LLM 推理系统分成六层,有助于定位问题、划分职责、做系统设计。
flowchart TB
L6["第 6 层:控制与运维层\n监控 / 日志 / Autoscaling / 热更新"]
L5["第 5 层:服务层\nHTTP/gRPC API / Streaming / 多租户"]
L4["第 4 层:调度层\nContinuous Batching / Token Budget / 抢占"]
L3["第 3 层:状态管理层\nKV Cache 分配 / 回收 / 跨请求复用"]
L2["第 2 层:执行层\nKernel / CUDA Graph / FlashAttention / Sampler"]
L1["第 1 层:模型表示层\n架构 / 权重加载 / 量化 / 图优化"]
L6 --> L5 --> L4 --> L3 --> L2 --> L1
第 1 层:模型表示层。关心模型架构是什么(Decoder-only、MoE、多模态等)、权重如何加载和存储、是否需要量化和图融合。没有这一层,系统连 forward 都无法执行。大多数研究代码只到这一层,关心"单次 forward 的正确性",不关心服务场景。
第 2 层:执行层。每轮 forward 如何在 GPU 上执行——attention、MLP、norm、sampler 的具体算子,kernel 调度,CUDA Graph、FlashAttention 等优化手段。这一层解决"每一轮算得够不够快"。
第 3 层:状态管理层。这是 LLM 推理系统和普通深度学习推理最不一样的地方。自回归生成要求系统跨轮维护每个请求的 KV Cache——它从哪里分配、什么时候回收、能不能跨请求复用、哪些前缀可以共享。vLLM 的 PagedAttention、block 化 KV Cache、prefix caching,本质都在这一层。
第 4 层:调度层。这是系统大脑。本轮哪些请求进 batch、token budget 如何分配、prefill 和 decode 如何混排、资源不够时谁被抢占、谁被延后。没有调度层,系统只能做静态批处理;真实线上流量不是静态批次。
第 5 层:服务层。OpenAI-compatible API、tokenization、流式返回、请求超时取消、多租户隔离。很多人会低估这一层,但线上系统最终靠它接住业务。
第 6 层:控制与运维层。监控指标、日志与 tracing、autoscaling、故障恢复、模型热更新。前五层解决"如何推理",这一层解决"如何长期可靠运行"。
vLLM 带来的思维转变
现在把 vLLM 放进这个框架里看,它贡献的不只是某个 kernel,而是四件事组合成的系统思路:
-
把 KV Cache 当成核心系统资源,而不是附属张量——分 block 管理、可回收、可复用、可调度,而不是单请求 forward 过程中的内部状态。
-
把调度看成动态持续过程,而不是静态 batch 组织——每个调度周期都重新决定哪些请求推进、以多少 token budget 推进,而不是"一批请求来了处理完再等下一批"。
-
把请求复用和显存管理统一到同一套 block 语义里——prefix caching 不是独立特性,而是 block 化 KV Cache 的自然延伸。
-
把服务、调度、worker 执行拆成清晰的多进程架构——职责分离,便于独立演进和调试。
这四点里,第 1、2、3 点的系统意义最重要。它背后是一次关键的思维转变:
传统深度学习推理框架:模型 forward 是中心,batch 是输入的组织方式,中间状态是 forward 的附属产物。
LLM 在线推理:真正的中心对象变成了请求、KV 状态、调度周期、token budget——模型 forward 从"唯一主角"变成"被调度系统反复调用的执行单元"。
以后看任何推理系统,可以先问一句:这个系统是把"模型"放在中心,还是把"请求与状态调度"放在中心?如果是后者,它通常更接近服务型推理引擎。
三组核心矛盾
任何 LLM 推理系统设计,都要在三组核心矛盾之间做取舍。这不是某个框架的特殊问题,而是这个问题域的固有张力。
| 矛盾 | 两端是什么 | 怎么取舍 |
|---|---|---|
| 吞吐 vs 延迟 | 大 batch 有利于 GPU 利用率(吞吐好),但等待更多请求会让当前用户排队(延迟差) | 离线批处理偏吞吐;在线聊天偏 TTFT 和 ITL;不同场景最优设计不同 |
| 计算资源 vs 状态资源 | 传统推理只看 kernel 速度;但 LLM 自回归生成要一边算、一边积累 KV Cache,状态是长期负担 | 系统必须同时优化算子性能和 KV Cache 管理,只做其一都不够 |
| 通用框架 vs 专项极致 | 通用框架模型覆盖广、易维护、快速支持新模型;专项系统针对特定硬件和模型打磨到极致 | 模型经常迭代 → 通用框架;模型固定且量大 → 专项优化;没有绝对高下 |
吞吐和延迟的矛盾值得多说一点。GPU 喜欢大工作量——batch 越大,kernel 启动开销摊薄越充分,SM 利用率越高,单 token 平均成本越低。但如果为了追求大 batch 而总是等待更多请求,当前用户 TTFT 就会上升,已经在 decode 的请求也可能被长 prefill 拖慢。真正成熟的设计不是消灭这组矛盾,而是根据目标 workload 决定在哪里取舍。
从零设计通用推理系统:10 个必须先想清的问题
这 10 个问题可以直接当系统设计题的骨架用:
| # | 问题 | 为什么重要 |
|---|---|---|
| 1 | 目标 workload 是什么? | 离线批处理 / 在线聊天 / agent 多轮 / 高共享前缀 RAG,后续所有设计都依赖这个前提 |
| 2 | 主要优化目标是什么? | 最大吞吐 / 最低 TTFT / 最低 ITL / 最低成本 / 最大并发——不先定目标无从谈设计 |
| 3 | 模型和硬件约束是什么? | 模型大小、上下文长度、GPU 显存、单卡/多卡、是否允许量化,直接决定并行策略和 batch 上限 |
| 4 | 状态怎么存? | KV Cache 连续分配还是 block 化?分配粒度多大?如何回收?是否支持跨请求复用? |
| 5 | 请求怎么调度? | 静态 batch 还是 continuous batching?prefill/decode 如何混合?token budget 如何定义? |
| 6 | 执行器怎么设计? | 每轮 forward 走 eager 还是 graph capture?attention 用什么实现?sampler 在 CPU 还是 GPU? |
| 7 | 并行怎么做? | 单卡不够时先 TP 还是 PP 还是 DP?MoE expert 路由与通信如何处理?通信和计算能否 overlap? |
| 8 | 服务接口怎么做? | OpenAI-compatible API?是否支持 streaming?如何做取消、超时?多租户怎么隔离? |
| 9 | 监控与调优怎么做? | 暴露哪些指标?如何看 TTFT / ITL / throughput / cache hit rate?如何定位各类瓶颈? |
| 10 | 如何持续演进? | 模型升级、新量化格式、新硬件后端、新加速特性——推理系统不是一次性工程 |
vLLM 的特色选择 vs 通用共性
学完 vLLM 后很容易把它的所有设计当成独创,实际上可以明确区分两类。
任何成熟推理系统都绕不开的共性问题:
- Prefill / Decode 的阶段差异及其对调度的影响
- 吞吐与延迟的权衡
- 动态请求调度(而不是等全批凑齐再处理)
- KV Cache 的存储、增长与回收
- 多卡并行与通信代价
- 服务接口与流式输出
- 监控、调优与故障定位
面试时不要把这些说成"vLLM 发明了这些问题"——这是 LLM 推理系统的共性挑战。
vLLM 对上述共性问题给出的特定工程答案:
| vLLM 特色 | 对应哪个共性问题 |
|---|---|
| Block/Page 化 KV Cache 管理 | KV Cache 的存储与回收 |
| PagedAttention(attention 访问适配 paged KV) | 执行层对 block 化状态的适配 |
| Prefix Caching(block 级 hash 复用) | 跨请求前缀共享 |
| Unified Scheduler + token budget 抽象 | Prefill/decode 混排调度 |
| 强吞吐/显存效率平衡(通用服务场景) | 吞吐与延迟的综合权衡 |
vLLM 的价值在于:这些共性问题是通用的,但它对这些问题给出了一套很系统、很工程化、很适合通用服务场景的答案。
面试回答框架:借 vLLM 讲系统设计
当面试官问"你学过 vLLM,那你觉得一个通用 LLM 推理系统应该怎么设计?"时,以下是一种比较成熟的答法主线:
1 | 第一步:先定 workload |
这个框架的好处是:没有被框死在某个框架特性里,把问题提升到了系统设计层,同时又能用 vLLM 作为具体例子支撑判断。
成熟推理系统工程师的五个思维习惯
这五个习惯是从 vLLM 学习中可以提炼出的可迁移认知:
习惯 1:先问 workload,再谈优化。 "某系统更快"在没有上下文时没有意义。先问:什么模型、什么硬件、什么并发、什么 prompt 长度分布、什么延迟 SLA——否则"更快"只是一句空话。
习惯 2:把状态当一等公民。 LLM 推理里,KV Cache 不是 forward 的副产物,而是持续增长的核心资源。谁把状态管理得好,谁更可能做出真正成熟的系统。
习惯 3:把系统拆层,而不是把特性堆在一起。 遇到复杂系统时,先问:这是调度问题?状态问题?执行器问题?服务层问题?运维问题?能拆层,才能定位问题和设计改进,特性列表叠再多也没用。
习惯 4:任何优化都要讲代价和边界。 Speculative decoding 不是永远有效;更大 batch 不一定对延迟友好;更激进量化可能伤精度;更复杂调度可能增加 CPU 开销。成熟的工程理解永远是"收益 + 代价 + 适用边界"三件套。
习惯 5:把实现细节上升为设计原则。 学完 vLLM,不应该只记住"它有 PagedAttention、有 prefix caching、有 unified scheduler",而应该上升到:
- 长生命周期状态要按系统资源来管理
- 动态流量要用持续调度而不是静态批处理
- 复用机制最好建立在统一的数据抽象之上
这才是遇到新系统也能迁移理解的基础。
12 个核心命题
把这一篇的核心结论压缩成 12 句话,每一句都值得单独思考:
- LLM 推理系统不只是计算系统,还是状态管理系统。
- 线上推理的核心对象不是单次 forward,而是持续到来的请求。
- 任何成熟推理系统都必须同时处理吞吐、延迟、显存和稳定性。
- Prefill / Decode 的差异会直接决定调度和优化策略。
- KV Cache 是 LLM 推理系统最重要的长期资源之一。
- 调度的任务不是把 batch 拼起来,而是在动态工作负载下分配推进机会。
- 好的推理系统,不只要算得快,还要装得下、调得稳、扩得开。
- 通用框架和专项极致优化没有绝对高下,关键看业务场景。
- vLLM 的强项不只是一个 kernel,而是一套围绕请求与状态组织起来的系统设计。
- 问题往往是通用的,系统之间真正拉开差距的是对这些问题的工程答案。
- 面试里讲 vLLM 时,最好能上升到通用 LLM 推理系统设计层面。
- 真正学会一个推理系统,不是会背特性,而是能提炼出可迁移的设计原则。
到这里,这个系列从单机 serving 原理、KV Cache 管理、调度机制、分布式部署、性能调优,到横向框架对比,走到了最后一步——把 vLLM 当成一个具体案例,拼出了通用 LLM 推理系统的设计框架。
