一块 24G 显存的显卡,想把 32B 的开源大模型跑成稳定服务,大多数人的第一反应是「显存不够」。其实缺的不只是显存,还有把显存用对的能力。这篇文章讲清楚两件事:vLLM 凭什么成为大模型厂商的默认推理引擎,以及你今天怎么在自己的机器上把它跑起来。
01 生成一个字,到底贵在哪
大模型回答问题时是一个 token 一个 token 往外蹦的(token 可以理解成「半个到一个词」)。每生成一个新 token,都要把前面所有内容完整过一遍神经网络。你问 1000 字、它答 2000 字,就是 2000 次前向计算,每次都带着前面越滚越长的上下文一起算。
工程师的解法叫 KV Cache:把已生成内容在每层网络里的中间计算结果(Key 和 Value 矩阵)存下来,下一个 token 只算增量。就像记账,核对过的账目不再重复核,只记新的一笔——计算省下来了,代价是显存。
KV Cache 的大小跟着「上下文长度 × 并发请求数」线性增长。以 7B 模型为例,一个 8K 上下文的请求大约要占几百 MB 到 1G 显存(具体看模型结构),32 个并发加起来就是几十 G——比模型权重本身还大。推理服务的并发能力,很大程度上取决于显存里能同时塞下多少个请求的 KV Cache。
02 浪费发生在分配方式上
早期推理框架的分配方式很「豪横」:请求一来,按模型支持的最大上下文长度预留一整块连续显存。模型支持 32K,哪怕你只问了三个字,也按 32K 的最大可能留位子。
结果三种浪费同时发生:
| 浪费类型 | 怎么发生的 | 后果 |
|---|---|---|
| 预留浪费 | 按「最大可能」预留,实际只用了零头 | 显存空转 |
| 碎片浪费 | 显存被切成不连续的块 | 有显存却凑不出连续大块 |
| 保守浪费 | 怕 OOM 只敢少接请求 | 吞吐上不去 |
vLLM 的 PagedAttention 借了操作系统分页管理的思路。操作系统管内存不是按「每个程序可能要多少」预留,而是切成固定大小的小页,用到哪指到哪。PagedAttention 把 KV Cache 同样切成固定大小的块(block),每块存固定数量 token 的 KV,用一张块表做逻辑地址到物理位置的映射——请求要的块不连续也无所谓,按表查就行。
效果用数字感受:vLLM 论文的测试里,吞吐比当时主流推理方案高 2-4 倍,比 HuggingFace Transformers 原生实现最高能到 24 倍。同样的卡,能同时服务的人多了几倍。
顺带回答标题里的问题:厂商选 vLLM 不只因为省显存。它的模型支持面在开源引擎里数一数二,OpenAI 兼容 API 让业务切换几乎零成本,2026 年 10 月发布的 v0.32.0 还在继续压 CPU 开销(Model Runner V2)和优化大规模部署(多 API server 并行)。

03 分页顺手送的前缀缓存
分页还有个红利:KV 复用。两个请求如果开头一样——同一个 system prompt、同一段 RAG 检索结果、多轮对话的历史——开头那段 KV Cache 完全可以共用一份物理块。后到的请求直接「接着算」,不用把开头重新算一遍。
多轮对话是最大受益场景:聊到第 5 轮时,前 4 轮的 KV 已经在显存里,vLLM 只对新增部分做计算,响应速度能快一截。这个能力叫 Automatic Prefix Caching,vLLM 默认开启,不用配置。
04 亲手跑一个
先装(建议 Python 3.10+,Linux/CUDA 环境最顺;首次启动会自动从 HuggingFace 下载模型,国内可设 HF_ENDPOINT=https://hf-mirror.com):
pip install vllm
vllm serve 后面跟的是 HuggingFace Hub 的模型 ID,首次启动会自动下载,缓存在 HF_HOME 指定的目录(默认 ~/.cache/huggingface/hub)。三种常见玩法:
# 1. 国内加速:设好镜像端点,照常启动
export HF_ENDPOINT=https://hf-mirror.com
# 2. 先手动下载好,再启动服务
huggingface-cli download Qwen/Qwen3-8B
# 3. 换 ModelScope(阿里源):加一个环境变量
export VLLM_USE_MODELSCOPE=1
已经下好本地权重的话,--model 直接给路径,不走在线下载:
vllm serve /data/models/Qwen3-8B \
--served-model-name Qwen/Qwen3-8B
--served-model-name 让客户端调用时仍然用原来的模型 ID,业务代码不用跟着改。
起服务,一行命令:
vllm serve Qwen/Qwen3-8B \
--gpu-memory-utilization 0.85 \
--max-model-len 8192
三个最常调的参数:
| 参数 | 作用 | 什么时候动它 |
|---|---|---|
--gpu-memory-utilization | vLLM 占用显存的比例 | OOM 就调低到 0.7;显存富余可拉高 |
--max-model-len | 最大上下文长度 | 超过显卡能力会启动失败,调小即可 |
--kv-cache-dtype | KV Cache 精度 | v0.32.0 起最低支持 NVFP4(4bit),显存紧张时用它换容量 |
启动后服务跑在 8000 端口,暴露的是 OpenAI 兼容 API。用官方 SDK 就能调:
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")
resp = client.chat.completions.create(
model="Qwen/Qwen3-8B",
messages=[
{"role": "system", "content": "你是一个严谨的中文助手"},
{"role": "user", "content": "用一句话解释 KV Cache"},
],
stream=True,
)
for chunk in resp:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
到这里,你已经拥有了一个和 OpenAI 接口完全一致的本地大模型服务——业务代码里只要换掉 base_url,就能把云上模型切换成自托管。
05 什么时候不值得用
vLLM 不是装上就快,三种情况别硬上:
- 显存本来就放不下模型:vLLM 优化的是「怎么用显存」,不能变出显存。权重都装不下就先做量化(
--quantization支持 GPTQ/AWQ/FP8 等)或换小模型,再谈优化。 - 单人本地玩:Ollama 一行命令更省事。vLLM 的收益主要来自高并发,一个人对着模型提问,分页管理基本帮不上忙。
- 只追首 token 延迟:vLLM 强在「同时服务更多人」(吞吐),单请求的首 token 延迟不一定比小框架低,对延迟敏感的单路场景要先测再说。
一句话总结:vLLM 的核心是把显存从「按最大预留」改成「按需分页」,让同一块卡同时塞下更多请求。
如果这篇帮你搞懂了分页思想,关注大鱼AI研究室,后面我会继续拆推理工程里的其他门道。
你现在跑推理,卡住的是显存不够还是并发上不去?评论区聊聊你的场景和配置。