01

认识 vLLM

当你向 ChatGPT 提问时,背后发生了什么?vLLM 就是那个让大模型飞速回答的引擎。

你每天都在用,只是不知道它的名字

想象一下:你在手机上跟 AI 聊天,输入一句话,它几乎瞬间就开始回答。这段"瞬间"的背后,有一个叫做 vLLM 的系统在疯狂运转。

vLLM 是一个推理引擎——它的任务就是把训练好的大语言模型(比如 LLaMA、Qwen)部署到服务器上,让成千上万的用户可以同时和模型对话。

💡
关键概念:训练 vs 推理

训练是让模型"上学"——喂给它海量文本,让它学会语言规律。这个过程可能花费数百万美元和几个月时间。推理是训练完成后,模型开始"工作"——回答用户的问题。vLLM 只负责推理这个环节,但这一环节的效率直接决定了用户体验和成本。

为什么不能直接用模型?

你可能会想:模型训练好了,直接让它回答不就行了?问题在于——大模型太大了,太慢了,太贵了

📦

模型巨大

一个 70B(700 亿参数)的模型需要约 140GB 显存。一张顶级显卡只有 80GB,放不下一个模型。

🐢

生成很慢

模型一次只生成一个 token,如果不做优化,每秒可能只吐出几个字。

💰

GPU 极贵

一张 NVIDIA A100 显卡售价超过 10 万元人民币。如果每个用户独占一张卡,成本是天文数字。

🎯
vLLM 的核心使命

让一张 GPU 同时服务尽可能多的用户,让每个用户的等待时间尽可能短。一句话:又快又省

一个请求的旅程

当你在聊天框里输入"什么是量子计算?"并点击发送,数据经历了这样的旅程:

👤
用户
🌐
API 服务器
📋
调度器
GPU 模型
点击"下一步"开始

启动 vLLM 只需要一行命令

这就是 vLLM 如此受欢迎的原因之一——你不需要写复杂的代码,一条命令就能启动一个高性能推理服务:

命令行

python -m vllm.entrypoints.openai.api_server \
  --model meta-llama/Llama-2-7b-chat-hf \
  --tensor-parallel-size 2 \
  --max-model-len 4096
            
白话翻译

启动 vLLM 的 API 服务器(兼容 OpenAI 的接口格式)…

加载 Meta 公司的 LLaMA-2 7B 对话模型…

使用 2 张 GPU 并行处理(把模型分到两张卡上)…

最多支持 4096 个 token 的上下文长度。

启动后,vLLM 就在 http://localhost:8000 上监听请求了。你完全可以用调用 OpenAI API 一样的方式来调用它。

检测你的理解

vLLM 的主要职责是什么?

为什么不能直接运行大模型,而需要 vLLM 这样的推理引擎?

02

核心架构

vLLM 内部有哪些"角色"?它们如何协作?认识系统的"演员表"。

vLLM 的演员表

一个好的系统就像一部电影——每个角色各司其职。vLLM 有五个核心角色:

🌐
API 服务器(API Server)

前台接待员——接收用户请求,返回模型回答。兼容 OpenAI 的 API 格式。

📋
调度器(Scheduler)

交通指挥——决定哪些请求先上 GPU、哪些排队等候。它像一个精明的项目经理。

🧠
模型执行器(Model Executor)

核心计算引擎——把模型的数学运算安排到 GPU 上执行。真正的"干活的人"。

💾
KV Cache 管理器

记忆管家——管理模型的"草稿纸"空间,让多用户的草稿纸互不冲突。

🔀
分块预填充(Chunked Prefill)

聪明的工作安排——把长文本拆成小块,跟其他请求混在一起处理,提高 GPU 利用率。

全局架构一览

点击架构图中的任意组件,了解它的职责:

用户侧

👤
用户 / 客户端

vLLM 核心

🌐
API Server
📋
Scheduler(调度器)
💾
PagedAttention / KV Cache

硬件层

GPU / Model Executor
点击任意组件查看说明

当请求来了——角色们的对话

让我们"偷听"一下 vLLM 内部角色们在处理一个请求时的对话:

代码中的调度器核心逻辑

调度器是 vLLM 最精妙的组件之一。以下是其核心调度逻辑的简化版本:

Python

class Scheduler:
  def schedule(self):
    # 调度器每次循环调用这个方法
    scheduler_outputs = []
    for seq_group in self.waiting:
      if self._check_memory(seq_group):
        self._allocate(seq_group)
        scheduler_outputs.append(
          seq_group)
    return scheduler_outputs
            
白话翻译

定义一个调度器类……

核心调度方法——每个循环周期调用一次……

(注释说明了调用时机)

准备一个空列表来收集本轮被批准的请求……

遍历所有正在排队等待的请求……

检查:GPU 显存够不够放下这个请求的 KV Cache?……

如果够,就为它分配 KV Cache 物理页……

把它加入本轮的执行列表……

返回所有获准进入 GPU 的请求列表。

架构理解测试

在 vLLM 中,谁负责决定一个请求何时可以被送上 GPU 处理?

KV Cache 管理器的主要职责是什么?

03

内存与性能优化

vLLM 最厉害的创新——PagedAttention,一个来自操作系统课本的灵感。

GPU 显存的碎片化噩梦

要理解 PagedAttention 为什么伟大,先得理解它解决了什么问题。

想象你经营一个停车场——但车的大小各不相同。有的只需要 2 个车位,有的需要 50 个。问题是:你不知道一辆车进来时会占多少车位(因为生成的文本长度不确定)。

传统做法是给每辆车预留最大可能的空间。结果?大部分车位空着,但已经"名花有主",别人用不了。

⚠️
传统方案的浪费

在 vLLM 出现之前,推理框架的显存利用率通常只有 20-40%。也就是说,一张 80GB 的 A100 显卡,实际可能只利用了 16-32GB,剩下的 48GB 被浪费在"预留但没用"的空间上。

PagedAttention:来自操作系统的灵感

这个问题的解法,计算机科学家在 1960 年代就找到了——虚拟内存分页

1
把 KV Cache 切成固定大小的"页"

每个页可以存放固定数量(比如 16 个)token 的 KV 值。不再为每个请求预留一大块连续空间。

2
建立页表——虚拟页到物理页的映射

每个请求有一个页表,记录"我的第 1 页存在物理页 #7,第 2 页存在物理页 #23"。页不需要连续!

3
按需分配,用完回收

生成新 token 时才分配新页。请求结束后,所有页立刻回收,可以被其他请求复用。零浪费。

💡
核心洞察

这个设计直接将显存利用率从 20-40% 提升到 接近 100%。同样一张 GPU,vLLM 可以服务 2-4 倍的用户。这就是 vLLM 能在 2023 年横空出世、迅速成为业界标准的原因。

PagedAttention 在代码中的实现

vLLM 的 KV Cache 管理器实现了一个类似操作系统内存管理器的页表系统:

Python

class BlockSpaceManager:
  def allocate(self, seq_group):
    num_blocks = math.ceil(
      seq_group.num_tokens / self.block_size)
    for i in range(num_blocks):
      block = self.free_blocks.pop()
      self.block_tables[seq_id].append(
        block)
    return self.block_tables[seq_id]
            
白话翻译

块空间管理器——相当于操作系统的内存管理器……

分配方法——为一个请求分配所需的缓存块……

算一下需要多少个块:总 token 数 ÷ 每块的容量,向上取整……

(续上行的计算)

逐个分配需要的块……

从空闲块池里取出一个块……

记录到这个请求的页表里——"第 i 页指向物理块 block"……

(续上行的记录操作)

返回这个请求的完整页表。

连续批处理:让 GPU 永远不闲着

PagedAttention 解决了"显存不够用"的问题。但还有另一个问题:GPU 的计算能力没有被充分利用

传统静态批处理

凑齐一批请求一起送 GPU。但 batch 里最长的请求完成之前,其他已经完成的请求还在等待,白白浪费 GPU 时间。

vLLM 连续批处理

每当一个请求生成完毕,立刻从等待队列拉一个新请求进来填补空位。GPU 的每一轮计算都是"满载"状态——没有空闲、没有等待。

🎯
为什么这很重要?

连续批处理让 vLLM 的 吞吐量比传统方案提升 2-4 倍。结合 PagedAttention 的显存优化,vLLM 的整体效率可以达到传统方案的 4-10 倍

优化策略理解测试

PagedAttention 的核心思想借鉴了哪个操作系统概念?

连续批处理(Continuous Batching)比静态批处理好在哪?

04

请求处理全流程

从你按下"发送"到 AI 开始回答,数据在 vLLM 内部经历了什么?完整追踪一次请求的一生。

推理的两个阶段

大模型的推理过程分为两个截然不同的阶段——就像读书和写文章是两种完全不同的脑力活动:

📖

Prefill 阶段(预填充)

"读书"——把用户的 prompt(可能是一段很长的文本)一次性通过模型,计算出所有 token 的 KV Cache。这一步是计算密集型的,但只做一次。就像读完整篇材料后,知识已经记在脑子里了。

✍️

Decode 阶段(逐 token 生成)

"写文章"——基于已经算好的 KV Cache,每次生成一个新的 token。每生成一个 token 都要访问之前所有的 KV 值。这一步是访存密集型的,速度受限于 GPU 显存带宽。

💡
为什么区分这两个阶段很重要?

因为它们对硬件的需求完全不同。Prefill 需要 GPU 的计算能力(大量的矩阵乘法),Decode 需要显存带宽(快速读取 KV Cache)。理解这一点,你就能更好地选择 GPU 型号和配置参数。

一个完整请求的数据流追踪

让我们追踪一个请求从进入到结束的完整旅程。点击"下一步"逐步观看:

👤
用户
🌐
API Server
📋
Scheduler
💾
BlockManager
GPU Engine
点击"下一步"开始追踪

Decode 循环的核心代码

在 vLLM 中,生成的核心是一个循环——每一步生成一个 token,直到满足停止条件:

Python

while seq_group.is_finished() is not True:
  scheduler_outputs = scheduler.schedule()
  output = model_executor.execute_model(
    scheduler_outputs)
  for seq in output:
    seq.append_token(seq.last_token)
  if has_eos_token(output):
    break
            
白话翻译

只要这个请求还没生成完毕,就一直循环……

调度器决定这一轮哪些请求可以进入 GPU(包含正在生成的和新进入的)……

把本轮所有请求打包交给 GPU 执行……

(续上行的 GPU 执行调用)

遍历 GPU 返回的结果,每个请求都有一个新 token……

把新 token 追加到这个请求的序列末尾……

如果生成了结束符(表示模型觉得回答完了)……

跳出循环,这个请求处理完毕。

模型太大怎么办?——张量并行

70B 参数的模型有 140GB,一张 A100 只有 80GB。vLLM 用张量并行来解决这个问题:

1
把模型的权重矩阵按列切开

比如一个 4096×4096 的矩阵,用 4 张 GPU,每张只需存储 4096×1024——四分之一的大小。

2
每张 GPU 独立计算自己那一部分

输入数据复制到每张卡上,各卡并行做矩阵乘法。互不干扰,同时进行。

3
用 AllReduce 通信汇总结果

每层计算完后,GPU 之间通过高速通信(如 NVLink)交换结果,拼出完整输出。

请求流程理解测试

Prefill 阶段和 Decode 阶段的核心区别是什么?

如果模型太大放不进一张 GPU,vLLM 的张量并行是怎么解决的?

05

实战部署与调试

掌握了原理之后,如何在实际项目中部署 vLLM?遇到问题怎么排查?

生产环境的启动参数

前面我们看到过最简启动命令。在实际生产中,你需要更多参数来调优性能和资源使用:

命令行

python -m vllm.entrypoints.openai.api_server \
  --model Qwen/Qwen2.5-72B-Instruct \
  --tensor-parallel-size 4 \
  --gpu-memory-utilization 0.90 \
  --max-model-len 8192 \
  --max-num-seqs 256 \
  --enable-prefix-caching
            
白话翻译

启动 vLLM 的 OpenAI 兼容 API 服务器……

加载阿里通义千问 72B 对话模型……

用 4 张 GPU 做张量并行(模型分到 4 张卡上)……

使用每张 GPU 90% 的显存(留 10% 给系统开销)……

最大上下文长度 8192 个 token……

最多同时处理 256 个并发请求……

开启前缀缓存,相同前缀的请求可以复用 KV Cache。

🎯
为什么这些参数很重要?

gpu-memory-utilization 决定你敢用多少显存(设太低浪费资源,设太高可能崩溃)。max-model-len 越大,支持的长文本越长,但显存消耗也越多。max-num-seqs 控制并发上限。这三个参数的平衡是性能调优的核心。

用代码调用 vLLM——和调用 OpenAI 一模一样

vLLM 的 API 完全兼容 OpenAI 的接口,这意味着你可以用任何支持 OpenAI 的 SDK 来调用它:

Python

from openai import OpenAI

client = OpenAI(
  base_url="http://localhost:8000/v1",
  api_key="EMPTY")

response = client.chat.completions.create(
  model="Qwen/Qwen2.5-72B-Instruct",
  messages=[{"role": "user",
    "content": "什么是量子计算?"}])
            
白话翻译

导入 OpenAI 的 Python SDK……

创建客户端,指向本地 vLLM 服务器……

把地址改为 vLLM 的地址(而不是 OpenAI 的云端地址)……

API key 随便填(本地部署不需要认证)。

调用聊天补全接口,和调用 OpenAI 的方式完全一样……

指定模型名称(需要和启动时加载的模型一致)……

传入对话消息列表——这里是用户的一个问题……

(续上行消息内容)

💡
为什么要兼容 OpenAI 接口?

这是一个聪明的工程决策。市面上几乎所有 AI 应用都使用 OpenAI 的 API 格式。vLLM 直接兼容这个格式,意味着你可以把 vLLM 当作 OpenAI 的"平替"——把 base_url 从 api.openai.com 改成 localhost:8000,其他代码一行不用改。

遇到问题怎么办?——常见场景排查

以下是你在使用 vLLM 时最可能遇到的问题,以及如何判断和解决:

🔴

OOM(显存溢出)

症状:服务崩溃,日志显示 CUDA out of memory排查:降低 gpu-memory-utilization(比如从 0.95 降到 0.85),减小 max-model-len,或减少 max-num-seqs。本质上是显存不够用了。

🟡

响应速度变慢

症状:初期很快,随着并发用户增多,延迟急剧上升。排查:/metrics 端点查看 gpu_cache_usage。如果接近 1.0,说明 KV Cache 快满了——考虑加 GPU 或降低并发上限。

🟢

首 token 延迟高

症状:用户发送请求后,第一个字要等很久才出现。排查:Prefill 阶段是瓶颈。开启 Chunked Prefill(分块预填充),让长 prompt 的处理与其他请求混合执行,减少等待。

用指标说话——vLLM 的监控端点

vLLM 内置了 Prometheus 监控指标,你可以通过 /metrics 端点查看系统的实时状态:

gpu_cache_usage_perc KV Cache 使用率——接近 1.0 意味着快满了,需要扩容或降低并发
avg_generation_throughput 平均每秒生成的 token 数——核心性能指标,越高越好
num_requests_running 当前正在 GPU 上处理的请求数——如果经常等于 max-num-seqs,说明瓶颈在并发
num_requests_waiting 排队等待的请求数——如果这个数字持续增长,说明系统处理不过来了
e2e_request_latency_seconds 端到端延迟——从请求进入到完成的总时间,用户体验的直接指标

实战场景测试

你的 vLLM 服务突然出现 CUDA out of memory 错误。以下哪组操作最可能解决问题?

你有一个已经使用 OpenAI API 的应用。迁移到 vLLM 自部署需要改多少代码?

🎉 恭喜!你已经掌握了 vLLM 的核心原理

让我们回顾一下这段旅程中学到的关键知识:

1
vLLM 是什么

高性能大模型推理引擎,让训练好的模型高效、低成本地服务用户。

2
五大核心角色

API 服务器、调度器、模型执行器、KV Cache 管理器、分块预填充——各司其职,协同工作。

3
PagedAttention

借鉴操作系统虚拟内存的分页思想,把显存利用率从 20-40% 提升到接近 100%。

4
两阶段推理 + 连续批处理

Prefill 处理输入,Decode 逐 token 生成。连续批处理让 GPU 始终满载。

5
实战部署

掌握关键启动参数、OpenAI 兼容接口、常见问题排查和性能监控。

🚀
下一步建议

现在你已经理解了 vLLM 的工作原理。试着在自己的项目中部署 vLLM,用 Prometheus 监控指标观察 PagedAttention 和连续批处理的实际效果。当你需要向 AI 编程工具描述需求时,可以精确地说"我要开启前缀缓存"、"需要张量并行度 4"、"gpu-memory-utilization 设为 0.9"——这些精确的词汇会让你的指令效率倍增。