Hermes + vLLM:搭建高吞吐量推理服务的完整流程

用vLLM部署Hermes模型搭建高吞吐量推理API,包含安装配置、模型加载、Continuous Batching原理解析和性能调优实战。

目录

  1. vLLM 是什么,凭什么快
  2. 环境准备
    1. 安装 vLLM
  3. 启动 Hermes 推理服务
    1. 基础启动
    2. 验证服务
    3. 用 Python 调用
  4. 深入理解 Continuous Batching
  5. 性能调优参数详解
    1. 关键参数
    2. 量化部署
    3. 多 GPU 部署
  6. 生产环境部署建议
    1. 用 systemd 管理服务
    2. 加个 Nginx 反代
    3. 监控
  7. 压测一下
  8. 常见问题排查
  9. Docker 部署
  10. 和其他方案的对比
  11. 后续可以做的事

如果你只是自己一个人用,Ollama 跑 Hermes 完全够用。但如果你要做的是一个服务——比如给团队十几个人用,或者给你的应用提供 API 后端——Ollama 的单请求处理模式就有点扛不住了。

这时候你需要的是 vLLM。

vLLM 是什么,凭什么快

vLLM 的全称是 Virtual Large Language Model,UC Berkeley 团队搞的。它最核心的两个技术点:

PagedAttention:传统的 KV Cache 管理方式很浪费显存——每个请求预分配一大块连续内存,用不完的部分就空着。PagedAttention 借鉴了操作系统虚拟内存分页的思路,把 KV Cache 切成小块按需分配。显存利用率直接提升了好几倍。

Continuous Batching:传统方案是等一批请求凑齐了再一起处理,先到的请求得等后到的。vLLM 的做法更聪明——新请求随时插入当前批次,完成的请求随时退出。相当于一个动态的”滚动窗口”,吞吐量能提升 2-4 倍。

说人话就是:同样的 GPU,vLLM 能同时伺候更多的请求,每个请求的等待时间也更短。

环境准备

vLLM 对硬件有要求,先确认一下你的环境:

  • NVIDIA GPU,至少 16GB 显存(跑 Hermes 3 8B)
  • CUDA 12.1+
  • Python 3.9-3.12

查看 GPU 信息:

1
nvidia-smi

确认 CUDA 版本:

1
nvcc --version

安装 vLLM

建议用 conda 或 venv 隔离环境:

1
2
3
4
5
6
# 创建虚拟环境
python -m venv vllm-env
source vllm-env/bin/activate

# 安装 vLLM
pip install vllm

安装过程会自动处理 PyTorch 和 CUDA 依赖。第一次装可能要等挺久,包比较大。

如果遇到网络问题,可以用清华源加速:

1
pip install vllm -i https://pypi.tuna.tsinghua.edu.cn/simple

启动 Hermes 推理服务

基础启动

最简单的启动方式:

1
2
3
4
5
python -m vllm.entrypoints.openai.api_server \
--model NousResearch/Hermes-3-Llama-3.1-8B \
--host 0.0.0.0 \
--port 8000 \
--max-model-len 8192

第一次运行会从 HuggingFace 下载模型,大概 16GB。之后就走本地缓存了。

启动成功后你会看到类似的日志:

1
2
INFO:     Started server process [12345]
INFO: Uvicorn running on http://0.0.0.0:8000

验证服务

1
2
3
4
5
6
7
8
9
10
11
12
13
# 查看可用模型
curl http://localhost:8000/v1/models

# 发送一个对话请求
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "NousResearch/Hermes-3-Llama-3.1-8B",
"messages": [
{"role": "user", "content": "用一句话介绍你自己"}
],
"max_tokens": 256
}'

用 Python 调用

因为 vLLM 提供的是标准 OpenAI 兼容 API,所以代码跟调 OpenAI 几乎一样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from openai import OpenAI

client = OpenAI(
base_url="http://localhost:8000/v1",
api_key="not-needed" # vLLM 默认不需要鉴权
)

response = client.chat.completions.create(
model="NousResearch/Hermes-3-Llama-3.1-8B",
messages=[
{"role": "system", "content": "你是一个专业的技术助手。"},
{"role": "user", "content": "解释一下 Transformer 的自注意力机制"}
],
temperature=0.7,
max_tokens=1024
)

print(response.choices[0].message.content)

深入理解 Continuous Batching

这部分稍微展开讲一下,因为理解了这个才能做好性能调优。

传统的 Static Batching 大概是这么个流程:

1
2
3
请求A(100 tokens) ──────────> 完成
请求B(50 tokens) ──────> 完成 [空等] [空等]
请求C(80 tokens) ────────> 完成 [空等]

B 和 C 虽然生成完了,但得等 A 这个最长的搞完,整个批次才算完。GPU 有一大半时间在摸鱼。

Continuous Batching 的做法:

1
2
3
请求A(100 tokens) ──────────> 完成
请求B(50 tokens) ──────> 完成 -> 请求D开始 ─────>
请求C(80 tokens) ────────> 完成 -> 请求E开始 ──>

B 完成后,它的 GPU 资源立刻释放给新的请求 D。没有空等,没有浪费。

vLLM 在这个基础上又做了优化——它可以在每一步 token 生成之后检查是否有请求完成或新请求加入,粒度细到了 iteration level。

性能调优参数详解

关键参数

1
2
3
4
5
6
7
8
9
10
11
python -m vllm.entrypoints.openai.api_server \
--model NousResearch/Hermes-3-Llama-3.1-8B \
--host 0.0.0.0 \
--port 8000 \
--tensor-parallel-size 1 \
--max-model-len 8192 \
--max-num-batched-tokens 16384 \
--max-num-seqs 64 \
--gpu-memory-utilization 0.90 \
--dtype auto \
--enforce-eager

逐个解释:

–tensor-parallel-size:张量并行数,等于你要用几张 GPU。单卡填 1,双卡填 2,以此类推。注意不是所有模型都支持任意并行数。

–max-model-len:最大上下文长度。Hermes 3 原生支持 128K,但设太大会吃更多显存。根据实际需求设置,8192 对大部分场景够用了。

–max-num-batched-tokens:每个 iteration 处理的最大 token 总数。设大了吞吐高但延迟也会上去,需要根据你的显存和场景权衡。

–max-num-seqs:最大并发序列数,也就是同时处理多少个请求。默认 256,如果显存紧张可以调小。

–gpu-memory-utilization:GPU 显存使用率上限。默认 0.9,留 10% 给系统。如果你的 GPU 只跑这一个服务,可以调到 0.95。

–enforce-eager:禁用 CUDA Graph。CUDA Graph 启动快但占额外显存。显存紧张时加上这个参数。

量化部署

显存实在不够?上量化:

1
2
3
4
5
# AWQ 量化版本(需要先下载对应模型)
python -m vllm.entrypoints.openai.api_server \
--model TheBloke/Hermes-3-Llama-3.1-8B-AWQ \
--quantization awq \
--max-model-len 8192

AWQ 量化大概能把显存需求减少一半,质量损失很小。

多 GPU 部署

如果你有多张卡:

1
2
3
4
5
# 2卡张量并行
python -m vllm.entrypoints.openai.api_server \
--model NousResearch/Hermes-3-Llama-3.1-8B \
--tensor-parallel-size 2 \
--max-model-len 16384

多卡并行不仅能处理更大的模型,还能显著提升吞吐量。不过通信开销也会上来,两张卡不是简单的 2 倍速。

生产环境部署建议

用 systemd 管理服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
cat > /etc/systemd/system/vllm-hermes.service << 'EOF'
[Unit]
Description=vLLM Hermes Inference Service
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/root
ExecStart=/root/vllm-env/bin/python -m vllm.entrypoints.openai.api_server \
--model NousResearch/Hermes-3-Llama-3.1-8B \
--host 0.0.0.0 \
--port 8000 \
--max-model-len 8192 \
--gpu-memory-utilization 0.90
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable vllm-hermes
systemctl start vllm-hermes

加个 Nginx 反代

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
upstream vllm_backend {
server 127.0.0.1:8000;
}

server {
listen 443 ssl;
server_name api.yourdomain.com;

ssl_certificate /etc/letsencrypt/live/api.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.yourdomain.com/privkey.pem;

location /v1/ {
proxy_pass http://vllm_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}

监控

vLLM 自带了 Prometheus metrics endpoint:

1
curl http://localhost:8000/metrics

关键指标:

  • vllm:num_requests_running:正在处理的请求数
  • vllm:num_requests_waiting:排队中的请求数
  • vllm:gpu_cache_usage_perc:GPU KV Cache 使用率
  • vllm:avg_generation_throughput_toks_per_s:平均生成速度

压测一下

用 vLLM 自带的 benchmark 工具跑一下看看性能:

1
2
3
4
5
6
python -m vllm.entrypoints.openai.bench_serving \
--backend openai \
--base-url http://localhost:8000 \
--model NousResearch/Hermes-3-Llama-3.1-8B \
--num-prompts 100 \
--request-rate 10

在单张 A100 80GB 上跑 Hermes 3 8B,大概能跑到 2000+ tokens/s 的吞吐量,50 个并发请求无压力。这个数字比 Ollama 高了不止一个量级。

常见问题排查

Q: 启动时报 CUDA out of memory?

几个方向:

  1. 减小 --max-model-len,比如从 8192 降到 4096
  2. 加上 --enforce-eager 禁用 CUDA Graph
  3. 降低 --gpu-memory-utilization 到 0.85
  4. 用量化模型

Q: 模型下载失败或者很慢?

HuggingFace 在国内访问经常不稳定。可以用镜像:

1
2
export HF_ENDPOINT=https://hf-mirror.com
python -m vllm.entrypoints.openai.api_server --model NousResearch/Hermes-3-Llama-3.1-8B

或者手动下载模型到本地,然后指定本地路径:

1
2
3
python -m vllm.entrypoints.openai.api_server \
--model /path/to/local/Hermes-3-Llama-3.1-8B \
--max-model-len 8192

Q: 返回结果质量不如 Ollama?

可能是聊天模板没正确加载。vLLM 通常会自动读取模型仓库里的 chat_template,但有时需要手动指定:

1
2
3
python -m vllm.entrypoints.openai.api_server \
--model NousResearch/Hermes-3-Llama-3.1-8B \
--chat-template ./hermes_template.jinja

Hermes 3 用的是 ChatML 格式,确保模板匹配。

Q: 多用户同时访问时部分请求超时?

调整以下参数:

1
2
--max-num-seqs 128        # 增加并发数
--max-num-batched-tokens 32768 # 增加批处理 token 上限

同时注意 Nginx 反代的超时设置也要调大。

Docker 部署

如果你不想手动管理 Python 环境,可以直接用 vLLM 的官方 Docker 镜像:

1
2
3
4
5
6
7
docker run --runtime nvidia --gpus all \
-v ~/.cache/huggingface:/root/.cache/huggingface \
-p 8000:8000 \
--ipc=host \
vllm/vllm-openai:latest \
--model NousResearch/Hermes-3-Llama-3.1-8B \
--max-model-len 8192

Docker 方式的好处是环境完全隔离,不用担心依赖冲突。--ipc=host 参数是必须的,因为 vLLM 用共享内存做进程间通信。

用 Docker Compose 组织多个服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
version: '3.8'

services:
vllm:
image: vllm/vllm-openai:latest
runtime: nvidia
ports:
- "8000:8000"
volumes:
- huggingface-cache:/root/.cache/huggingface
ipc: host
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
command: >
--model NousResearch/Hermes-3-Llama-3.1-8B
--host 0.0.0.0
--port 8000
--max-model-len 8192
--gpu-memory-utilization 0.90

volumes:
huggingface-cache:

和其他方案的对比

特性 Ollama vLLM TGI
上手难度 最低 中等 中等
单请求延迟
高并发吞吐 一般 很强
显存效率 一般 很高
生态整合
适用场景 个人/开发 生产服务 生产服务

选择很清楚:开发阶段用 Ollama,上线了切 vLLM。

后续可以做的事

vLLM 把推理服务跑起来之后,你可以:

在 cocoloop 社区里也有人分享过在不同 GPU 上跑 vLLM 的性能数据,可以去参考一下。

vLLM + Hermes 这套方案在生产环境里经过了不少验证。如果你要认真做一个面向用户的 AI 服务,这大概是目前最靠谱的开源自部署方案之一。

参与讨论

对这篇文章有疑问或想法?cocoloop 社区有不少开发者在讨论 Hermes 相关话题,欢迎加入交流。

前往 cocoloop 社区 →