用 vLLM 在 VPS 上部署 OpenAI 兼容推理 API:从零到生产(2026)
2026-08-16 · DevCraft Studio
手把手教你用 vLLM 在 GPU VPS 上拉起 OpenAI 兼容的 /v1/chat/completions 端点:Docker 部署、显存估算、张量并行、AWQ/GPTQ/FP8 量化、多 LoRA、网关鉴权与冷启动处理。
延伸阅读
更多相关攻略推荐:【API 中转 02】ChatGPT/Claude API 中转 V、炒币/外汇 EA 机器人用什么 VPS?低延迟到交易所的选机指南、量化/EA 交易要低延迟:跑外汇机器人该选哪台 VPS?就近机房实测、2026 多语言/多区域 SEO 技术栈:hreflang+CDN 、Tailscale 连上了却卡成狗?自建 DERP/ZeroTier。
为什么是 vLLM:不是又一个推理框架
到了 2026 年,如果你要在自己的服务器上把开源大模型当成 API 用,vLLM 基本是绕不开的选择。它和裸跑 transformers 的最大区别,在于两个工程化设计:PagedAttention 和连续批处理(continuous batching)。
PagedAttention 把 KV 缓存像操作系统管理内存一样分页,不再为每条请求预留一整块连续显存,显存碎片问题基本消失。连续批处理则让新进来的请求可以随时插进正在解码的批次里,GPU 几乎不再空转。这两点叠加,吞吐比 naive 方式高几个量级,这也是为什么大量自建推理服务都站在 vLLM 肩膀上。
对开发者最友好的地方是:vLLM 自带一套 OpenAI 兼容端点,包括 /v1/chat/completions、/v1/completions、/v1/embeddings。你原来给 OpenAI 写的 SDK 代码,只要把 base_url 指到自己的服务器,其余一行都不用改。换句话说,原本调 OpenAI 付费接口的产品后端,可以无缝切到自建模型。
先算账:显存怎么估(VRAM 数学)
实测里最容易踩的坑,不是命令写错,而是机器一启动就 OOM。根因是很多人只算了权重大小,忘了 KV 缓存和并发开销。给你一个能心算的公式:
第一步,权重占用 ≈ 参数量 × 每参数字节数。fp16/bf16 是 2 字节,fp8/int8 是 1 字节,int4 是 0.5 字节。第二步,实际占用还要再乘 1.3 到 2.0 的系数,这部分就是 KV 缓存、显存碎片和并发请求的开销。长上下文、高并发场景取上限。
举个具体例子,Qwen3-32B(约 328 亿参数,稠密模型,Apache-2.0):
- fp16:32.8B × 2 ≈ 64GB 权重,加上 KV 缓存就超过单张 80GB 卡,必须双卡张量并行,或者直接上量化。
- fp8:32.8B × 1 ≈ 32GB 权重,单张 H100(80GB)轻松装下,还能留不少空间给 KV 缓存。
常用的显存基准记住三个数:H100 是 80GB,H200 是 141GB,B200 是 192GB。配合上面的乘法,你基本上能秒算出任意模型该租几张卡。对独立开发者来说,约 30B 的稠密模型是甜点区,单卡就能跑,不用上集群。
一行 Docker 拉起 /v1/chat/completions
官方镜像 vllm/vllm-openai 的入口命令就是 vllm serve,所以镜像名后面的所有参数都是 serve 的参数。最朴素的起法:
docker run -d --gpus all --ipc=host -p 8000:8000 \
-v $HOME/.cache/huggingface:/root/.cache/huggingface \
vllm/vllm-openai:latest \
--model Qwen/Qwen3-8B \
--tensor-parallel-size 1 \
--gpu-memory-utilization 0.9 \
--max-model-len 8192 \
--api-key $VLLM_API_KEY
其中 --ipc=host 很重要,它让容器共享宿主机内存,避免多进程通信时共享内存不足。--gpu-memory-utilization 默认就是 0.9,留给 CUDA 内核一点余量,别一上来就拉到 0.99。
启动后用 docker logs -f 看加载进度,确认出现 serving on http://0.0.0.0:8000 之类的日志再测。最小验证:
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $VLLM_API_KEY" \
-d '{"model":"Qwen/Qwen3-8B","messages":[{"role":"user","content":"你好,介绍一下你自己"}],"max_tokens":200}'
如果能正常返回 content 字段,说明端点已经跑通。在 Vultr 这类提供 GPU 实例的厂商开一台带 H100 的机器,按上面命令几分钟就能拉起一个可对话的 API。
量化:AWQ / GPTQ / FP8 到底怎么选
显存不够是常态,量化是首选解法。先说一个重要前提:vLLM 不会在运行时从 bf16 现场量化,你必须准备一份已经量化好的检查点。社区里 TheBloke 等账号提供大量现成量化权重,Qwen 官方也发布了 FP8 检查点。
- AWQ(激活感知权重量化):它会根据激活幅度找出对量化最敏感的那部分通道,保留更高精度,所以 4-bit 下质量损失比朴素四舍五入小。Ampere 及以上架构可以用 awq_marlin 内核进一步加速。
- GPTQ:用二阶 Hessian 信息逐层最小化量化误差,社区权重极多,支持度广。质量在同样比特数下和 AWQ 接近,差别主要看你的具体任务。
- FP8:H100、H200、Blackwell 有原生 FP8 张量核,吞吐最高,而且 Qwen 官方直接提供 FP8 检查点,开箱即用。注意 A100、A10G 这类 Ampere 卡没有原生 FP8,千万别在它们上面强行用 fp8,否则要么报错要么退回慢路径。
起一个 FP8 模型:
docker run -d --gpus all --ipc=host -p 8000:8000 \
vllm/vllm-openai:latest \
--model Qwen/Qwen3-32B-FP8 \
--quantization fp8 \
--tensor-parallel-size 1 \
--max-model-len 16384
如果只能用 4-bit,可以选 AWQ 检查点:
vllm serve Qwen/Qwen3-8B-AWQ \
--quantization awq \
--tensor-parallel-size 1 \
--gpu-memory-utilization 0.95
多卡与张量并行
模型装不进单卡时,用 --tensor-parallel-size N 把权重切到 N 张卡上。比如 Qwen3-32B 的 fp16 权重约 64GB,单张 80GB 卡装了权重就没空间给 KV 缓存,稳妥做法是双卡:
vllm serve Qwen/Qwen3-32B \
--tensor-parallel-size 2 \
--gpu-memory-utilization 0.9 \
--max-model-len 16384
卡间互联带宽直接影响并行效率,NVLink 全互联的机器明显更顺。Vultr 的 H100 实例多卡之间带宽充足,很适合这类张量并行场景。再大的模型可以叠加 --pipeline-parallel-size 做流水线并行,跨机则靠 Ray 编排。
一个模型服务多个微调版:多 LoRA
如果你的产品需要同时支持多个微调版本(比如不同行业、不同风格的对话),给每个版本都加载一份完整模型太浪费。vLLM 支持动态加载 LoRA 适配器:启动时开启 --enable-lora,用 --lora-modules 把名字映射到路径,运行时按名字调用,显存只占一份 LoRA 增量。
vllm serve Qwen/Qwen3-8B \
--enable-lora \
--max-loras 4 \
--max-lora-rank 64 \
--lora-modules sql-lora=/models/sql-lora code-lora=/models/code-lora
调用时,请求里的 model 字段直接填 LoRA 名字(例如 sql-lora)即可,无需重启服务。这对做个性化模型服务的团队非常省显存、好管理。
网关鉴权、限速与兜底
vLLM 自带的 --api-key 只能配一个共享密钥,单人开发够用,但团队一多就乱了:谁在调、花了多少、崩了怎么办都说不清。生产环境建议在前面挂一个网关,比如 LiteLLM。
LiteLLM 是一个开源代理,能在 vLLM 前面提供每用户虚拟密钥、预算配额、请求路由,以及最关键的兜底能力——当本地 GPU 节点冷启动还没起来时,自动把请求转发到商业 API,等对端恢复再切回本地,对客户端完全透明。
model_list:
- model_name: local-qwen
litellm_params:
model: openai/Qwen/Qwen3-8B
api_base: http://vllm:8000/v1
api_key: $VLLM_API_KEY
- model_name: fallback-gpt
litellm_params:
model: gpt-4o
api_key: $OPENAI_API_KEY
router_settings:
fallbacks:
- {"local-qwen": ["fallback-gpt"]}
启动网关:litellm --config litellm_config.yaml --port 4000,客户端统一指向 http://网关:4000/v1。如果你不想引入 LiteLLM,也可以用十几行 FastAPI 反向代理做 key 校验和限速,但 LiteLLM 开箱即用更省心。
冷启动与运维:把坑提前填好
多 GB 模型加载进显存需要时间,第一个请求往往会卡很久,甚至因为平台健康检查超时而被判死、被重启。几个实测有效的做法:
- 健康检查一定打 /health 这个 vLLM 自带端点,并且给平台 health check 一个足够长的启动宽限期(比如 180 秒起步,大模型更要加)。
- 延迟敏感的服务不要缩容到零,保持实例常热;如果一定要省成本,就用上面说的 LiteLLM 兜底挡住冷启动期间的请求。
- 监控看 /metrics:gpu_cache_usage_perc 是 KV 缓存占用,num_requests_waiting 是排队数,time_to_first_token 是首 token 延迟。KV 缓存满了就降 --max-model-len 或调高 --gpu-memory-utilization。
把 API 暴露到公网时,建议走一层反向代理加 HTTPS,别直接把 8000 端口裸奔出去。对于面向国内用户的场景,DMIT 这类高端线路机房带宽足、延迟低,很适合把自建推理 API 暴露给国内调用方,配合网关鉴权一起用更稳。
实测:把 OpenAI SDK 指过来
客户端改造量几乎为零,只换 base_url。下面这段 Python 用官方 openai 库直接打你自己的端点:
from openai import OpenAI
client = OpenAI(
base_url="http://你的服务器IP:8000/v1",
api_key="你的VLLM_API_KEY",
)
resp = client.chat.completions.create(
model="Qwen/Qwen3-8B",
messages=[{"role": "user", "content": "用一句话解释 PagedAttention"}],
max_tokens=200,
temperature=0.7,
)
print(resp.choices[0].message.content)
只要模型名和你在 vLLM 里 --served-model-name 或 --model 指定的对应上,原来所有 OpenAI 的工具调用、流式输出、JSON 模式都能照常工作。前端工具如 OpenWebUI、LiteLLM、Continue、Cline 也都天然兼容这个端点。
前缀缓存与压测:上线前先量一遍
很多团队直接裸上生产,结果第一个流量高峰就排队超时。两个上线前必做动作。第一,开启 --enable-prefix-caching(vLLM v1 默认开,但老版本要显式加),它能复用相同系统提示前缀的 KV 块,对成百上千请求共享同一条 system prompt 的场景,首 token 延迟能降三成以上。第二,用 vLLM 自带的压测脚本量一遍真实吞吐:
python benchmarks/benchmark_serving.py \
--backend vllm \
--model Qwen/Qwen3-8B \
--dataset-name sharegpt \
--num-prompts 1000 \
--request-rate 10
重点看两个数字:TTFT 的 p95(首 token 延迟分位)和聚合 tok/s(吞吐)。经验上并发越高聚合吞吐越大,但尾部延迟也会变差。如果 p95 超过 500ms 还上不去并发,先调 --max-num-seqs 和 --max-num-batched-tokens,再考虑加卡。把这层摸清,上线后才不会被峰值打懵。