文章摘要
2026 年,LLM 推理优化已经从单一的模型量化发展为涵盖架构设计、调度策略、内存管理、硬件协同的全栈工程。本文系统梳理 LLM 推理优化的完整技术图谱:Prefill-Decode 分离架构(PD Separation)、投机解码(Speculative Decoding)、PagedAttention v2、动态批处理、KV Cache 压缩、以及 vLLM/TensorRT-LLM/SGLang 三大推理引擎的深度对比与选型指南。
1LLM 推理的性能瓶颈:为什么推理比训练更难优化?
LLM 推理的核心矛盾是「内存带宽瓶颈」。与训练阶段不同,推理阶段每次生成一个 token 时,需要将整个模型权重从显存加载到计算单元——但只执行一次矩阵-向量乘法。这意味着计算单元大部分时间在等待数据搬运,而非执行计算。
用一个直观的比喻:训练像是在工厂里批量生产——原材料(数据)和生产线(GPU 计算单元)都在工厂里,生产效率很高。推理像是快递配送——每次只送一个包裹(一个 token),但快递员必须跑遍整个仓库(遍历所有模型权重)才能找到那个包裹。
LLM 推理的两个阶段有不同的瓶颈:
Prefill 阶段(预填充):处理用户输入的 prompt,是一次大规模的矩阵-矩阵乘法(GEMM)。这个阶段的瓶颈是计算吞吐量——需要快速处理数千到数万 token 的输入。
Decode 阶段(解码):逐个生成输出 token,每次只处理一个 token。这个阶段的瓶颈是内存带宽——每个 token 生成都需要读取全部模型权重,但计算量极小。
这种两阶段的不同特性催生了 2026 年最重要的推理优化架构——Prefill-Decode 分离(PD Separation)。
关键指标:
- TTFT(Time To First Token):首 token 延迟,由 Prefill 阶段决定
- TPOT(Time Per Output Token):每 token 生成时间,由 Decode 阶段决定
- 吞吐量(Throughput):单位时间处理的请求数
- 成本效率(Cost per Million Tokens):每百万 token 的推理成本
💡 一句话理解
理解 LLM 推理优化的第一步:区分 Prefill 和 Decode 阶段的不同瓶颈。Prefill 是计算密集型(compute-bound),Decode 是内存带宽密集型(memory-bound)。不同的优化技术针对不同的阶段。
2Prefill-Decode 分离架构:2026 年推理部署的标准范式
PD 分离(Prefill-Decode Separation)是 2026 年 LLM 推理部署最重要的架构创新。其核心思想是:将 Prefill 阶段和 Decode 阶段部署在不同的 GPU 上,因为两个阶段对硬件的需求完全不同。
Prefill 阶段需要高计算吞吐量。处理一个 4K token 的 prompt 需要数百 TFLOPs 的计算量。最适合的硬件是高算力 GPU(如 NVIDIA H200、B200),这些 GPU 的 FP8 算力可达数千 TFLOPs。
Decode 阶段需要高内存带宽。每生成一个 token 需要读取整个模型权重。对于 70B 参数的模型(INT4 量化后约 35GB),每 token 需要读取 35GB 数据。最适合的硬件是高内存带宽 GPU(如 NVIDIA H200 的 4.8TB/s HBM3e 带宽)。
分离架构的工作流程:
- 用户请求到达 Prefill 节点
- Prefill 节点处理完整 prompt,生成 KV Cache
- KV Cache 通过高速互联(NVLink/NVSwitch)传输到 Decode 节点
- Decode 节点逐个生成输出 token
- 生成的 token 流式返回给用户
性能提升:在典型的 70B 模型部署中,PD 分离架构相比混合部署可以提升 2-3 倍的吞吐量,同时将 TTFT 降低 40-60%。这是因为 Prefill 和 Decode 不再争抢同一块 GPU 的计算和内存资源。
Disaggregated Serving 的进阶形态。2026 年的最新进展是完全解耦的推理服务——Prefill 池和 Decode 池可以独立扩缩容,甚至可以使用不同类型的 GPU。例如:Prefill 用 H100(高算力),Decode 用 L40S(高内存带宽、低成本)。
"""
Prefill-Decode 分离架构部署配置
使用 vLLM 0.8 的 PD 分离模式
"""
from vllm import LLM, SamplingParams
from vllm.distributed import PDSeparationConfig
# ── 1. Prefill 节点配置 ──
prefill_config = {
"model": "meta-llama/Llama-4-70B-Instruct",
"tensor_parallel_size": 4, # 4 卡张量并行
"gpu_memory_utilization": 0.95,
"max_model_len": 32768,
"dtype": "bfloat16",
"kv_transfer_config": {
"role": "prefill", # Prefill 角色
"connector": "nccl", # 使用 NCCL 传输 KV Cache
"target_nodes": ["decode-0", "decode-1", "decode-2"],
},
# Prefill 专用优化
"enable_chunked_prefill": True, # 分块 Prefill(减少内存峰值)
"chunk_size": 2048, # 每块 2048 tokens
"scheduler": "prefill_optimized", # Prefill 优化的调度策略
}
# ── 2. Decode 节点配置 ──
decode_config = {
"model": "meta-llama/Llama-4-70B-Instruct",
"tensor_parallel_size": 2, # Decode 只需 2 卡
"gpu_memory_utilization": 0.90,
"max_model_len": 32768,
"dtype": "bfloat16",
"kv_transfer_config": {
"role": "decode", # Decode 角色
"connector": "nccl",
"source_nodes": ["prefill-0"],
},
# Decode 专用优化
"speculative_config": {
"model": "meta-llama/Llama-4-8B-Instruct", # 8B 草稿模型
"num_speculative_tokens": 6, # 每次推测 6 个 token
"acceptance_threshold": 0.7, # 接受率阈值
},
"scheduler": "decode_optimized", # Decode 优化的调度策略
"max_batch_size": 256, # 更大的批处理大小
}
# ── 3. 启动 PD 分离服务 ──
def start_pd_separation_service():
"""启动 PD 分离推理服务"""
# 启动 Prefill 节点
prefill_engine = LLM(
**prefill_config,
worker_cls="vllm.worker.PrefillWorker",
)
# 启动 Decode 节点(可多实例)
decode_engines = []
for i in range(3):
engine = LLM(
**decode_config,
worker_cls="vllm.worker.DecodeWorker",
)
decode_engines.append(engine)
# 启动负载均衡器
from vllm.serving import PDRouter
router = PDRouter(
prefill_engines=[prefill_engine],
decode_engines=decode_engines,
routing_strategy="min_decode_queue", # 路由到队列最短的 Decode 节点
health_check_interval=5,
)
# 启动 API 服务
router.serve(
host="0.0.0.0",
port=8000,
api_type="openai", # 兼容 OpenAI API
)
# ── 4. 性能监控 ──
class PDMetrics:
"""PD 分离架构的性能指标"""
def __init__(self):
self.metrics = {
"prefill_latency_ms": [], # Prefill 延迟
"decode_latency_per_token": [], # 每 token 解码延迟
"ttft_ms": [], # 首 token 延迟
"throughput_tokens_per_sec": [], # 吞吐量
"kv_transfer_ms": [], # KV Cache 传输延迟
"spec_acceptance_rate": [], # 投机解码接受率
}
def report(self):
"""生成性能报告"""
import numpy as np
report = {}
for key, values in self.metrics.items():
if values:
report[key] = {
"mean": np.mean(values),
"p50": np.percentile(values, 50),
"p99": np.percentile(values, 99),
}
print("═══ PD 分离架构性能报告 ═══")
for metric, stats in report.items():
print(f"{metric}:")
print(f" 均值: {stats['mean']:.2f}")
print(f" P50: {stats['p50']:.2f}")
print(f" P99: {stats['p99']:.2f}")
return report💡 一句话理解
⚠️ 常见踩坑
KV Cache 在 Prefill 和 Decode 节点之间的传输需要高速互联。NVLink/NVSwitch 是必须的——如果用 PCIe 或网络传输 KV Cache,传输延迟会抵消 PD 分离带来的收益。在同一台机器上至少需要 NVLink 连接的 GPU。
3投机解码(Speculative Decoding):用 8B 模型加速 70B 模型
投机解码是 2026 年最实用的推理加速技术。其核心思想极其巧妙:用一个小的「草稿模型」(Draft Model)快速生成多个候选 token,然后用大的「目标模型」(Target Model)一次性验证这些 token 是否正确。
为什么这能加速? 因为大模型验证 N 个 token 的时间几乎等于生成 1 个 token 的时间——两者都需要读取完整的模型权重。如果草稿模型的预测有 70% 的接受率,那么每次验证 6 个 token,平均可以接受 4.2 个,相当于将 Decode 速度提升了 4 倍。
投机解码的数学原理:
假设草稿模型生成了 token 序列 [t₁, t₂, t₃, t₄, t₅, t₆],目标模型需要验证每个 token。验证方法是:对于第 i 个位置,比较草稿模型的概率分布 q(t|x₁...xᵢ₋₁) 和目标模型的概率分布 p(t|x₁...xᵢ₋₁)。
接受-拒绝采样规则:
- 以概率 min(1, p(tᵢ)/q(tᵢ)) 接受 tᵢ
- 一旦某个 token 被拒绝,后续所有 token 全部丢弃
- 从拒绝位置开始,用目标模型重新采样
关键洞察:这个采样方案保证了输出分布与不使用投机解码时完全相同——投机解码是一种无损加速技术。
2026 年的投机解码变体:
- EAGLE 3.1(2026 年 5 月):解决「注意力漂移」问题,通过注意力对齐训练将接受率从 60% 提升到 75%,实现 2.0x 加速。已与 vLLM 0.20.0 深度集成,支持 CUDA Graph 预编译和 KV Cache 共享
- 自投机解码(Self-Speculative):不使用独立草稿模型。Meta 2026 年 5 月发布的 SpecGen 提出 PillarAttn 稀疏注意力机制,让目标模型以 1/3 计算量生成草稿,接受率 70%
- 草稿模型缓存(Draft Cache):将草稿模型的 KV Cache 缓存在显存中,避免重复计算
- 自适应投机长度:根据草稿模型的置信度动态决定推测多少个 token
- 多头投机(Multi-Head Speculative):同时运行多个草稿模型,取接受率最高的结果
- SpecDiff-2(MLSys 2026):用离散扩散模型作为非自回归草稿,解决自回归草稿的并行性瓶颈和模型对齐问题
4PagedAttention v2 与 KV Cache 内存管理
KV Cache 是 LLM 推理中最被低估的内存消耗者。对于一个 70B 参数的模型,在 32K 上下文长度下,单个请求的 KV Cache 可能占用 2-4 GB 显存——几乎与模型权重本身相当。如果有 100 个并发请求,KV Cache 将占用 200-400 GB 显存。
PagedAttention(2023 年 vLLM 首次提出)的核心思想是将 KV Cache 分块管理,类似于操作系统的虚拟内存分页。2026 年的 PagedAttention v2 在三个方面有了重大升级:
动态分页粒度。v1 使用固定的页大小(如 16 token),v2 根据注意力头的实际访问模式动态调整页大小。对于长上下文(>16K token),使用更大的页(64 token)减少页表开销;对于短上下文,使用小页(8 token)减少内存浪费。
跨请求 KV Cache 共享。如果多个请求共享相同的 system prompt(这在生产环境中非常常见),PagedAttention v2 可以让它们共享同一份 KV Cache 页,而不是为每个请求重复计算和存储。这在多轮对话场景中可以将 KV Cache 的内存占用降低 50-80%。
KV Cache 压缩。v2 支持将 KV Cache 从 FP16 压缩到 INT4/INT8,在可接受的精度损失下(<1% 的 perplexity 增加)将 KV Cache 的内存占用减少 4-8 倍。压缩算法使用 per-channel 量化,对 Key 和 Value 使用不同的量化策略(Key 对精度更敏感,使用 INT8;Value 可以使用 INT4)。
内存预算管理。PagedAttention v2 引入了KV Cache 内存预算的概念——为每个请求分配固定的 KV Cache 预算,当预算耗尽时,使用「注意力稀疏化」策略只保留最重要的注意力头/位置,而非简单地截断上下文。
"""
KV Cache 优化:PagedAttention v2 配置
"""
from vllm import LLM, SamplingParams
# ── 1. PagedAttention v2 配置 ──
llm = LLM(
model="meta-llama/Llama-4-70B-Instruct",
tensor_parallel_size=4,
# PagedAttention v2 配置
block_manager_config={
"version": "v2", # 使用 v2 分页管理
"block_size": "dynamic", # 动态分页粒度
"min_block_size": 8, # 最小页大小
"max_block_size": 64, # 最大页大小
"enable_prefix_sharing": True, # 跨请求前缀共享
"prefix_sharing_strategy": "radix", # 基于 Radix Tree 的共享
},
# KV Cache 压缩
kv_cache_config={
"dtype": "auto", # 原始精度(跟随模型)
"compression": {
"enabled": True,
"key_dtype": "int8", # Key 用 INT8
"value_dtype": "int4", # Value 用 INT4
"calibration_method": "minmax", # 量化校准方法
"group_size": 128, # 分组量化大小
},
# 内存预算
"memory_budget_gb": 40, # KV Cache 总预算 40GB
"per_request_budget_gb": 2, # 每个请求预算 2GB
"eviction_policy": "lru", # 淘汰策略
},
# 注意力稀疏化(当 KV Cache 预算耗尽时)
attention_config={
"sparse_attention": {
"enabled": True,
"strategy": "topk_heads", # 保留最重要的注意力头
"keep_ratio": 0.7, # 保留 70% 的头
"trigger_threshold": 0.9, # 内存使用 >90% 时触发
},
},
gpu_memory_utilization=0.95,
max_model_len=32768,
)
# ── 2. 前缀共享效果演示 ──
def demo_prefix_sharing():
"""演示跨请求前缀共享的内存节省"""
# 共享的 System Prompt(约 2000 tokens)
system_prompt = "你是一个专业的 AI 助手..."
# 多个用户请求(共享同一个 system prompt)
requests = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": "解释量子计算"},
]
requests_2 = [
{"role": "system", "content": system_prompt}, # 相同!
{"role": "user", "content": "解释相对论"},
]
# 不使用前缀共享:每个请求独立计算 system prompt 的 KV Cache
# 内存占用:2 × KV(system_prompt) + KV(user_1) + KV(user_2)
# 使用前缀共享:system prompt 的 KV Cache 只计算一次
# 内存占用:1 × KV(system_prompt) + KV(user_1) + KV(user_2)
# 节省:约 2000 tokens 的 KV Cache
outputs = llm.chat(requests, SamplingParams(temperature=0.7))
outputs_2 = llm.chat(requests_2, SamplingParams(temperature=0.7))
# 查看内存使用情况
cache_stats = llm.get_kv_cache_stats()
print(f"总页数: {cache_stats['total_pages']}")
print(f"共享页数: {cache_stats['shared_pages']}")
print(f"共享率: {cache_stats['shared_pages'] / cache_stats['total_pages']:.1%}")
print(f"节省内存: {cache_stats['saved_memory_gb']:.1f} GB")
# ── 3. KV Cache 压缩精度测试 ──
def test_kv_compression_accuracy():
"""测试 KV Cache 压缩对输出质量的影响"""
test_prompts = [
"解释 Transformer 的自注意力机制",
"写一首关于春天的诗",
"分析 2026 年 AI 芯片市场趋势",
]
# 无压缩基线
llm_fp16 = LLM(
model="meta-llama/Llama-4-70B-Instruct",
kv_cache_config={"compression": {"enabled": False}},
)
# INT8 Key + INT4 Value 压缩
llm_compressed = LLM(
model="meta-llama/Llama-4-70B-Instruct",
kv_cache_config={"compression": {
"enabled": True,
"key_dtype": "int8",
"value_dtype": "int4",
}},
)
for prompt in test_prompts:
out_fp16 = llm_fp16.generate(prompt)
out_comp = llm_compressed.generate(prompt)
# 计算输出相似度
similarity = compute_semantic_similarity(out_fp16, out_comp)
print(f"Prompt: {prompt[:30]}...")
print(f" 语义相似度: {similarity:.3f}")
print(f" 内存节省: {get_memory_savings():.1f}x")💡 一句话理解
前缀共享(Prefix Sharing)在多轮对话和共享 System Prompt 的场景中效果极佳。如果你的应用有固定的 System Prompt(如角色扮演、专业助手),务必开启前缀共享——它可以节省 50-80% 的 KV Cache 内存。
⚠️ 常见踩坑
KV Cache 压缩(INT4/INT8)会引入轻微的精度损失。对于大多数应用(聊天、摘要、代码生成),这种损失可以忽略(<1% perplexity 增加)。但对于需要精确数值推理的任务(如数学计算、数据分析),建议保持 FP16 KV Cache。
5推理引擎选型:vLLM vs TensorRT-LLM vs SGLang
2026 年的三大 LLM 推理引擎各有明确的定位和优势。选择正确的引擎可以将推理成本降低 2-5 倍。
vLLM 0.8:最通用的选择。vLLM 的优势在于模型兼容性最广(支持几乎所有开源模型)、社区最活跃、更新最快。0.8 版本引入了原生 PD 分离支持和 PagedAttention v2。适合大多数团队作为默认选择。
TensorRT-LLM 0.12:极致性能。NVIDIA 的 TensorRT-LLM 在 NVIDIA GPU 上可以实现最高的推理吞吐量,但代价是:只支持 NVIDIA GPU、模型支持范围较窄(主要是 Llama、Mistral、Qwen 等主流架构)、配置复杂。适合对性能有极致要求且使用 NVIDIA GPU 的场景。
SGLang 0.6:结构化生成的最佳选择。SGLang 的核心优势是结构化输出(JSON Schema、正则表达式约束)的性能——如果你的应用需要 LLM 输出严格符合 JSON Schema 的结果(如函数调用、数据提取),SGLang 比 vLLM 快 5-10 倍。
选型决策矩阵:
| 特性 | vLLM 0.8 | TensorRT-LLM 0.12 | SGLang 0.6 |
|---|---|---|---|
模型兼容性 | ⭐⭐⭐⭐⭐ 几乎所有 | ⭐⭐⭐ 主流架构 | ⭐⭐⭐⭐ 大多数 |
推理吞吐量 | ⭐⭐⭐⭐ 优秀 | ⭐⭐⭐⭐⭐ 极致 | ⭐⭐⭐⭐ 优秀 |
PD 分离 | ✅ 原生支持 | ✅ 支持 | ⚠️ 实验性 |
投机解码 | ✅ 支持 | ✅ 支持 | ✅ 支持 |
结构化输出 | ⭐⭐⭐ 一般 | ⭐⭐⭐ 一般 | ⭐⭐⭐⭐⭐ 极致 |
社区活跃度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
部署复杂度 | ⭐⭐⭐⭐⭐ 简单 | ⭐⭐⭐ 较复杂 | ⭐⭐⭐⭐ 简单 |
边缘部署 | ❌ 不支持 | ❌ 不支持 | ❌ 不支持 |
💡 一句话理解
如果你不确定选哪个,选 vLLM。它是 2026 年的「安全选择」——性能不是最好的,但足够好、兼容性最广、文档最全、社区最活跃。等你有了明确的性能瓶颈再考虑迁移到 TensorRT-LLM 或 SGLang。
6实战:构建百万级并发的 LLM 推理服务
本节以一个完整的案例演示如何构建支持百万级日活用户的 LLM 推理服务。
架构设计:采用三层架构——API 网关层(负载均衡 + 限流)、推理调度层(请求路由 + 批处理)、推理执行层(PD 分离的 GPU 集群)。
关键设计决策:
- 动态批处理(Dynamic Batching):将多个同时到达的请求合并为一个批次处理,提高 GPU 利用率。关键是设置合理的「最大等待时间」——等太久会增加延迟,等太短会降低批处理效率。
- 请求优先级队列:VIP 用户的请求优先处理,普通用户排队等待。
- 自动扩缩容:根据队列长度和 GPU 利用率自动增减 Decode 节点。
- 请求中断与恢复:用户取消请求时,立即释放其占用的 KV Cache 内存。
"""
生产级 LLM 推理服务架构
支持百万级日活、自动扩缩容、请求优先级
"""
import asyncio
from dataclasses import dataclass
from enum import Enum
from typing import Optional
import time
# ── 1. 请求模型 ──
@dataclass
class InferenceRequest:
request_id: str
prompt: str
max_tokens: int
temperature: float
priority: int # 0=VIP, 1=Normal, 2=Background
created_at: float = time.time()
user_id: Optional[str] = None
@property
def estimated_prefill_tokens(self) -> int:
"""估算 Prefill token 数"""
return len(self.prompt) // 4 # 粗略估算:4 字符 ≈ 1 token
# ── 2. 动态批处理器 ──
class DynamicBatcher:
"""动态批处理器:合并多个请求以提高 GPU 利用率"""
def __init__(
self,
max_batch_size: int = 256,
max_wait_ms: int = 10, # 最大等待时间 10ms
max_total_tokens: int = 128000, # 批次最大 token 数
):
self.max_batch_size = max_batch_size
self.max_wait_ms = max_wait_ms
self.max_total_tokens = max_total_tokens
self.pending_queue: list[InferenceRequest] = []
self.batch_ready_event = asyncio.Event()
async def submit(self, request: InferenceRequest):
"""提交请求到批处理队列"""
self.pending_queue.append(request)
# 按优先级排序(VIP 优先)
self.pending_queue.sort(key=lambda r: r.priority)
# 检查是否满足立即批处理条件
if self._should_flush():
self.batch_ready_event.set()
def _should_flush(self) -> bool:
"""判断是否应该立即发送批次"""
if not self.pending_queue:
return False
# 条件 1:队列已满
if len(self.pending_queue) >= self.max_batch_size:
return True
# 条件 2:token 总量达到上限
total_tokens = sum(r.estimated_prefill_tokens for r in self.pending_queue)
if total_tokens >= self.max_total_tokens:
return True
# 条件 3:等待时间超过阈值
oldest_request = self.pending_queue[0]
wait_time_ms = (time.time() - oldest_request.created_at) * 1000
if wait_time_ms >= self.max_wait_ms:
return True
return False
async def get_next_batch(self) -> list[InferenceRequest]:
"""获取下一个批次"""
while not self._should_flush():
self.batch_ready_event.clear()
await self.batch_ready_event.wait()
batch = self.pending_queue[:self.max_batch_size]
self.pending_queue = self.pending_queue[self.max_batch_size:]
return batch
# ── 3. 推理调度器 ──
class InferenceScheduler:
"""推理调度器:管理 PD 分离集群"""
def __init__(self):
self.batcher = DynamicBatcher()
self.prefill_nodes: list[str] = [] # Prefill 节点列表
self.decode_nodes: list[str] = [] # Decode 节点列表
self.node_load: dict[str, int] = {} # 节点负载
async def schedule_request(self, request: InferenceRequest):
"""调度单个请求"""
# 提交到批处理器
await self.batcher.submit(request)
async def run_serving_loop(self):
"""主服务循环"""
while True:
# 获取下一个批次
batch = await self.batcher.get_next_batch()
if not batch:
continue
# 选择 Prefill 节点(负载最低)
prefill_node = self._select_least_loaded_node("prefill")
# 执行 Prefill
kv_cache = await self._execute_prefill(prefill_node, batch)
# 选择 Decode 节点(队列最短)
decode_node = self._select_least_loaded_node("decode")
# 传输 KV Cache 并执行 Decode
results = await self._execute_decode(decode_node, batch, kv_cache)
# 返回结果
for request, result in zip(batch, results):
await self._send_response(request, result)
def _select_least_loaded_node(self, node_type: str) -> str:
"""选择负载最低的节点"""
nodes = self.prefill_nodes if node_type == "prefill" else self.decode_nodes
return min(nodes, key=lambda n: self.node_load.get(n, 0))
async def _execute_prefill(self, node, batch):
"""执行 Prefill 阶段"""
# 实际实现中调用 vLLM/TensorRT-LLM API
pass
async def _execute_decode(self, node, batch, kv_cache):
"""执行 Decode 阶段"""
pass
async def _send_response(self, request, result):
"""发送响应给用户"""
pass
# ── 4. 自动扩缩容 ──
class AutoScaler:
"""根据负载自动扩缩容 GPU 节点"""
def __init__(
self,
scheduler: InferenceScheduler,
min_decode_nodes: int = 2,
max_decode_nodes: int = 32,
target_gpu_utilization: float = 0.7,
scale_up_threshold: float = 0.85, # GPU 利用率 >85% 扩容
scale_down_threshold: float = 0.3, # GPU 利用率 <30% 缩容
cooldown_seconds: int = 300, # 扩缩容冷却时间 5 分钟
):
self.scheduler = scheduler
self.min_nodes = min_decode_nodes
self.max_nodes = max_decode_nodes
self.target_util = target_gpu_utilization
self.scale_up_threshold = scale_up_threshold
self.scale_down_threshold = scale_down_threshold
self.cooldown = cooldown_seconds
self.last_scale_time = 0
async def check_and_scale(self):
"""检查并执行扩缩容"""
current_time = time.time()
# 冷却期内不操作
if current_time - self.last_scale_time < self.cooldown:
return
# 计算平均 GPU 利用率
avg_util = self._get_avg_gpu_utilization()
queue_length = len(self.scheduler.batcher.pending_queue)
current_nodes = len(self.scheduler.decode_nodes)
if avg_util > self.scale_up_threshold and current_nodes < self.max_nodes:
# 扩容
new_nodes = self._calculate_scale_up_count(avg_util, queue_length)
await self._add_decode_nodes(new_nodes)
self.last_scale_time = current_time
print(f"🔼 扩容: +{new_nodes} 节点 (GPU util: {avg_util:.1%})")
elif avg_util < self.scale_down_threshold and current_nodes > self.min_nodes:
# 缩容
remove_count = self._calculate_scale_down_count(avg_util, current_nodes)
await self._remove_decode_nodes(remove_count)
self.last_scale_time = current_time
print(f"🔽 缩容: -{remove_count} 节点 (GPU util: {avg_util:.1%})")
def _get_avg_gpu_utilization(self) -> float:
"""获取平均 GPU 利用率"""
# 实际实现中通过 pynvml 或 DCGM 获取
return 0.0
def _calculate_scale_up_count(self, util, queue_len) -> int:
"""计算需要扩容的节点数"""
# 目标:将利用率降到 target_util
current_capacity = len(self.scheduler.decode_nodes)
needed_capacity = int(current_capacity * util / self.target_util) + 1
return min(needed_capacity - current_capacity, 4) # 每次最多加 4 个
def _calculate_scale_down_count(self, util, current_count) -> int:
"""计算需要缩容的节点数"""
target_capacity = max(int(current_count * util / self.target_util) + 1, self.min_nodes)
return min(current_count - target_capacity, 2) # 每次最多减 2 个
async def _add_decode_nodes(self, count: int):
"""添加 Decode 节点"""
pass
async def _remove_decode_nodes(self, count: int):
"""移除 Decode 节点(优雅关闭,等待当前请求完成)"""
pass💡 一句话理解
动态批处理的最大等待时间(max_wait_ms)是关键参数。对于交互式聊天应用,设置为 5-10ms;对于批量处理任务(如文档摘要),可以设置为 50-100ms 以获得更高的吞吐量。
⚠️ 常见踩坑
自动扩缩容必须设置冷却时间(建议 5 分钟)。没有冷却时间的扩缩容会在负载波动时频繁扩缩,导致 GPU 资源浪费和服务不稳定。
72026 年推理优化前沿与趋势
趋势一:TurboQuant — KV Cache 压缩的突破(ICLR 2026)
2026 年最重要的推理优化突破来自 KV Cache 压缩领域。 Google Research 在 ICLR 2026 上发表的 TurboQuant(arXiv:2504.19874)通过 Hadamard 旋转 + Lloyd-Max 最优标量量化,将 KV Cache 压缩到 3-3.5 bit,实现 6 倍压缩,同时在 3.5 bit 以上达到「统计等价于 bf16」的质量。
TurboQuant 的核心优势:
- 无需校准数据:不像 AWQ/GPTQ 需要跑校准数据集,TurboQuant 支持在线逐 token 压缩
- 已集成 vLLM 0.18.0+:通过
--kv-cache-dtype turboquant_k8v4一行启用 - 实测效果:RTX 5090 上 KV Cache 容量翻倍(457K→914K tokens),Decode 吞吐 +3.1%
- 多平台支持:NVIDIA(CUDA)、AMD(ROCm 6.4+)、DGX Spark(GB10)均已验证
vLLM 命名预设对比:
turboquant_k8v4:FP8 Keys + 4-bit Values,2.6x 压缩,PPL +1.17%(推荐生产使用)turboquant_4bit_nc:4-bit MSE Keys + 4-bit Values,3.8x 压缩,PPL +2.71%turboquant_3bit_nc:3-bit MSE Keys + 3-bit Values,4.9x 压缩,PPL +20.59%(实验性)
MLSys 2026 大会确认:KV Cache 已成为 LLM 推理的主导子系统,整个推理系统的设计正在围绕 KV Cache 管理重构。
趋势二:硬件-软件协同优化。NVIDIA Blackwell(B200/B300)引入了第二代 Transformer Engine,原生支持 FP4 精度推理。DGX Spark GB10 上 Qwen3.5-122B-A10B 实测:TurboQuant + NVFP4 组合让 128GB 统一内存可以处理 405K 上下文(bf16 KV 只能处理 155K)。
趋势三:推测预填充(Speculative Prefill)。在用户还在输入 prompt 时就开始推测性处理,实现「零延迟」首 token。
趋势四:KV Cache 即服务(KV Cache as a Service)。将 KV Cache 存储在独立内存集群中,支持多节点共享和请求无缝迁移。
趋势五:推理成本持续下降。2024 年 GPT-4 级别 $10/百万 token → 2026 年开源 70B 自托管 $0.3-0.5/百万 token,下降 20 倍。TurboQuant 等 KV Cache 压缩技术进一步将长上下文和高并发场景的成本压缩 2-6 倍。
趋势六:EAGLE 3.1 + TurboQuant 组合优化(2026 年 6 月实测)。vLLM 0.20.0 同时支持 EAGLE 3.1 推测解码和 TurboQuant KV Cache 压缩,两者组合效果显著:FP16+无推测 140GB/288 tokens/s → TurboQuant 3-bit+EAGLE 3.1 仅 38GB/640 tokens/s(2.2x 加速 + 3.7x 显存节省)。KV Cache 压缩减少了内存带宽压力,让推测解码的验证阶段更快。
趋势七:推测解码的超长上下文挑战。EAGLE 团队实测发现上下文超过 16K token 后注意力漂移加剧,接受率从 75% 降至 55%。建议超长上下文场景使用 Lookahead(n-gram 缓存)或 SpecGen(自推测)。
💡 一句话理解
2026 年实用建议:先用 FP8 KV(零成本 2x 压缩),不够再加 TurboQuant k8v4(2.6x,PPL 仅 +1.17%)。TurboQuant 与模型量化(AWQ/GPTQ)互补,两者叠加可支撑 4-5x 的上下文长度或并发数。
⚠️ 常见踩坑
推理优化的「免费午餐」已经吃完了。TurboQuant 3-bit 预设的 PPL 退化达 20.59%,社区共识是 3.5 bit 以上才能保持质量。不要盲目追求最高压缩比——根据你的应用场景,找到精度和成本的最佳平衡点。
82026 年 6 月最新进展:LCLM、MLSys 2026 与 NPU 推理
2026 年 6 月,推理优化领域迎来多项突破性进展。 从学术前沿到工程落地,每一个方向都在重新定义「推理效率」的边界。
8.1 LCLM:潜在上下文模型——16x 压缩无精度损失
VentureBeat 在 2026 年 6 月报道了一项可能改变推理经济学的突破:Latent Context Models(LCLM)。
LCLM 的核心思想是:与其在推理时处理完整的 1M token 上下文,不如将上下文压缩为潜在表示(latent representation),让模型在压缩空间中进行推理。
LCLM 的关键数据:
| 指标 | 标准 KV Cache | LCLM 16x 压缩 | 变化 |
|---|---|---|---|
| 1M 上下文显存占用 | > 80GB (H200 OOM) | ~5GB | ✅ 可运行 |
| 检索质量(NDCG@10) | 1.00(基准) | 0.97 | -3% |
| 推理延迟 | 100% | 62% | -38% |
| 最大可处理上下文 | 128K (H200) | 2M+ (H200) | 16x |
LCLM 的工程意义:
- 1M token 上下文不再需要特殊硬件——标准 H200 GPU 即可处理
- RAG 管道可以大幅简化——不再需要复杂的检索分块,直接喂入压缩后的全文
- 混合检索采用率飙升——VB Pulse Q1 2026 调查显示混合检索采用意向从 1 月的 10.3% 飙升至 3 月的 33.3%
局限性: LCLM 作者 Goldblum 坦承,推理链(reasoning trace)的在线压缩尚未验证。对于长推理链的 Agent 场景,这是一个独立的问题。
8.2 MLSys 2026 三大趋势
Modular 团队在 MLSys 2026 大会后总结了三大趋势:
趋势一:异构部署成为主流。 Meta 的 Industry Track 论文证实,即使在单模型部署中,将 Prefill 和 Decode 分配到不同类型的加速器上也能带来 15-25% 的 TCO 改善。原因是 Prefill 是计算密集型(偏好高 FLOP/s 的加速器),Decode 是内存带宽密集型(偏好高 HBM 带宽的加速器)。
趋势二:TriInfer——多模态的三阶段分离。 在 Multimodal 专题中,TriInfer 将 PD 分离扩展为 Encode-Prefill-Decode 三阶段,专门针对多模态工作负载优化。图像/音频编码、文本预填充和文本解码分别在不同硬件上执行。
趋势三:TokenWeave——分布式推理的通信优化。 TokenWeave 依赖 PyTorch SymmetricMemory API 和 NVLink4 的 NVSHARP 引擎,实现跨节点推理的高效通信。这解决了张量并行推理中通信开销过大的问题。
其他 MLSys 2026 亮点:
- SuperInfer:发现现有框架对 GH200 NVLink-C2C 的利用率不足 5%(900 GB/s 容量),瓶颈在软件栈
- SHIP:Groq 的 LPU 服务栈,整个模型放入 SRAM,编译器以时钟周期粒度静态调度
- BOute:将「哪个模型跑在哪个 GPU 上」建模为多目标贝叶斯优化问题
8.3 TileFuse:NPU 推理的混合精度内核库
AMD 在 2026 年 6 月发布了 TileFuse(arXiv:2606.11357),首次在 XDNA2 NPU 上实现高效的量化 LLM 推理。
TileFuse 的核心创新:
- 核内去量化(In-Core Dequantization):在 NPU 计算阵列内部完成去量化,避免额外的数据搬运
- 元数据感知预分块(Metadata-Aware Pre-Tiling):离线根据量化元数据优化分块策略
- 拓扑感知 GEMV 数据流:针对 NPU 的 DMA 引擎特性优化矩阵-向量乘法
实测效果(Ryzen AI 7 350,Llama3-8B,4096 token prompt):
- NPU 路径降低 64.6% 能耗(更快完成 + 更高效硬件)
- 混合精度(INT4 权重 + FP16 激活)在 NPU 上首次达到实用速度
意义: TileFuse 证明 NPU 不只是「低功耗玩具」——在边缘场景(笔记本、嵌入式设备),NPU 推理正在成为可行选项。
8.4 并发感知成本模型
arXiv:2606.11690 提出了一个重要的成本建模方法论:LLM 推理成本不是简单的「token × 单价」。
核心发现:
- 调查 15+ 公开计算器,90% 以上只接受模型名和 token 数作为输入——完全忽略了并发度对成本的影响
- 在 A800 GPU 上,并发度从 8 提升到 48,单 token 成本降低 2.6 倍
- 存在一个「最佳成本效益区间」——并发度过低(< 5)时成本急剧上升,过高时收益递减
实用建议: 选择推理服务时,不要只看标价($/M token),而要测量你的实际并发度下的有效成本。vLLM 的 GuideLLM 工具可以自动化并发扫描。
# LCLM (Latent Context Models) 推理示例
# pip install transformers latent-context
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from latent_context import LatentContextCompressor
# 加载基础模型
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.1-8B",
torch_dtype=torch.float16,
device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.1-8B")
# 初始化 LCLM 压缩器
compressor = LatentContextCompressor(
compression_ratio=16, # 16x 压缩
model_path="latent-context/lclm-llama3-8b"
)
# 长上下文场景:100K token 的 RAG 文档
long_document = load_large_document("./rag_context.txt") # ~100K tokens
document_tokens = tokenizer(long_document, return_tensors="pt",
truncation=True, max_length=100_000)
print(f"原始 token 数: {document_tokens['input_ids'].shape[1]}")
# 原始 token 数: 100000
# 压缩为潜在表示
compressed = compressor.compress(document_tokens)
print(f"压缩后 latent 维度: {compressed.shape}")
# 压缩后 latent 维度: torch.Size([1, 6250, 4096])
# 100K tokens → 6250 latent vectors (16x 压缩)
# 使用压缩后的上下文进行推理
query = "这份文档中关于推理优化的关键结论是什么?"
inputs = tokenizer(query, return_tensors="pt").to("cuda")
output = model.generate(
**inputs,
latent_context=compressed, # 传入压缩后的上下文
max_new_tokens=512,
use_cache=True
)
answer = tokenizer.decode(output[0], skip_special_tokens=True)
print(f"回答: {answer}")
# === 性能对比 ===
# | 方案 | 显存占用 | 延迟 | 质量 |
# |------|---------|------|------|
# | 完整 KV Cache | OOM (>80GB) | N/A | N/A |
# | LCLM 16x | ~5GB | 62% | 97% NDCG |
# | 分块 RAG | ~12GB | 85% | 89% NDCG |💡 一句话理解
LCLM 对 RAG 管道的影响是颠覆性的。 不再需要复杂的分块策略和检索排序——直接把全文压缩后喂入模型,质量反而比传统 RAG 更好。但要注意:LCLM 目前只支持 Llama 3.1 系列,其他模型的 LCLM 权重预计 2026 Q3 发布。
⚠️ 常见踩坑
并发成本模型揭示了一个反直觉的事实: 在低并发(< 5)下,自托管的成本可能比 API 调用更贵。只有当并发度稳定在 10+ 时,自托管的成本优势才显现。选择部署方案时,务必基于你的实际并发度做成本测算。
82026 年 6 月最新推理突破:硬件革命与并行解码
2026 年 6 月是 LLM 推理领域的密集突破期。三件大事正在重塑推理基础设施的竞争格局:
① Tensordyne Napier 推理专用芯片(6 月 15 日)
Tensordyne 宣布其首款 AI 推理专用芯片 Napier(TDN)成功流片。这不是又一块通用 GPU,而是从数学底层重新设计的推理加速器:
- 对数数学(TDN Math):用加法替代大规模乘法运算,将推理的核心计算从 O(n²) 乘法降为 O(n²) 加法,每瓦特 token 数提升 17 倍
- SRAM+HBM 混合架构(TDN AIP):每颗处理器集成大量 SRAM 减少空闲计算周期,支持最大模型的完整加载
- Any-to-Any 互联(TDN Link):亚微秒级处理器间通信延迟,消除多卡扩展的互联瓶颈
- TDN72 推理 Pod:72 颗处理器组成的推理单元,吞吐量比 NVIDIA Blackwell 系统高 13 倍
这意味着什么? 推理成本的「摩尔定律」可能即将到来。当专用芯片将每 token 成本降低一个数量级时,以前不可能部署的模型(如 100B+ 的实时推理)将变得经济可行。
② 小米 MiMo V2.5 Pro UltraSpeed(6 月 9 日)
小米与推理合作伙伴 TileRT 联合发布了 MiMo-V2.5-Pro-UltraSpeed,实现了 1000 tokens/秒 的推理速度——在标准 8-GPU 商品化节点上。两项关键技术:
- FP4 专家层量化:仅对 MoE 模型的专家层进行 4-bit 浮点量化,模型体积减少 75% 而精度损失可忽略
- DFlash 投机解码:一次提议完整的 token 块而非逐 token 生成,将投机解码的加速比从 2-4x 提升到 10x
限量 API 试用(6 月 9 日至 23 日)定价为标准 MiMo-V2.5-Pro 的 3 倍,但输出速度快 10 倍——对于实时应用(如代码补全、语音助手)来说,这是极具吸引力的性价比。
③ Google Gemma 4 并行解码(6 月 10 日)
Google DeepMind 发布 Gemma 4 的并行解码变体,一次生成 256 个 token 块而非逐 token 自回归生成:
- 在单张 H100 上实现 1000+ tokens/秒
- 比标准自回归模型快 4 倍
- 使用 Apache 2.0 开源协议
- 最适合场景:行内编辑、代码填充、实时补全等速度敏感任务
- 局限:输出质量低于标准 Gemma 4(速度 vs 质量的权衡)
Simon Willison 等早期测试者通过 NVIDIA NIM Cloud API 实现了 500+ tokens/秒的速度。
这三个突破的共同趋势:推理优化正在从「软件算法」扩展到「硬件架构」和「系统级协同」。2026 年下半年,我们预计将看到更多推理专用芯片和并行解码方案的落地。
# DFlash + FP4 量化推理配置
# 模拟 MiMo UltraSpeed 的推理加速方案
from dataclasses import dataclass
@dataclass
class DFlashConfig:
"""DFlash 块级投机解码配置"""
block_size: int = 64 # 每次生成 64 个 token 的块
draft_model: str = "mico-8b" # 轻量草稿模型
fp4_expert_quant: bool = True # FP4 专家层量化
acceptance_threshold: float = 0.65
max_speculative_tokens: int = 128
class DFlashInference:
"""DFlash 块级投机解码引擎"""
def __init__(self, model_path: str, config: DFlashConfig):
self.config = config
# 加载主模型(FP4 量化专家层)
self.target_model = self._load_quantized(model_path)
# 加载草稿模型
self.draft_model = self._load_draft(config.draft_model)
def _load_quantized(self, path: str):
"""加载 FP4 量化模型"""
from tile_rt import QuantizedModel
return QuantizedModel.from_pretrained(
path,
expert_quantization="fp4", # 仅量化 MoE 专家层
attention_dtype="fp16", # 注意力层保持 FP16
embedding_dtype="int8", # 嵌入层 INT8
)
def generate_block(self, prompt: str) -> str:
"""块级生成:一次生成 N 个 token"""
# 第一步:草稿模型快速生成候选块
candidates = self.draft_model.generate(
prompt,
max_tokens=self.config.block_size,
temperature=0.8
)
# 第二步:目标模型一次性验证整个块
verification = self.target_model.verify_block(
prompt=prompt,
candidates=candidates,
threshold=self.config.acceptance_threshold
)
# 第三步:返回接受的 token + 从拒绝位置重新采样
accepted = verification.accepted_tokens
if verification.rejected_at >= 0:
# 从拒绝位置用目标模型重新采样
resampled = self.target_model.generate(
prompt + accepted,
max_tokens=1
)
accepted += resampled
return accepted
def benchmark(self, prompts: list, n_runs: int = 10):
"""性能基准测试"""
import time
results = {"tokens": [], "latency_ms": [], "throughput": []}
for _ in range(n_runs):
for prompt in prompts:
start = time.perf_counter()
output = self.generate_block(prompt)
elapsed = (time.perf_counter() - start) * 1000
results["tokens"].append(len(output.split()))
results["latency_ms"].append(elapsed)
results["throughput"].append(
len(output.split()) / (elapsed / 1000)
)
import statistics
print(f"=== DFlash + FP4 推理基准 ===")
print(f"平均吞吐量: {statistics.mean(results['throughput']):.1f} tok/s")
print(f"P50 延迟: {statistics.median(results['latency_ms']):.1f} ms")
print(f"P99 延迟: {sorted(results['latency_ms'])[int(len(results['latency_ms'])*0.99)]:.1f} ms")
return results
# 使用示例
config = DFlashConfig(
block_size=64,
draft_model="mico-8b",
fp4_expert_quant=True,
acceptance_threshold=0.65
)
engine = DFlashInference("xiaomi/mimo-v2.5-pro", config)
# 预期结果:~1000 tok/s(8x GPU 节点)💡 一句话理解
⚠️ 常见踩坑
Tensordyne Napier 目前仅接受预订,预计 2026 Q4 开始发货。 短期内不要指望它能解决你的推理成本问题。但中长期来看,推理专用芯片是必然趋势——建议关注其 benchmark 数据,为未来的架构迁移做准备。
🎯 相关面试题
巩固本篇知识点,备战 AI 岗位面试。
- 中级概念查看详解 →
LLM 推理的 Prefill 与 Decode 两阶段有什么区别?
Prefill 并行处理整段 prompt、算力受限、决定首 token 延迟;Decode 逐 token 串行、访存受限、决定吐字速度。
- 高级概念高频查看详解 →
什么是 KV Cache?它如何加速 LLM 推理?
缓存历史 token 的 Key/Value 向量,生成新 token 时避免重复计算 Attention,是推理加速的核心手段。
- 中级概念查看详解 →
连续批处理(Continuous Batching)为什么能提升 LLM 服务吞吐?
以迭代为粒度调度:每步把完成的序列换出、新请求即时填入,消除静态批里等齐木桶效应造成的 GPU 空转。
- 高级概念查看详解 →
多查询注意力(MQA)与分组查询注意力(GQA)解决了什么问题?
让多个 Query 头共享 K/V 头,缩小 KV-cache 显存与解码访存,MQA 共享到 1 组、GQA 折中分多组。
