大模型私有化部署:vLLM vs TGI 性能对比
赵文博 · 2026年3月6日 · 28 分钟
背景
私有化部署大模型已经成为企业 AI 落地的标配。出于数据安全、成本控制和延迟要求,越来越多的企业选择自建推理服务而非调用云端 API。
在推理框架的选择上,vLLM 和 Hugging Face TGI(Text Generation Inference)是目前最主流的两个开源选项。此外还有 NVIDIA 的 TensorRT-LLM、ONNX Runtime 等选择,但在开源社区的活跃度和易用性上,vLLM 和 TGI 是第一梯队。
我们在相同硬件环境下对两者进行了系统性对比,覆盖吞吐量、延迟、显存利用率、长文本处理、多模型服务等多个维度。
测试环境
硬件配置
| 组件 | 配置 |
|---|---|
| GPU | 2x NVIDIA A100 80GB(NVLink) |
| CPU | 2x AMD EPYC 7763 64-Core |
| 内存 | 512 GB DDR4 |
| 存储 | 2TB NVMe SSD |
| 网络 | 100 Gbps InfiniBand |
软件版本
| 组件 | 版本 |
|---|---|
| 操作系统 | Ubuntu 22.04 LTS |
| CUDA | 12.2 |
| Driver | 535.104.05 |
| Python | 3.11 |
| vLLM | 0.6.4 |
| TGI | 2.4.0 |
测试模型
| 模型 | 参数量 | 量化 | 显存占用 |
|---|---|---|---|
| Qwen2.5-72B-Instruct | 72B | AWQ 4-bit | ~40 GB |
| Qwen2.5-7B-Instruct | 7B | FP16 | ~14 GB |
| Llama-3.1-70B-Instruct | 70B | AWQ 4-bit | ~38 GB |
主要使用 Qwen2.5-72B-Instruct(AWQ 量化)进行核心对比,7B 模型用于补充验证。
测试工具
我们使用自研 benchmark 工具,模拟真实业务请求分布:
# 请求参数设置
test_configs = {
"short": {"input_len": 128, "output_len": 128}, # 短文本
"medium": {"input_len": 512, "output_len": 256}, # 中等文本
"long": {"input_len": 2048, "output_len": 512}, # 长文本
"very_long": {"input_len": 8192, "output_len": 1024}, # 超长文本
}
# 并发设置
concurrency_levels = [1, 4, 8, 16, 32, 64, 128]
核心对比结果
吞吐量(Throughput)
在并发 32 请求、中等文本(512/256)条件下:
| 框架 | 吞吐量 (tokens/s) | 相对性能 |
|---|---|---|
| vLLM | 1,847 | 100% (基准) |
| TGI | 1,512 | 82% |
不同并发下的吞吐量对比:
| 并发数 | vLLM (tok/s) | TGI (tok/s) | vLLM 优势 |
|---|---|---|---|
| 1 | 98 | 95 | +3% |
| 4 | 385 | 370 | +4% |
| 8 | 748 | 695 | +8% |
| 16 | 1,320 | 1,150 | +15% |
| 32 | 1,847 | 1,512 | +22% |
| 64 | 2,156 | 1,680 | +28% |
| 128 | 2,230 | 1,710 | +30% |
关键发现: vLLM 的优势随并发增加而扩大。在低并发(1-4)下差异不大,但在高并发(32+)下 vLLM 领先 22-30%。这主要得益于 PagedAttention 的 KV Cache 管理效率。
首 Token 延迟(TTFT - Time To First Token)
| 框架 | TTFT P50 | TTFT P95 | TTFT P99 |
|---|---|---|---|
| vLLM | 285ms | 512ms | 820ms |
| TGI | 260ms | 480ms | 750ms |
TGI 在首 token 延迟上略优,约快 8-10%。 TGI 在 prefill 阶段的调度优化使其在首 token 延迟上有一定优势。对于对话式交互场景,这个差异会被用户感知。
端到端延迟(E2E Latency)
单请求、中等文本条件下:
| 框架 | P50 | P95 | P99 |
|---|---|---|---|
| vLLM | 2.8s | 3.5s | 4.2s |
| TGI | 3.1s | 4.0s | 5.1s |
vLLM 在端到端延迟上优势更明显(10-15%),因为 decode 阶段的效率更高。
显存利用率
| 框架 | 模型加载后 | 峰值(并发 32) | 可用显存 |
|---|---|---|---|
| vLLM | 42.5 GB | 73.2 GB | 6.8 GB |
| TGI | 43.8 GB | 76.8 GB | 3.2 GB |
vLLM 的 PagedAttention 更高效地管理 KV Cache:
- 减少显存碎片,同样的显存支持更大的批处理
- 非连续内存分配,避免了 KV Cache 的预分配浪费
- 在显存受限的环境中(如单 A100 40GB),这个差异更关键
长文本处理
当输入 token 数增加时,两者的性能变化:
| 输入长度 | vLLM 吞吐量 | TGI 吞吐量 | vLLM 下降 | TGI 下降 |
|---|---|---|---|---|
| 512 | 1,847 tok/s | 1,512 tok/s | 基准 | 基准 |
| 2048 | 1,620 tok/s | 1,250 tok/s | -12% | -17% |
| 4096 | 1,480 tok/s | 1,105 tok/s | -20% | -27% |
| 8192 | 1,320 tok/s | 980 tok/s | -29% | -35% |
| 16384 | 1,050 tok/s | 720 tok/s | -43% | -52% |
vLLM 在长文本场景的优势更明显——随着输入长度增加,TGI 的性能下降更快。在 16K token 输入时,vLLM 的吞吐量是 TGI 的 1.46 倍。
深入技术分析
PagedAttention 原理
vLLM 的核心创新是 PagedAttention——借鉴了操作系统虚拟内存的分页机制来管理 KV Cache:
传统方案的问题:
- 为每个请求预分配最大长度的 KV Cache → 严重浪费
- 已完成的请求的 KV Cache 不能被复用 → 显存碎片化
- 预分配策略导致最大并发数受限
PagedAttention 的解决方案:
- 将 KV Cache 分成固定大小的"页"(类似 OS 内存页)
- 按需分配,用完即释放
- 非连续存储,通过页表管理映射关系
- 支持 Copy-on-Write,相同前缀的请求可以共享 KV Cache
这使得 vLLM 在高并发下的显存利用率提升 2-4 倍。
TGI 的 Continuous Batching
TGI 使用 Continuous Batching(也叫 In-flight Batching)策略:
- 不等待一个批次全部完成再开始下一个
- 当某个请求完成时,立即将新请求插入批次
- 这在 TTFT 优化上有优势,因为新请求可以更快进入处理
Speculative Decoding
两者都在探索的优化方向——推测解码:
- 用小模型快速生成多个候选 token
- 大模型验证候选是否正确
- 正确的直接采纳,不正确的回退
vLLM 在 0.6.x 版本中已支持 Speculative Decoding,实测在特定场景下可提速 1.5-2 倍。
工程化对比
部署体验
vLLM 部署:
# 安装
pip install vllm
# 启动(API 兼容 OpenAI 格式)
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-72B-Instruct-AWQ \
--quantization awq \
--tensor-parallel-size 2 \
--max-model-len 32768 \
--gpu-memory-utilization 0.9 \
--port 8000
# 调用(完全兼容 OpenAI SDK)
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="unused")
response = client.chat.completions.create(
model="Qwen/Qwen2.5-72B-Instruct-AWQ",
messages=[{"role": "user", "content": "你好"}]
)
TGI 部署:
# Docker 方式(推荐)
docker run --gpus all -p 8080:80 \
-v /data/models:/data \
ghcr.io/huggingface/text-generation-inference:2.4.0 \
--model-id Qwen/Qwen2.5-72B-Instruct-AWQ \
--quantize awq \
--num-shard 2 \
--max-input-length 16384 \
--max-total-tokens 32768
# 调用(使用 TGI 的自定义客户端)
from huggingface_hub import InferenceClient
client = InferenceClient("http://localhost:8080")
response = client.text_generation(
"你好",
max_new_tokens=256
)
部署体验对比:
| 维度 | vLLM | TGI |
|---|---|---|
| 安装方式 | pip install | Docker(推荐) |
| API 格式 | OpenAI 兼容 | 自定义 |
| 多模型服务 | 需要多实例 | 需要多实例 |
| 配置复杂度 | 中等 | 中等 |
| 文档质量 | 好 | 好 |
| 社区支持 | 非常活跃 | 活跃 |
模型支持
| 维度 | vLLM | TGI |
|---|---|---|
| 支持模型架构 | 100+ | 60+ |
| 新模型适配速度 | 社区驱动,通常 1-2 周 | 官方驱动,通常 2-4 周 |
| 多模态模型 | 支持(LLaVA 等) | 部分支持 |
| 自定义模型 | 容易(纯 Python) | 需要 Rust 适配 |
量化支持
| 量化方法 | vLLM | TGI |
|---|---|---|
| AWQ | 支持 | 支持 |
| GPTQ | 支持 | 支持 |
| SqueezeLLM | 支持 | 不支持 |
| FP8 | 支持 | 支持 |
| EETQ | 不支持 | 支持 |
| Marlin (4-bit) | 支持 | 不支持 |
| bitsandbytes | 支持 | 支持 |
生产环境功能
| 功能 | vLLM | TGI |
|---|---|---|
| Tensor Parallelism | 支持 | 支持 |
| Pipeline Parallelism | 支持 | 不支持 |
| Prefix Caching | 支持 | 部分支持 |
| LoRA 在线切换 | 支持 | 支持 |
| Token Streaming | 支持 | 支持 |
| 请求优先级 | 支持 | 不支持 |
| Prometheus Metrics | 支持 | 支持 |
| Structured Output | 支持(Outlines) | 支持 |
不同场景的选型建议
| 场景 | 推荐 | 原因 |
|---|---|---|
| 追求最大吞吐量 | vLLM | PagedAttention 在高并发优势明显 |
| 首 token 延迟敏感(对话) | TGI | Prefill 调度优化更好 |
| 显存受限(40GB GPU) | vLLM | 显存利用率更高 |
| 需要 OpenAI 兼容 API | vLLM | 原生支持,零成本切换 |
| 长文本处理(8K+) | vLLM | 长文本性能衰减更小 |
| Hugging Face 生态集成 | TGI | 原生集成 |
| 多 LoRA 切换 | vLLM | 切换开销更低 |
| 生产稳定性优先 | 两者均可 | 都经过大规模验证 |
| 追求新功能/新模型 | vLLM | 社区更活跃,迭代更快 |
生产部署最佳实践
高可用架构
Client Request
↓
[Nginx / HAProxy] ← 负载均衡
├── vLLM Instance 1 (GPU 0-1)
├── vLLM Instance 2 (GPU 2-3)
└── vLLM Instance 3 (GPU 4-5)
↓
[Prometheus] → [Grafana] ← 监控
Kubernetes 部署
apiVersion: apps/v1
kind: Deployment
metadata:
name: vllm-qwen72b
spec:
replicas: 2
selector:
matchLabels:
app: vllm-qwen72b
template:
spec:
containers:
- name: vllm
image: vllm/vllm-openai:latest
args:
- "--model"
- "Qwen/Qwen2.5-72B-Instruct-AWQ"
- "--quantization"
- "awq"
- "--tensor-parallel-size"
- "2"
- "--gpu-memory-utilization"
- "0.9"
- "--max-model-len"
- "32768"
resources:
limits:
nvidia.com/gpu: 2
memory: 64Gi
ports:
- containerPort: 8000
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 120 # 模型加载需要时间
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 120
periodSeconds: 10
监控关键指标
# Prometheus 告警规则
groups:
- name: vllm_alerts
rules:
- alert: HighLatency
expr: vllm_e2e_request_latency_seconds{quantile="0.95"} > 10
for: 5m
labels:
severity: warning
annotations:
summary: "vLLM P95 延迟超过 10 秒"
- alert: HighGPUMemory
expr: vllm_gpu_cache_usage_perc > 95
for: 5m
labels:
severity: critical
annotations:
summary: "GPU 缓存使用率超过 95%"
- alert: RequestQueueFull
expr: vllm_num_requests_waiting > 100
for: 2m
labels:
severity: warning
annotations:
summary: "等待队列超过 100 个请求"
成本优化建议
- 选择合适的量化:AWQ 4-bit 在大多数场景下质量损失极小,但显存减少 75%
- 合理设置 max_model_len:不需要 32K 上下文就设小一些,节省显存
- Prefix Caching:系统 Prompt 相同时启用,减少重复计算
- 弹性伸缩:基于 GPU 利用率和队列长度做 HPA
- 混合部署:常用模型常驻,低频模型按需加载
我们的选择
在实际项目中,我们默认选择 vLLM,原因:
- PagedAttention 的吞吐量优势在高并发场景尤为明显——我们的业务通常并发 16-64
- OpenAI 兼容 API 降低了应用层的适配成本——切换模型只需改 base_url
- 社区活跃度更高,新功能和 Bug 修复更快
- 显存效率更高,意味着同样的硬件可以服务更多请求
- 长文本处理能力更强,我们的 RAG 场景经常需要处理 8K+ 的上下文
但在以下场景中我们仍然考虑 TGI:
- 首 token 延迟极其敏感的实时对话场景
- 深度集成 Hugging Face 生态的项目
- 需要 EETQ 量化的特定模型
其他值得关注的推理框架
TensorRT-LLM
NVIDIA 官方出品,基于 TensorRT 优化:
- 性能:在 NVIDIA GPU 上通常是最快的
- 缺点:模型需要预编译,部署流程复杂,不支持非 NVIDIA 硬件
- 适用:追求极致性能且能接受复杂部署流程的场景
SGLang
来自 LMSYS 团队的新框架:
- 创新的 RadixAttention 机制
- 编程模型更灵活(支持复杂的 Prompt 编排)
- 正在快速发展中,值得关注
llama.cpp
C++ 实现的轻量级推理引擎:
- 支持 CPU 推理,无需 GPU
- 适合边缘部署、消费级硬件
- 不适合高并发的生产环境
总结
推理框架的选择没有绝对的好坏,关键是匹配业务场景。
我们的核心建议:
- 在真实数据和负载下做 Benchmark,不要仅依赖公开测评
- 关注总拥有成本(TCO),而不只是单一性能指标
- 考虑运维复杂度——最快的框架如果无法稳定运行也没有意义
- 保持关注社区动态,推理框架迭代很快,半年前的结论可能已过时
- 先从 vLLM 开始(生态最好、上手最简单),有特定需求再评估其他方案
希望本文的对比数据和分析能帮助你做出更好的选型决策。如果你有不同的测试结果或实践经验,欢迎交流讨论。