LLM 推理优化
"推理成本是 AI 落地的最大障碍之一。"
LLM 推理优化 是在保持模型输出质量的前提下,提升推理速度、降低延迟、减少成本的技术集合。随着 LLM 应用规模扩大,推理优化已成为生产部署的核心挑战。
一、推理优化概览
1.1 优化目标
| 目标 | 指标 | 业务价值 |
|---|---|---|
| 降低延迟 | TTFT, TPS | 提升用户体验 |
| 提高吞吐 | Requests/s | 服务更多用户 |
| 减少成本 | $/1M tokens | 降低运营成本 |
| 节省资源 | GPU 内存, 计算量 | 更低硬件要求 |
1.2 推理延迟组成
关键指标:
| 指标 | 全称 | 说明 |
|---|---|---|
| TTFT | Time To First Token | 首个 Token 产生的时间 |
| TPOT | Time Per Output Token | 每个输出 Token 的生成时间 |
| TPS | Tokens Per Second | 每秒生成的 Token 数 |
| Throughput | Requests/sec | 每秒处理的请求数 |
二、推理参数详解
2.1 采样参数
| 参数 | 作用 | 范围 | 影响 |
|---|---|---|---|
| temperature | 控制随机性 | 0.0-2.0 | 越高越随机/创意 |
| top_p | 核采样阈值 | 0.0-1.0 | 累积概率截断 |
| top_k | 候选 Token 数 | 1-100+ | 限制选择范围 |
| max_tokens | 最大生成长度 | 1-∞ | 输出长度上限 |
| presence_penalty | 出现惩罚 | -2.0-2.0 | 减少重复 |
| frequency_penalty | 频率惩罚 | -2.0-2.0 | 降低高频词 |
2.2 Temperature 深入理解
Temperature 对概率分布的影响:
原始概率: [0.5, 0.3, 0.15, 0.05]
Temperature = 0.5 (更确定):
[0.7, 0.2, 0.08, 0.02] → 高概率词更突出
Temperature = 1.0 (原始):
[0.5, 0.3, 0.15, 0.05] → 保持原分布
Temperature = 1.5 (更随机):
[0.4, 0.3, 0.2, 0.1] → 分布更平均2.3 任务场景推荐配置
| 任务类型 | Temperature | Top-P | Top-K | 说明 |
|---|---|---|---|---|
| 代码生成 | 0.0-0.2 | 0.1-0.3 | 1-10 | 需要精确性 |
| 问答/摘要 | 0.3-0.5 | 0.3-0.5 | 10-30 | 平衡准确与流畅 |
| 对话聊天 | 0.7-0.9 | 0.8-0.9 | 30-50 | 自然多样 |
| 创意写作 | 0.9-1.2 | 0.9-0.95 | 50-100 | 鼓励创意 |
| 头脑风暴 | 1.0-1.5 | 0.95 | 100+ | 最大多样性 |
最佳实践
- 主要调整 Temperature 或 Top-P,不建议同时大幅调整
- 代码/事实类任务:Temperature ≈ 0
- 创意任务:Temperature 0.8-1.2
三、量化技术
3.1 量化原理
将模型参数从高精度(FP32/FP16)转换为低精度(INT8/INT4):
原始权重 (FP16): 2 bytes/参数
↓
量化 (INT8): 1 byte/参数 → 50% 内存节省
量化 (INT4): 0.5 byte/参数 → 75% 内存节省3.2 主流量化方法
| 方法 | 精度 | 内存节省 | 精度损失 | 适用场景 |
|---|---|---|---|---|
| FP16/BF16 | 16-bit | 基准 | 无 | 标准推理 |
| INT8 | 8-bit | 50% | 极小 | 通用优化 |
| GPTQ | 4-bit | 75% | 小 | 离线量化 |
| AWQ | 4-bit | 75% | 小 | 激活感知 |
| GGUF | 2-8 bit | 可变 | 可变 | llama.cpp |
| FP8 | 8-bit | 50% | 极小 | Hopper GPU |
| NF4 | 4-bit | 75% | 小 | QLoRA |
3.3 量化效果示例
以 Llama 3.1 70B 为例:
| 精度 | 显存需求 | 速度变化 | 质量影响 |
|---|---|---|---|
| FP16 | ~140GB | 基准 | 基准 |
| INT8 | ~70GB | +20-30% | <1% 下降 |
| INT4 (AWQ) | ~35GB | +50-100% | 1-3% 下降 |
| INT4 (GPTQ) | ~35GB | +40-80% | 2-4% 下降 |
3.4 量化工具
python
# 使用 AutoGPTQ 进行量化
from transformers import AutoTokenizer
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig
# 定义量化配置
quantize_config = BaseQuantizeConfig(
bits=4, # 4-bit 量化
group_size=128, # 分组大小
desc_act=True # 激活降序排列
)
# 加载模型并量化
model = AutoGPTQForCausalLM.from_pretrained(
"meta-llama/Llama-3.1-8B",
quantize_config
)
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.1-8B")
# 执行量化
model.quantize(calibration_data)
# 保存量化模型
model.save_quantized("./llama-3.1-8b-gptq")四、KV Cache 优化
4.1 KV Cache 原理
Transformer 在 Attention 计算中需要保存历史 Token 的 Key 和 Value:
没有 KV Cache:
每生成一个 Token,重新计算所有历史 Token 的 KV
→ 时间复杂度 O(n²)
有 KV Cache:
缓存已计算的 KV,只计算新 Token 的 KV
→ 时间复杂度 O(n)4.2 KV Cache 内存占用
KV Cache 大小 = 2 × num_layers × hidden_size × seq_len × batch_size × precision
示例 (Llama 3.1 70B, FP16, seq=4096):
= 2 × 80 × 8192 × 4096 × 1 × 2 bytes
≈ 10.7 GB / 请求4.3 KV Cache 优化技术
| 技术 | 原理 | 效果 |
|---|---|---|
| PagedAttention | 分页管理,减少碎片 | 内存利用率 +50% |
| KV Cache 量化 | 压缩至 INT8/INT4 | 内存减少 50-75% |
| MQA/GQA | 共享 KV 头 | 内存减少 50-90% |
| Sliding Window | 限制注意力窗口 | 固定内存占用 |
| Prefix Caching | 复用公共前缀 | 减少重复计算 |
4.4 PagedAttention (vLLM)
五、推理引擎对比
5.1 主流推理引擎
| 引擎 | 提供商 | 特点 | 适用场景 |
|---|---|---|---|
| vLLM | 开源 | 灵活、PagedAttention、多硬件 | 通用生产部署 |
| TensorRT-LLM | NVIDIA | 极致性能、NVIDIA 优化 | NVIDIA GPU 高性能 |
| SGLang | 开源 | 结构化生成、RadixAttention | 结构化输出 |
| llama.cpp | 开源 | CPU/Apple Silicon、量化 | 边缘设备 |
| Ollama | 开源 | 简单易用、本地部署 | 开发测试 |
| Text Generation Inference | Hugging Face | 生产就绪、Flash Attention | HF 生态集成 |
5.2 vLLM vs TensorRT-LLM
| 方面 | vLLM | TensorRT-LLM |
|---|---|---|
| 部署复杂度 | 低 | 中 |
| NVIDIA 优化 | 好 | 极致 |
| 多硬件支持 | 广泛 | 仅 NVIDIA |
| 灵活性 | 高 | 中 |
| 量化支持 | AWQ, GPTQ | FP8, INT8, INT4 |
| 最佳场景 | 灵活部署、混合负载 | 高吞吐稳定负载 |
5.3 vLLM 使用示例
python
from vllm import LLM, SamplingParams
# 初始化模型
llm = LLM(
model="meta-llama/Llama-3.1-8B-Instruct",
tensor_parallel_size=2, # 2 GPU 并行
gpu_memory_utilization=0.9, # GPU 内存利用率
max_model_len=8192, # 最大序列长度
quantization="awq" # 使用 AWQ 量化
)
# 采样参数
sampling_params = SamplingParams(
temperature=0.7,
top_p=0.9,
max_tokens=512
)
# 批量推理
prompts = [
"解释什么是机器学习",
"Python 和 JavaScript 的区别",
"写一首关于 AI 的诗"
]
outputs = llm.generate(prompts, sampling_params)
for output in outputs:
print(f"Prompt: {output.prompt}")
print(f"Generated: {output.outputs[0].text}\n")5.4 启动 vLLM 服务器
bash
# 使用 OpenAI 兼容 API 启动
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-3.1-8B-Instruct \
--tensor-parallel-size 2 \
--gpu-memory-utilization 0.9 \
--max-model-len 8192 \
--port 8000python
# 客户端调用
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="dummy")
response = client.chat.completions.create(
model="meta-llama/Llama-3.1-8B-Instruct",
messages=[{"role": "user", "content": "Hello!"}],
temperature=0.7
)六、高级优化技术
6.1 Speculative Decoding(投机解码)
使用小模型预测,大模型验证:
| 组件 | 作用 | 示例 |
|---|---|---|
| Draft Model | 快速生成候选 | Llama 3.1 8B |
| Target Model | 验证正确性 | Llama 3.1 70B |
| 加速比 | 通常 1.5-2x | 取决于接受率 |
6.2 Continuous Batching(连续批处理)
传统 Static Batching:
Request 1: [████████]
Request 2: [████░░░░] ← padding 浪费
Request 3: [██░░░░░░] ← padding 浪费
全部完成后才返回
Continuous Batching:
Request 1: [████████] → 完成即返回
Request 2: [████] → 新请求加入
Request 3: [██] → 动态调整优势:
- 吞吐量提升 10-50x
- 减少排队等待
- 更高 GPU 利用率
6.3 FlashAttention
优化 Attention 计算的内存访问:
| 特性 | FlashAttention 1 | FlashAttention 2 | FlashAttention 3 |
|---|---|---|---|
| 内存 | 减少 5-20x | 进一步优化 | 最优 |
| 速度 | 2-4x | 2x+ | for Hopper |
| 硬件 | Ampere+ | Ampere+ | Hopper |
6.4 Multi-Query/Grouped-Query Attention
减少 KV Cache 大小:
| 方法 | KV 头数 | 内存节省 | 质量影响 |
|---|---|---|---|
| MHA | = Query 头数 | 基准 | 基准 |
| MQA | 1 | ~90% | 可能有损 |
| GQA | Query 头数 / n | ~50-80% | 接近 MHA |
七、成本优化策略
7.1 Token 成本分析
API 调用成本 = 输入 Token × 输入价格 + 输出 Token × 输出价格
示例 (GPT-4o):
- 输入: $2.5/M tokens
- 输出: $10/M tokens
1000 次对话 (平均 500 输入 + 200 输出):
= 1000 × (500 × $2.5/M + 200 × $10/M)
= $1.25 + $2.00 = $3.257.2 成本优化方法
| 策略 | 节省幅度 | 实施难度 | 说明 |
|---|---|---|---|
| Prompt 压缩 | 20-50% | 低 | 精简 Prompt,减少 Token |
| 缓存复用 | 30-70% | 中 | 相似请求复用结果 |
| 模型路由 | 40-60% | 中 | 简单问题用小模型 |
| 批量处理 | 20-40% | 低 | 合并请求减少开销 |
| 自托管 | 50-80% | 高 | 大规模时更经济 |
| 量化部署 | 30-50% | 中 | 降低计算资源需求 |
7.3 智能路由架构
7.4 缓存策略
| 缓存类型 | 命中场景 | 节省效果 |
|---|---|---|
| 精确缓存 | 完全相同的请求 | 100% |
| 语义缓存 | 语义相似的请求 | 80-95% |
| 前缀缓存 | 相同系统提示 | 30-50% |
| KV 缓存共享 | 相同上下文 | 50-80% |
python
# 语义缓存示例
from langchain.cache import SemanticCache
from langchain.embeddings import OpenAIEmbeddings
# 初始化语义缓存
cache = SemanticCache(
embedding=OpenAIEmbeddings(),
similarity_threshold=0.95
)
# 设置全局缓存
langchain.llm_cache = cache八、部署架构
8.1 单机部署
yaml
# docker-compose.yml
version: '3.8'
services:
vllm:
image: vllm/vllm-openai:latest
runtime: nvidia
environment:
- NVIDIA_VISIBLE_DEVICES=all
ports:
- "8000:8000"
volumes:
- ./models:/models
command: >
--model /models/Llama-3.1-8B-Instruct
--tensor-parallel-size 1
--gpu-memory-utilization 0.98.2 多 GPU 并行策略
| 策略 | 适用场景 | 通信开销 |
|---|---|---|
| Tensor Parallelism | 单机多 GPU | 低 |
| Pipeline Parallelism | 跨节点 | 中 |
| Data Parallelism | 多副本 | 低 |
| 组合策略 | 大规模部署 | 可变 |
bash
# 4 GPU Tensor Parallel
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-3.1-70B-Instruct \
--tensor-parallel-size 4 \
--port 80008.3 生产部署架构
8.4 Kubernetes 部署
yaml
# vllm-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: vllm-inference
spec:
replicas: 3
selector:
matchLabels:
app: vllm
template:
metadata:
labels:
app: vllm
spec:
containers:
- name: vllm
image: vllm/vllm-openai:latest
resources:
limits:
nvidia.com/gpu: 2
ports:
- containerPort: 8000
args:
- "--model"
- "meta-llama/Llama-3.1-8B-Instruct"
- "--tensor-parallel-size"
- "2"
---
apiVersion: v1
kind: Service
metadata:
name: vllm-service
spec:
selector:
app: vllm
ports:
- port: 80
targetPort: 8000
type: LoadBalancer九、监控与调优
9.1 关键监控指标
| 指标 | 描述 | 目标值 |
|---|---|---|
| TTFT | 首 Token 延迟 | < 500ms |
| TPS | 每秒 Token 数 | > 50 |
| GPU 利用率 | GPU 计算利用率 | > 80% |
| GPU 内存 | 显存使用率 | 80-95% |
| 队列长度 | 等待请求数 | < 10 |
| 错误率 | 失败请求比例 | < 0.1% |
9.2 Prometheus 指标
yaml
# 常用 vLLM 指标
- vllm:num_requests_running # 运行中请求数
- vllm:num_requests_waiting # 等待中请求数
- vllm:gpu_cache_usage_perc # KV Cache 使用率
- vllm:avg_prompt_throughput # 平均 Prompt 吞吐
- vllm:avg_generation_throughput # 平均生成吞吐9.3 性能调优检查清单
□ GPU 内存利用率是否在 80-95%?
□ 是否启用了量化(AWQ/GPTQ)?
□ 是否启用了 FlashAttention?
□ 批处理大小是否合适?
□ 是否启用了 Prefix Caching?
□ 是否配置了合理的 max_model_len?
□ 是否使用了 Continuous Batching?
□ 网络延迟是否在可接受范围?十、成本估算模板
10.1 自托管 vs API 对比
| 场景 | 自托管成本/月 | API 成本/月 | 推荐 |
|---|---|---|---|
| 小规模 (<1M tokens/天) | $500+ | $50-200 | API |
| 中规模 (1-10M tokens/天) | $1,000-3,000 | $500-5,000 | 视情况 |
| 大规模 (>10M tokens/天) | $3,000-10,000 | $5,000-50,000 | 自托管 |
10.2 GPU 成本参考
| GPU | 显存 | 可运行模型 | 云租赁/小时 |
|---|---|---|---|
| RTX 4090 | 24GB | 7B-13B FP16, 70B INT4 | $0.5-1.5 |
| A100 40GB | 40GB | 13B-30B FP16, 70B INT8 | $2-4 |
| A100 80GB | 80GB | 70B FP16 | $3-5 |
| H100 80GB | 80GB | 70B FP16 + 优化 | $4-8 |
十一、2025-2026 趋势
| 趋势 | 说明 |
|---|---|
| FP4/NF4 量化 | 更低精度,更小模型 |
| 硬件专用加速 | AI 专用芯片普及 |
| KV Cache 智能管理 | 预测性缓存、跨请求共享 |
| 边缘推理 | 本地设备运行中型模型 |
| 推理即服务成熟 | Serverless LLM 推理 |
| 多模态推理优化 | 图像、视频、音频协同 |
十二、学习资源
12.1 推理引擎文档
| 资源 | 链接 |
|---|---|
| vLLM | docs.vllm.ai |
| TensorRT-LLM | nvidia.github.io/TensorRT-LLM |
| SGLang | github.com/sgl-project/sglang |
| llama.cpp | github.com/ggerganov/llama.cpp |
12.2 论文
| 论文 | 贡献 |
|---|---|
| vLLM: PagedAttention | 高效 KV Cache 管理 |
| FlashAttention 2 | 快速 Attention |
| Speculative Decoding | 投机解码加速 |
核心建议
- 先量化:4-bit 量化是性价比最高的优化
- 用 vLLM:开箱即用的生产级推理引擎
- 启用缓存:Prefix Caching 对重复前缀很有效
- 监控优先:没有监控就没有优化