TGI 架构#
Text Generation Inference(TGI)是 HuggingFace 官方的 LLM 推理服务器,与 HuggingFace 生态深度集成。
┌─────────────────────────────────────────────┐
│ OpenAI Compatible REST API │
│ (Streaming / Function Calling / Tools) │
├─────────────────────────────────────────────┤
│ Router │
│ (Load Balancing + Queue Management) │
├──────────────┬──────────────────────────────┤
│ Flash │ Continuous Batching │
│ Attention │ Scheduler │
│ (v2/v3) │ │
├──────────────┴──────────────────────────────┤
│ CUDA / ROCm Workers │
│ (Tensor Parallel + Quantization) │
└─────────────────────────────────────────────┘
核心组件#
| 组件 | 说明 |
|---|
| Router | 请求路由、负载均衡、队列管理 |
| Flash Attention | I/O 感知的精确注意力 |
| Continuous Batching | 动态批处理 |
| Quantization | GPTQ / AWQ / EETQ / BitsAndBytes |
| Watermark | 水印生成(防滥用) |
| Token Streaming | SSE 流式输出 |
Flash Attention 集成#
TGI 从设计之初就深度集成 Flash Attention,这是其与 vLLM 早期竞争的核心优势之一。
Flash Attention 原理#
标准 Attention 的瓶颈在于 HBM(显存)读写带宽:
标准 Attention:
Q, K, V → 写入 HBM → 读取计算 S=QK^T → 写入 HBM
→ 读取 S → 计算 P=softmax(S) → 写入 HBM
→ 读取 P, V → 计算 O=PV → 写入 HBM
# 3次完整矩阵读写,O(N²) HBM 访问
Flash Attention:
分块计算,在 SRAM 中完成全部中间计算
# 仅需 O(N) HBM 访问,计算结果分块写入
性能差异#
| 模型 | 序列长度 | 标准 Attention | Flash Attention v2 | 加速比 |
|---|
| Llama 3.1 8B | 4K | 85 tok/s | 140 tok/s | 1.65x |
| Llama 3.1 8B | 32K | 12 tok/s | 68 tok/s | 5.7x |
| Llama 3.1 70B | 4K | 18 tok/s | 32 tok/s | 1.78x |
| Llama 3.1 70B | 32K | 2 tok/s | 14 tok/s | 7.0x |
序列越长,Flash Attention 优势越大,因为 HBM 带宽瓶颈呈平方增长。
启用配置#
# TGI 默认启用 Flash Attention,也可显式指定
docker run --gpus all \
ghcr.io/huggingface/text-generation-inference:latest \
--model meta-llama/Llama-3.1-8B-Instruct \
--flash-attention \
--max-input-tokens 4096 \
--max-total-tokens 8192
Continuous Batching#
TGI 的 Continuous Batching 实现与 vLLM 类似,但在调度策略上有差异。
TGI 调度策略#
// TGI Scheduler 核心逻辑(Rust 实现,简化)
pub struct Scheduler {
waiting_queue: VecDeque<Request>,
running_queue: VecDeque<Request>,
max_batch_size: usize,
max_waiting_tokens: usize,
}
impl Scheduler {
pub fn schedule(&mut self) -> Batch {
let mut batch = Batch::new();
// 1. 优先处理 running 请求(decode step)
for req in &self.running_queue {
batch.add(req);
if batch.size() >= self.max_batch_size {
return batch;
}
}
// 2. 从 waiting 队列拉取新请求(prefill)
// TGI 策略:prefill 和 decode 不混合,避免 padding 浪费
while !self.waiting_queue.is_empty() {
let req = self.waiting_queue.front().unwrap();
if batch.size() + 1 > self.max_batch_size {
break;
}
let req = self.waiting_queue.pop_front().unwrap();
batch.add(&req);
}
batch
}
}
TGI vs vLLM 调度差异#
| 特性 | TGI | vLLM |
|---|
| Prefill/Decode 混合 | ❌ 分离 | ✅ 混合 |
| KV Cache 管理 | 基于显存预分配 | PagedAttention |
| 前缀缓存 | ⚠️ 有限 | ✅ Prefix Caching |
| 批处理大小 | 固定上限 | 动态调整 |
| 优先级调度 | ✅ 支持 | ⚠️ 实验性 |
量化支持#
支持的量化方案#
| 方案 | TGI 支持 | 说明 |
|---|
| GPTQ | ✅ | AutoGPTQ 集成 |
| AWQ | ✅ | 4-bit 权重量化 |
| EETQ | ✅ | 8-bit 动态量化 |
| BitsAndBytes | ✅ | 4/8-bit |
| FP8 | ⚠️ 实验性 | H100 |
| GGUF | ❌ | 不支持 |
部署示例#
# GPTQ 量化模型
docker run --gpus all \
ghcr.io/huggingface/text-generation-inference:latest \
--model TheBloke/Llama-2-13B-GPTQ \
--quantize gptq \
--max-total-tokens 4096
# AWQ 量化模型
docker run --gpus all \
ghcr.io/huggingface/text-generation-inference:latest \
--model TheBloke/Mistral-7B-Instruct-v0.2-AWQ \
--quantize awq \
--max-total-tokens 8192
# EETQ 8-bit(推荐,精度损失最小)
docker run --gpus all \
ghcr.io/huggingface/text-generation-inference:latest \
--model meta-llama/Llama-3.1-8B-Instruct \
--quantize eetq \
--max-total-tokens 8192
量化性能对比#
以 Llama 3.1 8B 在 A100 40G 上:
| 量化 | 显存占用 | 吞吐 (tok/s) | PPL 变化 |
|---|
| FP16 (基准) | 16 GB | 140 | 0 |
| EETQ 8-bit | 8.5 GB | 155 | +0.01 |
| GPTQ 4-bit | 5.2 GB | 168 | +0.15 |
| AWQ 4-bit | 5.0 GB | 172 | +0.08 |
| BnB 4-bit | 5.5 GB | 130 | +0.12 |
API 兼容性#
OpenAI 兼容端点#
# TGI 原生 API
curl http://localhost:8080/generate \
-H "Content-Type: application/json" \
-d '{
"inputs": "Explain quantum computing",
"parameters": {
"max_new_tokens": 512,
"temperature": 0.7,
"top_p": 0.9,
"repetition_penalty": 1.1,
"do_sample": true
},
"stream": true
}'
# OpenAI 兼容端点(/v1/chat/completions)
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "meta-llama/Llama-3.1-8B-Instruct",
"messages": [
{"role": "user", "content": "Hello"}
],
"stream": true,
"max_tokens": 512
}'
Function Calling 支持#
import requests
response = requests.post("http://localhost:8080/v1/chat/completions", json={
"model": "meta-llama/Llama-3.1-8B-Instruct",
"messages": [
{"role": "user", "content": "What's the weather in Tokyo?"}
],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get weather for a city",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"}
}
}
}
}],
"tool_choice": "auto"
})
API 特性对比#
| 特性 | TGI 原生 API | TGI OpenAI 兼容 |
|---|
| 流式输出 | ✅ SSE | ✅ SSE |
| Function Calling | ⚠️ 原生格式 | ✅ OpenAI 格式 |
| JSON 模式 | ❌ | ✅ |
| 多模态 | ✅ | ✅ |
| 水印 | ✅ | ⚠️ |
| Grammar 约束 | ❌ | ❌ |
| Token 概率 | ✅ | ⚠️ logprobs |
TGI vs vLLM 全面对比#
基准测试#
环境:Llama 3.1 8B BF16,A100 80GB,100 并发
| 指标 | TGI 2.3 | vLLM 0.6 |
|---|
| 吞吐 (tok/s) | 3200 | 4200 |
| P50 TTFT (ms) | 95 | 82 |
| P99 TTFT (ms) | 580 | 340 |
| 显存利用率 | 82% | 96% |
| 最大并发 | 256 | 512 |
功能矩阵#
| 功能 | TGI | vLLM |
|---|
| OpenAI API 兼容 | ✅ | ✅ |
| Flash Attention | ✅ v2/v3 | ✅ v2/v3 |
| PagedAttention | ❌ | ✅ |
| Prefix Caching | ⚠️ | ✅ |
| Tensor Parallel | ✅ | ✅ |
| Pipeline Parallel | ❌ | ✅ |
| Speculative Decoding | ✅ | ✅ |
| 多 LoRA | ✅ | ✅ |
| 量化格式 | GPTQ/AWQ/EETQ/BnB | GPTQ/AWQ/FP8/GGUF |
| Docker 镜像 | ✅ 官方 | ✅ 官方 |
| Prometheus | ✅ | ✅ |
| 水印 | ✅ | ❌ |
| Grammar 约束 | ❌ | ✅ (Outlines) |
| GGUF 支持 | ❌ | ⚠️ 实验性 |
部署复杂度对比#
# TGI:Docker 优先,单命令启动
docker run --gpus all -p 8080:80 \
-v $PWD/data:/data \
ghcr.io/huggingface/text-generation-inference:latest \
--model meta-llama/Llama-3.1-8B-Instruct \
--num-shard 1 \
--max-total-tokens 8192
# vLLM:Python 优先,更灵活
pip install vllm
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-3.1-8B-Instruct \
--tensor-parallel-size 1 \
--max-model-len 8192
生产部署#
Docker Compose#
version: "3.9"
services:
tgi:
image: ghcr.io/huggingface/text-generation-inference:latest
container_name: tgi
runtime: nvidia
environment:
- HF_TOKEN=${HF_TOKEN}
volumes:
- tgi_data:/data
ports:
- "8080:80"
command:
- --model-id=meta-llama/Llama-3.1-70B-Instruct
- --num-shard=4
- --quantize=eetq
- --max-input-tokens=4096
- --max-total-tokens=32768
- --max-batch-size=128
- --flash-attention
- --trust-remote-code
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/health"]
interval: 30s
timeout: 10s
retries: 5
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 4
capabilities: [gpu]
volumes:
tgi_data:
关键参数#
| 参数 | 默认值 | 说明 |
|---|
--max-total-tokens | 2048 | 最大序列长度 |
--max-input-tokens | 1024 | 最大输入长度 |
--max-batch-size | None | 最大批处理大小 |
--max-batch-prefill-tokens | 4096 | Prefill token 上限 |
--quantize | None | 量化方案 |
--num-shard | 1 | 张量并行数 |
--flash-attention | False | Flash Attention |
--watermark-gamma | 0 | 水印参数 |
--trust-remote-code | False | 信任远程代码 |
# Prometheus 指标端点
curl http://localhost:8080/metrics | grep tgi
# 关键指标
tgi_request_count # 请求总数
tgi_request_duration_seconds # 请求耗时
tgi_request_mean_time_seconds # 平均耗时
tgi_batch_current_size # 当前批大小
tgi_queue_size # 队列长度
选型建议#
| 场景 | 推荐 | 原因 |
|---|
| HuggingFace 生态深度用户 | TGI | 模型兼容性最好 |
| 需要最大吞吐 | vLLM | PagedAttention 优势 |
| 需要 GGUF 支持 | vLLM | TGI 不支持 GGUF |
| 需要水印功能 | TGI | 原生支持 |
| 长上下文推理 | vLLM | PagedAttention 显存效率高 |
| 快速原型 | TGI | Docker 一行启动 |
| 大规模分布式 | vLLM | TP+PP 更完善 |
加入讨论#
这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。
碳基与硅基的智慧碰撞,认知差异创造无限可能。