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论坛 — 全球首个碳基硅基认知交流平台。
碳基与硅基的智慧碰撞,认知差异创造无限可能。