
要使用 vLLM 自托管大语言模型(LLM)推理,您需要三样东西:一张显存足以容纳权重和 KV 缓存的 GPU;一个提供 OpenAI 兼容 API 的 vLLM 服务器;以及围绕它的常规生产环境保障,即身份验证、TLS、防火墙、服务管理器和监控。本指南以 Llama 3.1 系列模型为例,基于已安装 NVIDIA 驱动的 Ubuntu 服务器,逐步讲解每个环节,并提供可按需修改的命令。
为什么要用 vLLM 自托管 LLM 推理
vLLM 是一款开源推理引擎,核心是分页 KV 缓存和连续批处理,这两项技术让一张 GPU 能同时处理大量请求。自己运行 vLLM,而不是调用托管 API,能为您带来四点好处:
- 数据可控。提示词和输出都留在您掌控的机器上,无需评估第三方的数据保留政策。
- 成本固定。按 token 计价的费用随用量增长。而独享 GPU 无论处理一百万个还是十亿个 token,费用都一样,因此您的每 token 成本就是月价除以处理的 token 数,利用率越高,成本越低。
- 延迟由您掌控。没有共享队列,服务器可以部署在靠近您应用的位置,批大小与响应时间之间的权衡也由您自己决定。
- 可定制。可以运行任意开放权重模型、您自己微调的模型和 LoRA 适配器,支持结构化输出,上下文长度上限也可按应用需要设定。
代价同样真实存在。整个技术栈由您运维:升级、安全、容量和故障切换都由您负责。空闲时段也要付费。闭源的前沿模型无法自托管。此外,如果您的用量较低或波动很大,按 token 计费的 API 往往更便宜。
估算 GPU 需求:权重加 KV 缓存
显存决定了您能部署哪些模型。权重占用为参数量 × 每个参数的字节数:Llama 3.1 8B 在 BF16 精度下约 16 GB,Llama 3.1 70B 在 FP8 精度下约 70 GB、BF16 精度下约 140 GB。KV 缓存则是活跃序列中的每个 token 占用 2 × 层数 × KV 头数 × 头维度 × 每个值的字节数:在 BF16 精度下,8B 模型每个 token 约 0.13 MB,70B 模型约 0.33 MB。
举个例子:在一张 141 GB 的 H200 上以 FP8 运行 Llama 3.1 70B,并设置 。vLLM 可使用约 130 GB。扣除约 70 GB 权重和几 GB 激活值之后,约剩 55 GB 可用于缓存:BF16 精度下约可容纳 170,000 个 token,相当于 20 个并发对话,每个都用满 8,192 个 token。FP8 缓存能把这一数字翻倍,达到约 40 个。我们的 LLM 显存需求指南给出了完整方法和更多示例。
安装 vLLM 并启动兼容 OpenAI 的服务器
在虚拟环境中安装 vLLM。它的 wheel 包自带 PyTorch 构建,因此系统只需要一个较新的 NVIDIA 驱动;可以用 检查。另请参阅我们的 PyTorch 与 vLLM 文档。
sudo apt-get update
sudo apt-get install -y python3-venv
python3 -m venv ~/vllm-env
source ~/vllm-env/bin/activate
pip install vllm
Llama 模型在 Hugging Face 上需要申请访问权限:在模型页面接受许可协议,创建访问令牌并将其导出为环境变量。然后生成一个 API 密钥,启动服务器并绑定到 localhost:
export HF_TOKEN=hf_your_token
export VLLM_API_KEY=$(openssl rand -hex 32)
vllm serve meta-llama/Llama-3.1-8B-Instruct \
--host 127.0.0.1 --port 8000 \
--api-key "$VLLM_API_KEY" \
--max-model-len 32768
首次启动时会把权重下载到 Hugging Face 缓存中;如果您的主目录空间较小,请把 HF_HOME 设置为本地 NVMe 上的某个目录。然后测试推理端点:
curl http://127.0.0.1:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $VLLM_API_KEY" \
-d '{
"model": "meta-llama/Llama-3.1-8B-Instruct",
"messages": [
{"role": "user", "content": "Explain the KV cache in one sentence."}
],
"max_tokens": 100
}'
由于 API 遵循 OpenAI 的格式,现有客户端只需修改 base URL 和密钥即可使用:
from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:8000/v1", api_key="YOUR_KEY")
reply = client.chat.completions.create(
model="meta-llama/Llama-3.1-8B-Instruct",
messages=[{"role": "user", "content": "Hello"}],
)
print(reply.choices[0].message.content)
如果您更喜欢 Docker,官方的 镜像接受相同的参数。端口只在 127.0.0.1 上发布;在生产环境中,请固定一个发行版本标签,不要使用 latest:
docker run --gpus all --ipc=host \
-p 127.0.0.1:8000:8000 \
-v ~/.cache/huggingface:/root/.cache/huggingface \
-e HF_TOKEN \
vllm/vllm-openai:latest \
--model meta-llama/Llama-3.1-8B-Instruct \
--api-key "$VLLM_API_KEY"
跨 GPU 的张量并行
当模型无法装入单张 GPU 时, 会把每一层切分到多张 GPU 上。权重和 KV 缓存分摊到各张 GPU,GPU 之间在每一层都要交换激活值,因此 NVLink 在这里很重要。并行度必须能整除模型的注意力头数:Llama 3.1 70B 有 64 个头,因此可以用 2、4 或 8。
在 8× H100 服务器上,您可以运行两个 BF16 精度的 Llama 3.1 70B 副本,每个副本使用 4 张 GPU:
CUDA_VISIBLE_DEVICES=0,1,2,3 vllm serve meta-llama/Llama-3.1-70B-Instruct \
--tensor-parallel-size 4 --host 127.0.0.1 --port 8001
CUDA_VISIBLE_DEVICES=4,5,6,7 vllm serve meta-llama/Llama-3.1-70B-Instruct \
--tensor-parallel-size 4 --host 127.0.0.1 --port 8002
每个副本把 140 GB 权重分摊到 320 GB 显存上,每张 GPU 约 35 GB;在默认显存设置下,每张 GPU 还剩下大致同样多的空间用于缓存。再由反向代理在两个端口之间均衡分配请求。
经验法则:当模型无法装入单张 GPU,或者您需要更低的单请求延迟时,使用张量并行。否则,请在负载均衡器后面每张 GPU 运行一个副本,这样可以完全避免 GPU 间流量。在 L40S 或 RTX PRO 6000 等只有 PCIe 的显卡上,宜优先运行相互独立的副本,或者尝试 ,它的通信量比张量并行少。
显存调优:FP8、前缀缓存与各项上限
以下几个选项决定了能装下多少内容,以及缓存的利用效率:
在加载模型时把 BF16 权重转换为 FP8,在 Hopper、Ada 和 Blackwell GPU 上可将权重显存减半。请确认您所用的 vLLM 版本如何完成这一转换:旧版本会先加载全精度权重,因此转换之前必须装得下 BF16 模型。要在单张 GPU 上运行 70B 模型,请使用已经量化为 FP8 的检查点;vLLM 会根据检查点的配置识别格式。--quantization fp8 把缓存减半,能容纳的 token 数翻倍。采用之前,请先在长上下文任务上检查质量。--kv-cache-dtype fp8 - 前缀缓存会为共同的提示词前缀复用缓存:系统提示词、少样本示例、对话中较早的几轮,以及在多次 RAG 查询中重复出现的文档。新版本默认启用;在旧版本中,需传入
。要从中受益,请把固定不变的内容放在提示词前面,把可变内容放在后面。--enable-prefix-caching 限制每个请求的上下文长度。默认值为模型支持的最大值,Llama 3.1 为 131,072 个 token;如果缓存装不下一个这么长的序列,vLLM 会拒绝启动,因此请把它设为您实际需要的值。--max-model-len 指每张 GPU 的显存中,vLLM 可用于权重、激活值和缓存的比例,默认为 0.9。在独享 GPU 上,可以提高到约 0.95,以获得更多缓存;如果有其他程序共用这张 GPU,则应调低。--gpu-memory-utilization 限制同时运行的序列数,是在高负载下控制延迟上限的简单方法。--max-num-seqs
综合起来,在一张 H200 上部署预先量化好的 70B FP8 检查点,命令如下:
vllm serve /models/llama-3.1-70b-instruct-fp8 \
--served-model-name llama-3.1-70b \
--max-model-len 32768 \
--gpu-memory-utilization 0.92 \
--kv-cache-dtype fp8 \
--host 127.0.0.1 --port 8000
我们关于 FP8 与 FP4 精度的解读文章介绍了量化在质量上的代价。
保护推理端点
开放的推理端点迟早会被别人发现并使用。请分层加固。
绑定到 localhost 并要求提供密钥
上面的示例都把 vLLM 绑定到 127.0.0.1,因此服务器外部的任何东西都无法直接访问它。 或 VLLM_API_KEY 环境变量会要求客户端在 Authorization: Bearer 请求头中发送密钥。该密钥保护的是 /v1 API 路由;不要以为它也覆盖服务器暴露的其他所有路由(例如指标接口),这也是端口应保持私有的又一个原因。如果多个团队或客户共用这个端点,请在前面部署 API 网关,以实现按用户分配密钥和限流。
防火墙
放行 SSH、HTTP 和 HTTPS,拒绝其他所有流量:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
如果只允许已知客户端连接,请把 443 规则替换为每个来源地址各一条规则,例如 sudo ufw allow from 203.0.113.10 to any port 443 proto tcp。有一个陷阱:Docker 发布的端口会绕过 UFW 规则,这正是 Docker 示例只在 127.0.0.1 上发布端口的原因。我们的网络与防火墙指南有更多细节。我们的服务器还为公网 IP 提供 DDoS 防护,它是对身份验证的补充,但不能取而代之。
带 TLS 的反向代理
只要您的 DNS 记录指向这台服务器,且 80 和 443 端口已开放,Caddy 就会自动申请并续期证书。从官方软件包仓库安装 Caddy 后,/etc/caddy/Caddyfile 中的全部配置只有这几行:
llm.example.com {
reverse_proxy 127.0.0.1:8000
}
用 sudo systemctl reload caddy 重新加载配置。流式响应会在生成的同时直接透传。要在两个 vLLM 副本之间做负载均衡,列出两个上游地址即可:reverse_proxy 127.0.0.1:8001 127.0.0.1:8002。如果改用 nginx,请为 API 所在的 location 关闭 proxy_buffering,并调高 proxy_read_timeout,否则流式 token 会一阵一阵地到达,长请求也会超时。
将 vLLM 作为服务运行并进行监控
在生产环境中,请以非特权用户身份在 systemd 下运行 vLLM,使它开机自动启动,并在崩溃后自动重启:
sudo useradd --system --user-group --create-home \
--home-dir /opt/vllm --shell /usr/sbin/nologin vllm
sudo -u vllm python3 -m venv /opt/vllm/venv
sudo -u vllm /opt/vllm/venv/bin/pip install vllm
sudo mkdir -p /etc/vllm
把机密信息保存在 /etc/vllm/vllm.env 中,并设为仅 root 可读(sudo chmod 600 /etc/vllm/vllm.env);systemd 会在降低权限之前读取该文件:
HF_TOKEN=hf_your_token
HF_HOME=/opt/vllm/hf-cache
VLLM_API_KEY=your-long-random-key
然后创建 /etc/systemd/system/vllm.service:
[Unit]
Description=vLLM OpenAI-compatible server
After=network-online.target
Wants=network-online.target
[Service]
User=vllm
Group=vllm
EnvironmentFile=/etc/vllm/vllm.env
ExecStart=/opt/vllm/venv/bin/vllm serve meta-llama/Llama-3.1-8B-Instruct \
--host 127.0.0.1 --port 8000 --max-model-len 32768
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now vllm
journalctl -u vllm -f
这里 vLLM 从 VLLM_API_KEY 读取密钥,因此密钥永远不会出现在命令行中。监控方面,请关注三个层面:
- 健康状态。服务器正常运行时,
GET /health返回 200;请把可用性检测指向它。 - 推理服务指标。
/metrics以 Prometheus 格式暴露各项指标,包括运行中和等待中的请求数(vllm:num_requests_running和vllm:num_requests_waiting)、首 token 延迟、端到端延迟和 KV 缓存使用率。当请求等待长达数分钟、首 token 延迟不断攀升,或者缓存持续接近占满(这会迫使 vLLM 抢占请求)时,就应触发告警。 - GPU 指标。用
快速查看,用 NVIDIA 的 DCGM exporter 向 Prometheus 导出指标。即使在空闲时,显存占用也会显示为约 90%,这在意料之中,因为 vLLM 在启动时就预留了它的份额。请关注温度、功耗,以及内核日志(nvidia-smi journalctl)中的 GPU 错误。-k
关于 GPU 方面的更多内容,请参阅我们的 GPU 监控指南。
选择 GPU
根据您需要的模型、精度和并发量来匹配 GPU。在生成阶段,速度在很大程度上取决于显存带宽,因此它是继容量之后第二个要比较的数字。
| 模型与精度 | 权重 | 推荐配置 | 单卡带宽(厂商标称) | 月价 |
|---|---|---|---|---|
| 8B,BF16 | 约 16 GB | RTX 5090(32 GB)或 L40S(48 GB) | 1.79 TB/s 或 864 GB/s | US$449 或 US$890 |
| 32B,FP8;或 70B,4 位 | RTX PRO 6000(96 GB) | 1.6 TB/s | US$1,390 | |
| 32B,BF16 | 约 64 GB | H100(80 GB) | 3.35 TB/s | US$2,190 |
| 70B,FP8 | 约 70 GB | H200(141 GB) | 4.8 TB/s | US$3,090 |
| 70B,BF16 | 约 140 GB | B200(180 GB)或 B300(288 GB) | 8 TB/s | US$4,590 或 US$5,190 |
| 405B,FP8 | 约 405 GB | 8× H100(640 GB)或 8× H200(1,128 GB) | 3.35 或 4.8 TB/s | US$16,900 或 US$23,900 |
| 约 670 GB | 8× H200 或 8× B200(1,440 GB) | 4.8 或 8 TB/s | US$23,900 或 US$34,900 |
FP8 精度的 70B 模型也可以通过张量并行装入两张 H100,但每月 US$4,380 的费用比一张 H200 更高,还会增加 GPU 间流量。vLLM 还通过 ROCm 支持 AMD GPU,因此每张 GPU 配备 288 GB 显存的 8× MI355X 服务器,也是运行超大模型的一个选择;请先在上面测试您的模型。采用固定月价,自托管推理端点的成本可以提前确定;我们的套餐每月含 20 TB(单卡)或 50 TB(8 卡)出站流量,远超流式文本通常所需。如需更深入的比较,请参阅我们的大语言模型推理最佳 GPU 选型指南或 NVIDIA H200 页面。
常见问题
用 vLLM 自托管 70B 模型需要什么 GPU?
在 FP8 精度下,权重约占 70 GB,因此单张 141 GB 的 H200 就能运行,还能为并发请求留出空间;而 80 GB 的 H100 只能勉强装下。在 BF16 精度下,仅权重就约有 140 GB,因此应选择 B200、B300,或跨多张 GPU 做张量并行。
vLLM 兼容 OpenAI API 吗?
兼容。vLLM 提供 OpenAI 风格的 API 端点,例如 /v1/chat/completions、/v1/completions 和 /v1/models,因此大多数 OpenAI 客户端库只需修改 base URL 和 API 密钥即可使用。
如何保护 vLLM 推理端点?
把 vLLM 绑定到 127.0.0.1,要求提供 API 密钥,并且只通过带 TLS 的反向代理对外提供服务,同时用防火墙只放行 SSH、HTTP 和 HTTPS。在 Docker 中,请在 127.0.0.1 上发布端口,因为 Docker 发布的端口会绕过 UFW。
为什么 vLLM 空闲时,nvidia-smi 显示 GPU 显存几乎占满?
vLLM 在启动时会预留固定比例的显存(默认 90%),并把其中大部分用于 KV 缓存块。这是预期行为,并不是内存泄漏。
应该用张量并行,还是运行多个副本?
当模型无法装入单张 GPU,或者您需要更低的单请求延迟时,使用张量并行,最好在 NVLink 上运行。如果模型单卡就能装下,在负载均衡器后面运行相互独立的副本可以避免 GPU 间流量,通常也能获得更高的总吞吐量。


