8G 显存跑 7B 模型,并发 8 就排队:vLLM 部署 OpenAI 兼容服务实测(2026)

vLLM 是一个高吞吐的推理引擎,核心是 PagedAttention(把 KV cache 按页管理,减少显存碎片)和连续批处理(continuous batching,新请求可以插进正在跑的批次)。 它对外暴露 OpenAI 兼容接口,所以换过去只需要改客户端的 base_url。2026 年 10 月,我在一张 8G 显存的 RTX 4060 上用 Qwen2.5-7B 的 4bit 量化权重起服务,--max-model-len 4096、--gpu-memory-utilization 0.85,启动后显存占满但不 OOM。单请求时它和 Ollama 的体感差别不大;并发到 8 个请求时,Ollama 开始明显排队,vLLM 的总吞吐还在往上走——这就是连续批处理的实际价值。

上面是结论。上一篇写 Ollama + Open WebUI 时,定位是「一个人本地随便聊」;这篇解决的是「几个人同时用同一个模型」。

vLLM 的请求批处理

vLLM 和 Ollama 的本质区别是什么?

结论:Ollama 优化的是「装得上、跑得动、好切换模型」,vLLM 优化的是「单位时间服务更多 token」——前者偏体验,后者偏吞吐。

维度 Ollama vLLM
目标场景 单机自用、快速试模型 多人共用、API 服务
调度方式 请求排队,逐批处理 连续批处理,动态插批
显存管理 整块分配 PagedAttention 分页
模型格式 GGUF 为主 safetensors / AWQ / GPTQ
OpenAI 兼容 有 /v1 端点 原生支持,实现更完整
装起来的难度 一条命令 要处理 CUDA、依赖、显存参数
多卡 支持有限 --tensor-parallel-size 原生

判断标准:如果同时用的人超过两个,或者你要给一个应用当后端,vLLM 值得折腾;如果只是自己写代码时补全、偶尔问两句,Ollama 更省事。

我两个都留着:Ollama 跑在 3060 那台机器上做日常实验,vLLM 跑在 4060 上给内部工具当接口。

部署五步

第一步:装之前先算清楚显存

结论:7B 模型 4bit 量化权重约占 4.5G,剩下的显存才是 KV cache 的地盘——8G 卡能跑,但没有富余。

先做个粗算,避免装完才发现放不下:

项目 7B / 4bit 说明
权重 ~4.5 GB 4bit 量化后约 0.6GB/1B 参数
激活与框架开销 ~0.8 GB CUDA context、临时张量
KV cache 可用 ~1.5–2.5 GB 取决于 gpu-memory-utilization
上下文长度 4096 起 8192 需要更大 KV 预算

KV cache 的大小和「层数 × 头数 × 头维度 × 序列长度 × 并发数」成正比。它不是一个固定值,而是随并发和上下文长度线性增长。 这就是为什么「明明权重才 4.5G,8G 卡却报显存不足」——吃显存的是 KV cache。

先确认显卡和驱动:

$ nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv
name, memory.total [MiB], driver_version
NVIDIA GeForce RTX 4060, 8188 MiB, 566.36
$ nvcc --version | tail -2

vLLM 对 CUDA 版本有要求,装之前对一眼官方 安装文档 里标注的对应关系,别装到一半才发现不匹配。

步骤 1:核对显存与驱动

第二步:安装与下载权重

结论:用独立虚拟环境装,权重走国内镜像下——这两件事能省掉 80% 的安装时间。

$ python -m venv /opt/vllm-env
$ source /opt/vllm-env/bin/activate
$ pip install --upgrade pip
$ pip install vllm==0.6.3

版本号要写死。vLLM 迭代很快,参数名和默认值在不同版本之间有变化,pip install vllm 拿到最新版之后照着旧教程配参数会对不上。

下载模型(以 Qwen2.5-7B-Instruct 的 AWQ 版本为例):

$ export HF_ENDPOINT=https://hf-mirror.com
$ pip install huggingface_hub
$ huggingface-cli download Qwen/Qwen2.5-7B-Instruct-AWQ \
    --local-dir /opt/models/qwen2.5-7b-awq

HF_ENDPOINT 这一行很关键。不设的话走 huggingface.co,国内经常卡在几百 KB/s 或者直接超时。镜像站是社区维护的,速度稳定在几十 MB/s。

下载完检查目录结构:

$ ls -lh /opt/models/qwen2.5-7b-awq
config.json  generation_config.json  model-00001-of-00002.safetensors  tokenizer.json ...

config.json 里的 quantization_config 段会告诉 vLLM 这是 AWQ 权重,不用手动传 --quantization。

步骤 2:安装与下载

第三步:起服务,参数怎么给

结论:三个参数决定成败——--max-model-len(上下文长度)、--gpu-memory-utilization(显存占比)、--max-num-seqs(最大并发)。8G 卡上保守取值。

$ source /opt/vllm-env/bin/activate
$ vllm serve /opt/models/qwen2.5-7b-awq \
    --served-model-name qwen2.5-7b \
    --host 0.0.0.0 \
    --port 8000 \
    --max-model-len 4096 \
    --gpu-memory-utilization 0.85 \
    --max-num-seqs 8 \
    --dtype auto

逐个说:

  • --max-model-len 4096:单次请求的最大上下文。这个值直接决定 KV cache 的单请求占用,设 32768 在 8G 卡上必然起不来。
  • --gpu-memory-utilization 0.85:vLLM 允许占用的显存比例。0.85 是给系统和显示输出留余量;设 0.95 在带桌面的机器上容易崩。
  • --max-num-seqs 8:同时处理的请求数上限。设小了并发上不去,设大了 KV cache 不够会报错。
  • --dtype auto:让 vLLM 自己判断,AWQ 权重会走对应的 kernel。

启动日志里会打印关键信息,这三行必须看:

INFO: Maximum concurrency for 4096 tokens per request: 5.83x
INFO: KV cache memory: 1.72 GiB
INFO: GPU blocks: 262, CPU blocks: 0

Maximum concurrency 是这套配置能同时服务多少个「满 4096 token」的请求。5.83x 意味着理论上能同时跑 5 个长请求,短请求能更多。这个数字比你猜的准。

步骤 3:启动服务

第四步:用 OpenAI SDK 直接连

结论:vLLM 的 /v1/chat/completions 和 OpenAI 的协议一致,改 base_url 就能跑,连 api_key 都只是占位。

from openai import OpenAI

client = OpenAI(base_url="http://127.0.0.1:8000/v1", api_key="not-needed")

resp = client.chat.completions.create(
    model="qwen2.5-7b",
    messages=[{"role": "user", "content": "用三句话解释 PagedAttention"}],
    temperature=0.7,
    max_tokens=256,
)
print(resp.choices[0].message.content)
print(resp.usage)

api_key 是必填参数但 vLLM 默认不校验,随便填一个非空字符串即可。如果服务暴露在公网,必须加 --api-key 你的密钥,否则任何人都能白嫖你的卡。

服务端指定了 --api-key 之后,客户端改用:

client = OpenAI(base_url="http://你的域名/v1", api_key="你的密钥")

流式也一样,stream=True 直接可用,不用改别的东西:

$ curl -s http://127.0.0.1:8000/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{"model":"qwen2.5-7b","messages":[{"role":"user","content":"你好"}],"stream":true}'

兼容端点的完整说明在 vLLM · OpenAI-Compatible Server,包括 /v1/models、/v1/embeddings、工具调用等。

步骤 4:客户端接入

第五步:并发到底差多少

结论:单请求没差别,并发上来差距明显——因为 Ollama 的请求是排队的,vLLM 是插批的。

我用同一份提示词、同一个模型规模做了对比,观察到的现象是:

场景 Ollama vLLM(8G / 7B AWQ)
1 个请求 体感相当 体感相当
4 个并发 明显的排队感,后发的等前面的 基本同时出字
8 个并发 响应时间接近 4 倍 响应时间约 1.5–2 倍
显存表现 稳定,占用低 接近打满,靠分页调度

具体毫秒数会随提示词长度、生成长度、量化方式大幅波动,我不打算给一个「vLLM 快 X 倍」的数字——这个数字在不同硬件和不同请求形态下毫无可比性。可靠的结论是定性的:连续批处理在并发场景下的优势随并发数增长而放大,单请求时两者没有本质区别。

如果你的使用场景是「一个人用」,那 vLLM 的收益接近零,还多了安装成本。这也是我一直建议先用 Ollama 的原因。

步骤 5:并发压测

踩过的三个坑

结论:三个坑全部和显存有关——上下文设太大、并发设太大、gpu-memory-utilization 设太高。

坑一:No available memory for the cache blocks。 这是最典型的报错,意思是权重加载完之后没有空间给 KV cache 了。三种改法按优先级:降 --max-model-len、降 --max-num-seqs、提 --gpu-memory-utilization(如果还有余量)。我一开始把 max-model-len 设成 16384,直接起不来,降到 4096 才过。

坑二:显存打满后系统卡死。 在带桌面的 Windows 上尤其明显——vLLM 按 gpu-memory-utilization 抢显存,桌面环境也需要显存合成画面,两边打架的结果是整机卡住。8G 卡带桌面时把比例降到 0.75 更稳;纯命令行环境可以到 0.9。

坑三:以为 AWQ 权重能直接喂给 Ollama。 不能。Ollama 要 GGUF,vLLM 要 safetensors/AWQ/GPTQ。两套格式要各自准备一份,别指望一个权重通吃。我最初的目录里混着两种格式,vllm serve 报了一堆看不懂的 tensor 名字错误,查了很久才发现指错了目录。

什么时候该换回 Ollama

结论:单人使用、频繁切模型、机器显存小于 8G,这三条命中任何一条,Ollama 都是更划算的选择。

vLLM 的真实成本不是安装,是调参——每换一个模型、改一次上下文长度,都要重新算一遍 KV cache 预算。这套东西适合「模型固定、长期对外服务」的场景。如果你的用法是「今天试试 Qwen、明天试试 Llama」,Ollama 的 ollama run 是无敌的。

还有一个现实问题:8G 显存跑 7B 4bit 已经是舒适区的边缘。想上 14B,要么换 12G 以上的卡,要么接受更短的上下文和更低的并发。

常见问题

Q:vLLM 支持 CPU 推理吗?
A:有 CPU 后端但吞吐很低,只适合验证流程。真正的 CPU 推理用 llama.cpp 更合适。

Q:能不能多卡?
A:支持,--tensor-parallel-size 2 用两张卡切分模型。要求卡型号一致、显存接近,否则会被最小的那张拖住。

Q:模型怎么换成别的?
A:把 vllm serve 后面的路径换掉,--served-model-name 一起改。上下文和并发参数要按新模型的规模重新算。

Q:能不能接 new-api 统一管理?
A:能,把 vLLM 当成一个 OpenAI 兼容的上游填进 new-api,就能和云端 API 混在一起按模型名路由。

Q:服务重启后模型要重新加载多久?
A:7B 从磁盘加载约 10–30 秒,取决于磁盘速度。放 NVMe 上会明显更快,这也是我把它装在系统盘而不是机械盘的原因。

相关阅读

上一篇 备份脚本在 cron 里跑了三年,换机器后一次没成功:systemd timer 迁移实录(2026)