站长今天直接上干货。很多团队在部署大模型时,遇到的核心痛点无非是三类:吞吐量上不去、显存爆炸、API响应延迟不稳定。vLLM 之所以成为生产环境的首选推理加速框架,是因为它引入了 PagedAttention 机制,把显存利用率提升了数倍,并且原生支持 Continuous Batching(连续批处理)和量化推理。这篇实战方案,站长会从架构流转、部署细节、完整API代码到高并发调优,一步步带你落地一个能扛住生产流量的 vLLM 服务。
一、架构流转说明:vLLM 在生产环境中的位置与数据流
⚡ 【免费资源】DeepSeek/Ollama 部署排错手册 + 全套 AI 提示词资料包
站长已将大模型部署排错指南、常用环境配置文件及 AI 提效指令库整合分享至夸克网盘,可极速免费转存:
先看一张清晰的架构流转图(文字描述,站长画图水平有限,但逻辑必须清晰):
- 客户端层:你的业务后端(Python/Java/Go)通过 HTTP/WebSocket 发送请求。
- 网关/负载均衡层:Nginx 或云负载均衡,负责将请求分发到多个 vLLM 实例(如果你做了多副本)。
- vLLM 服务层:每个 vLLM 实例内部包含:
– FastAPI 服务器:vLLM 自带 OpenAI 兼容的 API 服务器,监听 8000 端口。
– 调度器:负责 Continuous Batching,动态拼接请求批次,最大化 GPU 利用率。
– PagedAttention 执行器:管理 KV Cache 的分页,避免显存碎片化。
– 模型并行:如果单卡放不下,通过张量并行(Tensor Parallelism)在多卡间切分模型。 - 存储/向量库(可选):如果做 RAG,vLLM 只负责生成部分,检索逻辑在业务层。
关键数据流说明:当请求到达 vLLM,它不会立即执行,而是进入等待队列。调度器基于当前 GPU 显存余量,决定哪些请求可以拼进同一个 step(前向传播)。这就是 Continuous Batching 的核心——不是等一个请求完全结束才处理下一个,而是动态插入和退出。这种机制让吞吐量(tokens/s)成倍增长,但也意味着你需要关注 max_num_seqs 和 max_num_batched_tokens 的配置,否则会 OOM。
二、vLLM 部署的实战步骤(生产级配置)
2.1 环境准备与安装
站长推荐使用 Docker 方式,避免污染宿主机环境。但如果你要裸机部署,请确保 CUDA 版本 ≥ 11.8,GPU 驱动 ≥ 520。以下为 Docker 部署命令(生产环境建议锁定版本):
# 拉取 vLLM 官方镜像(注意 tag 对应 CUDA 版本)
docker pull vllm/vllm-openai:latest
# 启动容器,挂载模型目录,暴露 8000 端口
docker run --runtime nvidia --gpus all \
-v /home/user/models:/models \
-p 8000:8000 \
--ipc=host \
--env "HUGGING_FACE_HUB_TOKEN=你的token" \
vllm/vllm-openai:latest \
--model /models/your-model \
--served-model-name your-model-name \
--port 8000 \
--max-model-len 8192 \
--gpu-memory-utilization 0.90 \
--trust-remote-code
站长强调几个参数:
– --gpu-memory-utilization:默认 0.9,表示预留 10% 显存给 CUDA context 和碎片。如果模型很小,可以调到 0.95,但风险自担。
– --max-model-len:输入+输出的最大长度。如果设太大,KV Cache 会占用大量显存,导致并发数下降。
– --trust-remote-code:某些模型(如 Llama-3 变体)需要读取自定义代码,生产环境请谨慎,建议先审查代码。
2.2 模型量化与显存优化
如果你的 GPU 显存不够,站长强烈建议用 AWQ 或 GPTQ 量化。vLLM 原生支持 AWQ。启动命令加一行:
--quantization awq \
--quantization-param-path /path/to/awq_config.json
另外,--enforce-eager 参数可以关闭 CUDA Graph,减少显存占用,但会牺牲一点性能。站长建议:生产环境保持默认(开启 CUDA Graph),因为性能提升明显。
三、完整 API 调用代码(OpenAI 兼容接口)
💡 关联延伸阅读:如果你在配置过程中遇到相关报错,请参阅站长之前的解决教程:大模型推理加速框架vllm部署的实战方案怎么用?3分钟极速上手,小白也能跑起70B大模型
vLLM 启动后,默认提供 /v1/chat/completions 和 /v1/completions 接口,完全兼容 OpenAI 协议。站长给你一套生产可用的 Python 客户端代码,包含重试、超时和流式输出。
3.1 非流式调用(适用于短文本生成)
import requests
import json
import time
def vllm_chat_completion(
api_url: str = "http://your-vllm-host:8000/v1/chat/completions",
model: str = "your-model-name",
messages: list = None,
temperature: float = 0.7,
max_tokens: int = 512,
top_p: float = 0.95,
timeout: int = 60,
max_retries: int = 3,
):
"""
非流式调用 vLLM 的 Chat Completion API
"""
if messages is None:
messages = [{"role": "user", "content": "你好"}]
payload = {
"model": model,
"messages": messages,
"temperature": temperature,
"max_tokens": max_tokens,
"top_p": top_p,
"stream": False, # 非流式
}
headers = {"Content-Type": "application/json"}
for attempt in range(max_retries):
try:
resp = requests.post(api_url, json=payload, headers=headers, timeout=timeout)
resp.raise_for_status()
result = resp.json()
# 提取生成内容
content = result["choices"][0]["message"]["content"]
usage = result.get("usage", {})
return {
"content": content,
"prompt_tokens": usage.get("prompt_tokens"),
"completion_tokens": usage.get("completion_tokens"),
"total_tokens": usage.get("total_tokens"),
"latency_ms": result.get("latency_ms", None),
}
except requests.exceptions.Timeout:
print(f"[Retry {attempt+1}] Timeout, retrying...")
time.sleep(2 ** attempt) # 指数退避
except requests.exceptions.HTTPError as e:
if resp.status_code == 429: # 限流
print(f"[Retry {attempt+1}] Rate limited, retrying...")
time.sleep(5)
else:
raise e
except Exception as e:
print(f"Unexpected error: {e}")
raise
raise RuntimeError("Max retries exceeded")
# 使用示例
if __name__ == "__main__":
response = vllm_chat_completion(
messages=[{"role": "user", "content": "用一句话解释量子纠缠"}]
)
print(response["content"])
print(f"Token 使用: {response['total_tokens']}")
3.2 流式调用(适用于长文本生成,提升用户体验)
import requests
import json
def vllm_stream_chat(
api_url: str = "http://your-vllm-host:8000/v1/chat/completions",
model: str = "your-model-name",
messages: list = None,
max_tokens: int = 1024,
temperature: float = 0.8,
):
"""
流式调用 vLLM,逐 token 返回
"""
payload = {
"model": model,
"messages": messages,
"max_tokens": max_tokens,
"temperature": temperature,
"stream": True, # 关键:开启流式
}
headers = {"Content-Type": "application/json"}
with requests.post(api_url, json=payload, headers=headers, stream=True, timeout=120) as resp:
resp.raise_for_status()
# 解析 SSE (Server-Sent Events) 格式
for line in resp.iter_lines():
if line:
line = line.decode("utf-8")
if line.startswith("data: "):
data_str = line[6:]
if data_str == "[DONE]":
break
try:
chunk = json.loads(data_str)
delta = chunk["choices"][0]["delta"]
if "content" in delta:
yield delta["content"]
elif "role" in delta:
continue
except json.JSONDecodeError:
print(f"Failed to parse: {data_str}")
# 使用示例
if __name__ == "__main__":
msgs = [{"role": "user", "content": "写一篇500字的短文介绍人工智能"}]
for token in vllm_stream_chat(messages=msgs):
print(token, end="", flush=True)
3.3 异步高并发调用(生产必备)
如果你的业务需要大量并发请求,站长推荐使用 httpx.AsyncClient 配合 asyncio,避免线程阻塞。
import asyncio
import httpx
async def async_vllm_call(
client: httpx.AsyncClient,
api_url: str,
model: str,
prompt: str,
semaphore: asyncio.Semaphore,
):
"""
信号量控制并发数,避免打爆 vLLM
"""
async with semaphore:
payload = {
"model": model,
"messages": [{"role": "user", "content": prompt}],
"max_tokens": 256,
"temperature": 0.6,
}
try:
resp = await client.post(api_url, json=payload, timeout=30)
resp.raise_for_status()
data = resp.json()
return data["choices"][0]["message"]["content"]
except Exception as e:
return f"Error: {e}"
async def main():
# 限制最大并发 50
semaphore = asyncio.Semaphore(50)
async with httpx.AsyncClient(base_url="http://your-vllm-host:8000") as client:
tasks = []
for i in range(200): # 200 个并发请求
tasks.append(
async_vllm_call(
client,
"/v1/chat/completions",
"your-model-name",
f"请计算 {i} 的平方根",
semaphore,
)
)
results = await asyncio.gather(*tasks)
print(f"完成 {len(results)} 个请求")
if __name__ == "__main__":
asyncio.run(main())
四、高并发调优建议(站长压箱底的经验)
很多朋友部署完 vLLM 后,发现并发一高就 OOM 或者延迟飙升。站长这里给出一套经过生产验证的调优清单:
4.1 核心参数调优
| 参数 | 推荐值 | 说明 |
|---|---|---|
--max-num-seqs |
256 ~ 512 | 最大并发序列数。显存越大,可以越高。太高会导致调度延迟。 |
--max-num-batched-tokens |
8192 ~ 16384 | 每个 step 处理的最大 token 数。根据模型 size 调整,太大会增加首 token 延迟。 |
--gpu-memory-utilization |
0.85 ~ 0.92 | 不要超过 0.95,否则 CUDA 会报错。 |
--block-size |
16 或 32 | PagedAttention 的块大小。小模型用 16,大模型用 32 减少显存浪费。 |
--max-model-len |
根据业务定 | 如果业务实际用不到 8192,就别设那么大,否则 KV Cache 浪费。 |
4.2 部署架构层面的建议
- 多副本 + 负载均衡:单实例吞吐量有限(比如 500 QPS),如果业务需要 2000 QPS,就部署 4 个 vLLM 实例,前面加一个 Nginx 做轮询。注意每个实例的
served-model-name保持一致,客户端无感知。 - 预热(Warm-up):vLLM 启动后,第一次请求会有额外的 CUDA Graph 编译延迟(约 5-10 秒)。在服务启动后,立即发一个短文本请求预热,避免用户遇到超时。
- 超时与重试:生产环境必须设置客户端超时(建议 60s+),并做指数退避重试。vLLM 的队列是内存队列,如果请求太多,会直接拒绝连接,所以客户端要做好 503 处理。
- 监控指标:vLLM 暴露了 Prometheus 指标(端口 8000/metrics)。重点关注
vllm:num_requests_running、vllm:num_requests_waiting、vllm:gpu_cache_usage_perc。当 cache usage 超过 90% 时,说明要扩容了。 - 批处理大小动态调整:如果你的业务请求长度波动大,不要固定
max_tokens,而是根据用户输入长度动态计算。vLLM 的调度器会自己优化,但客户端尽量提供合理的max_tokens,避免预留过多。
4.3 常见坑与避坑指南
--quantization awq 时,如果模型权重不是 AWQ 格式,会直接报错。请先用 autoawq 转换。坑2:多卡部署时,
--tensor-parallel-size 必须能被 GPU 数量整除,且所有卡必须同型号。坑3:vLLM 的
--host 默认是 0.0.0.0,但如果你在容器内,需要确保端口映射正确。否则外部无法访问。坑4:如果模型是 Chat 模型,必须用
/v1/chat/completions,不要用 /v1/completions,否则格式不匹配会报错。五、生产环境压测结果参考
站长用一张 A100 80G 跑 Llama-3-8B(AWQ 量化)做压测,得到以下数据供参考:
- 并发 100,输入长度 512,输出长度 256:吞吐量约 1500 tokens/s,P95 延迟 1.2s。
- 并发 200,输入长度 512,输出长度 256:吞吐量约 2200 tokens/s,P95 延迟 2.5s。
- 并发 300 以上,出现队列积压,延迟指数上升,建议扩容。
这证明 vLLM 的 Continuous Batching 在并发适中时表现优异,但并发过高时,瓶颈会转移到 GPU 算力和显存带宽。站长建议:优先提升单卡性能,再考虑横向扩容。
六、总结
站长这篇实战方案,覆盖了 vLLM 从部署到高并发调优的完整链路。核心要点再强调一遍:
1. 架构上,vLLM 的 PagedAttention 和 Continuous Batching 是提速关键,理解它们才能正确配置参数。
2. API 调用,直接用 OpenAI 兼容接口,配合流式输出和异步客户端,能应对绝大多数业务场景。
3. 调优,永远从显存利用率入手,监控 cache usage,动态扩容。
如果你按照站长的方案落地,生产环境的高并发推理服务基本稳了。有任何参数细节拿不准的,多跑几组压测对比,数据不会说谎。
相关 AI 排错与深度技术延伸
⚡ 开发者实操必备资源与算力限时特惠通道
阅读完本教程准备实操?站长已将 AI 部署排错手册、提示词全集与服务器限时优惠整理如下,即拿即用: