第24章 推理框架与模型服务化
来源:https://ai-agent-guide.xiaofuge.cn/chapters/ch20-inference-framework.html 所属:第七篇-工程化
从开源模型到可用服务,Ollama/vLLM/SGLang 实战 🧭 本章先抓住这条主线
第1章我们学过:开源模型的优势是数据隐私、可微调、无 API 依赖、成本低。但有一个前提——你得先让模型跑起来。
本章回答的核心问题:拿到一个开源模型(Qwen2、Llama3、DeepSeek),怎么把它变成 Agent 能调用的推理服务?从一台 Mac 本地调试,到企业级 GPU 集群高并发部署,推理框架是中间那层关键的桥梁。
读完本章的最低目标:能回答"选 Ollama 还是 vLLM",能独立部署一个本地推理服务并让 Agent 代码接入。 🎤 面试官更爱这样追问
比起问"什么是 Ollama",更真实的问法通常是:
- 为什么 Agent 从 GPT 切换到本地模型只需要改一行 base_url?
- PagedAttention 解决了什么问题?为什么 vLLM 的显存利用率能达到 90%?
- INT4 量化后精度损失多少?什么场景下量化不可接受?
- 多 GPU 推理时,模型怎么切分?通信开销怎么优化?
24.1 为什么需要推理框架?
很多小白的误区是:以为下载了一个模型文件(.bin / .safetensors),就可以直接用了。事实是——模型文件只是一个权重矩阵,你还需要推理框架把它变成一个可调用的服务。
类比理解:模型文件像一张蓝图,推理框架像工厂。蓝图再好,没有工厂也造不出产品。推理框架负责:加载模型到 GPU/CPU、处理输入 Token、执行矩阵运算、解码输出 Token、提供 API 接口。
🧱 推理框架的五层职责 | 层级 | 职责 | 类比 | | --- | --- | --- | | ① 模型加载 | 读取权重文件、分配 GPU/CPU 显存/内存、初始化计算图 | 把蓝图交给车间 | | ② Token 处理 | 输入分词、Embedding 编码、输出解码、采样策略 | 原材料加工 | | ③ 计算调度 | KV Cache 管理、PagedAttention、连续批处理、多 GPU 分布式 | 生产线调度 | | ④ API 服务 | 提供 OpenAI-compatible API、HTTP 服务、并发管理 | 成品展示厅 | | ⑤ 辅助能力 | 量化转换、模型管理、健康检查、日志监控 | 质检+后勤 | 没有推理框架,你面临的困境:
- 手动加载模型:需要写 PyTorch/Transformers 代码,处理显存分配、模型分片、dtype 转换
- 没有 API 接口:Agent 只能用 Python 函数调用,不能像 OpenAI 一样用 HTTP API
- 无法并发:一次只能处理一个请求,多个 Agent 同时调用就会排队
- 显存浪费:KV Cache 重复存储,同一段文本的 Cache 无法共享,显存利用率只有 20-40%
推理框架把这些工程问题全部解决了,让你专注在 Agent 逻辑上,而不是推理基础设施上。
24.2 Ollama:轻量易用的本地推理
Ollama 是最简单的本地 LLM 运行方案。一条命令下载模型,一条命令启动服务,API 接口兼容 OpenAI 格式。适合个人开发、快速验证、学习实验。
核心特性
- 一键部署:
ollama run llama3— 模型自动下载、自动量化、自动服务 - OpenAI兼容:API 格式和 OpenAI 一样,Agent 代码零改动切换,只需改
base_url - 模型丰富:支持 Llama 3/4、Qwen 2/3、Mistral、DeepSeek、Gemma 等主流开源模型
- Mac/PC 即可:4GB 内存起步,Apple Silicon 优化,无需 NVIDIA GPU
- GGUF 量化:自动下载量化版本(Q4_K_M),显存占用降低 4 倍
安装与运行
Shell
# === 安装 ===
# macOS: brew install ollama
# Linux: curl -fsSL https://ollama.com/install.sh | sh
# Windows: 下载安装包 https://ollama.com/download
# === 启动服务 ===
ollama serve # 启动后台服务(默认端口 11434)
# === 下载并运行模型 ===
ollama pull qwen2:7b # 下载模型(自动量化为 GGUF Q4_K_M)
ollama run qwen2:7b # 运行模型(进入交互式对话)
# === 查看已安装模型 ===
ollama list
# === 模型管理 ===
ollama rm llama3 # 删除模型
ollama cp qwen2:7b my-agent # 复制模型(用于自定义 Modelfile)
Agent 代码接入
Ollama 最强大的地方在于API 兼容 OpenAI 格式。你原来用 GPT-4 的 Agent 代码,只需要改一行配置就能切换到本地模型:
from openai import OpenAI
# ========== 方案A:云端 API ==========
# client = OpenAI(
# base_url="https://api.openai.com/v1",
# api_key="sk-xxx"
# )
# model = "gpt-4o"
# ========== 方案B:本地 Ollama — 只改这两行 ==========
client = OpenAI(
base_url="http://localhost:11434/v1",
api_key="ollama" # Ollama 不需要真密钥
)
model = "qwen2:7b" # 改为本地模型名
# ========== 以下代码完全不变 ==========
# 1. 简单对话
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": "你是客服Agent,帮助用户解决问题"},
{"role": "user", "content": "我的订单还没到,订单号ORD123"}
]
)
print(response.choices[0].message.content)
# 2. Function Calling(Ollama 从 v0.5 起支持)
tools = [
{
"type": "function",
"function": {
"name": "query_order",
"description": "查询订单状态",
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "string", "description": "订单号"}
},
"required": ["order_id"]
}
}
}
]
response = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": "查一下ORD123"}],
tools=tools
)
if response.choices[0].message.tool_calls:
for tool_call in response.choices[0].message.tool_calls:
print(f"调用函数: {tool_call.function.name}")
print(f"参数: {tool_call.function.arguments}")
import OpenAI from 'openai';
// ========== 方案A:云端 API ==========
// const client = new OpenAI({
// baseURL: 'https://api.openai.com/v1',
// apiKey: 'sk-xxx'
// });
// const model = 'gpt-4o';
// ========== 方案B:本地 Ollama — 只改这两行 ==========
const client = new OpenAI({
baseURL: 'http://localhost:11434/v1',
apiKey: 'ollama', // Ollama 不需要真密钥
});
const model = 'qwen2:7b'; // 改为本地模型名
// ========== 以下代码完全不变 ==========
// 1. 简单对话
const response = await client.chat.completions.create({
model,
messages: [
{ role: 'system', content: '你是客服Agent,帮助用户解决问题' },
{ role: 'user', content: '我的订单还没到,订单号ORD123' }
]
});
console.log(response.choices[0].message.content);
// 2. Function Calling(Ollama 从 v0.5 起支持)
const tools = [
{
type: 'function' as const,
function: {
name: 'query_order',
description: '查询订单状态',
parameters: {
type: 'object',
properties: {
order_id: { type: 'string', description: '订单号' }
},
required: ['order_id']
}
}
}
];
const response2 = await client.chat.completions.create({
model,
messages: [{ role: 'user', content: '查一下ORD123' }],
tools
});
if (response2.choices[0].message.tool_calls) {
for (const toolCall of response2.choices[0].message.tool_calls) {
console.log(`调用函数: ${toolCall.function.name}`);
console.log(`参数: ${toolCall.function.arguments}`);
}
}
package main
import (
"context"
"fmt"
openai "github.com/sashabaranov/go-openai"
)
func main() {
// ========== 方案B:本地 Ollama — 只改这两行 ==========
config := openai.DefaultConfig("ollama") // Ollama 不需要真密钥
config.BaseURL = "http://localhost:11434/v1"
client := openai.NewClientWithConfig(config)
model := "qwen2:7b" // 改为本地模型名
ctx := context.Background()
// 1. 简单对话
resp, err := client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{
Model: model,
Messages: []openai.ChatCompletionMessage{
{Role: openai.ChatMessageRoleSystem, Content: "你是客服Agent,帮助用户解决问题"},
{Role: openai.ChatMessageRoleUser, Content: "我的订单还没到,订单号ORD123"},
},
})
if err != nil {
panic(err)
}
fmt.Println(resp.Choices[0].Message.Content)
// 2. Function Calling
resp2, err := client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{
Model: model,
Messages: []openai.ChatCompletionMessage{
{Role: openai.ChatMessageRoleUser, Content: "查一下ORD123"},
},
Functions: []openai.FunctionDefinition{
{
Name: "query_order",
Description: "查询订单状态",
Parameters: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"order_id": map[string]string{
"type": "string",
"description": "订单号",
},
},
"required": []string{"order_id"},
},
},
},
})
if err != nil {
panic(err)
}
for _, choice := range resp2.Choices {
if choice.Message.FunctionCall != nil {
fmt.Printf("调用函数: %s\n", choice.Message.FunctionCall.Name)
fmt.Printf("参数: %s\n", choice.Message.FunctionCall.Arguments)
}
}
}
import com.openai.client.OpenAIClient;
import com.openai.client.OpenAIClientConfig;
import com.openai.models.*;
import java.util.*;
public class AgentApp {
public static void main(String[] args) {
// ========== 方案B:本地 Ollama — 只改这两行 ==========
OpenAIClientConfig config = OpenAIClientConfig.builder()
.baseUrl("http://localhost:11434/v1")
.apiKey("ollama") // Ollama 不需要真密钥
.build();
OpenAIClient client = new OpenAIClient(config);
String model = "qwen2:7b"; // 改为本地模型名
// 1. 简单对话
ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
.model(model)
.addMessage(ChatCompletionMessageParam.builder()
.role(ChatCompletionMessageParam.Role.SYSTEM)
.content("你是客服Agent,帮助用户解决问题")
.build())
.addMessage(ChatCompletionMessageParam.builder()
.role(ChatCompletionMessageParam.Role.USER)
.content("我的订单还没到,订单号ORD123")
.build())
.build();
ChatCompletion response = client.chat().completions().create(params);
System.out.println(response.choices().get(0).message().content());
// 2. Function Calling
FunctionDefinition queryOrder = FunctionDefinition.builder()
.name("query_order")
.description("查询订单状态")
.parameters(Map.of(
"type", "object",
"properties", Map.of(
"order_id", Map.of("type", "string", "description", "订单号")
),
"required", List.of("order_id")
))
.build();
ChatCompletionCreateParams params2 = ChatCompletionCreateParams.builder()
.model(model)
.addMessage(ChatCompletionMessageParam.builder()
.role(ChatCompletionMessageParam.Role.USER)
.content("查一下ORD123")
.build())
.addTool(queryOrder)
.build();
ChatCompletion response2 = client.chat().completions().create(params2);
for (ChatCompletionMessage.ToolCall toolCall : response2.choices().get(0).message().toolCalls()) {
System.out.printf("调用函数: %s%n", toolCall.function().name());
System.out.printf("参数: %s%n", toolCall.function().arguments());
}
}
}
Ollama Modelfile:自定义模型行为
Ollama 支持通过 Modelfile 自定义模型参数,类似 Dockerfile 的概念:
Modelfile — 自定义 Agent 专用模型
# 基于基础模型
FROM qwen2:7b
# 设置系统提示词(Agent 角色定义)
SYSTEM """
你是智能客服 Agent,帮助用户查询订��、处理退货、推荐商品。
回答要简洁、专业、有温度。
"""
# 设置生成参数
PARAMETER temperature 0.3 # 低温度 = 更稳定输出
PARAMETER top_p 0.9 # 保留前 90% 概率的词
PARAMETER num_ctx 4096 # 上下文窗口大小
PARAMETER repeat_penalty 1.1 # 防止重复输出
# 创建自定义模型
# ollama create my-customer-agent -f Modelfile
# 运行自定义模型
# ollama run my-customer-agent
24.3 vLLM:企业级高吞吐推理引擎
vLLM 是工业级推理引擎,核心优势是PagedAttention技术——像操作系统管理虚拟内存一样管理 GPU 显存,极大提升并发吞吐量。适合高并发生产环境、企业级部署。
PagedAttention:核心突破
传统推理中,每个请求的 KV Cache(注意力计算的中间结果)需要连续的显存空间。问题是:
- 请求长度不可预知——预分配多了浪费,少了溢出要重新分配
- 不同请求的 Cache 不能共享——同样的 prompt 前缀被反复存储
- 显存碎片化——频繁的分配/释放导致大量碎片,利用率只有 20-40%
PagedAttention 的解决方案:把 KV Cache 切成固定大小的页(Page),像 OS 的虚拟内存一样管理:
- 按需分配:不需要预分配连续空间,用到多少页就分配多少
- 跨请求共享:相同 prompt 前缀的 KV Cache 页可以跨请求复用(copy-on-write)
- 消除碎片:页式管理天然避免碎片,显存利用率从 20-40% 提升到 90%+
安装与运行
Shell — vLLM 安装与启动
# === 安装(需要 NVIDIA GPU + CUDA) ===
pip install vllm
# === 启动 OpenAI-compatible API 服务 ===
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2-7B-Instruct \
--served-model-name qwen2-7b \
--host 0.0.0.0 \
--port 8000 \
--gpu-memory-utilization 0.9 \ # 显存利用率目标 90%
--max-model-len 8192 \ # 最大上下文长度
--tensor-parallel-size 2 # 2卡并行推理(可选)
# === 验证服务 ===
curl http://localhost:8000/v1/models
# === 调用模型 ===
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "qwen2-7b",
"messages": [
{"role": "user", "content": "解释PagedAttention"}
]
}'
vLLM 核心特性详解
⚡ vLLM 四大核心技术 | 技术 | 原理 | 收益 | | --- | --- | --- | | PagedAttention | KV Cache 页式管理,按需分配,跨请求共享 | 显存利用率 90%+,并发吞吐提升 2-4 倍 | | 连续批处理 | 动态组 batch,新请求随时加入,完成的请求立即退出 | 吞吐最大化,不同请求不等齐 | | 分布式推理 | Tensor Parallel 模型分片,多 GPU 并行计算 | 百亿级模型也能跑,支持多节点扩展 | | Prefix Caching | 自动缓存相同 prompt 前缀的 KV Cache,后续请求直接复用 | 相同 System Prompt 的请求首 Token 延迟降低 80% | ## 24.4 SGLang 与其他推理框架
除了 Ollama 和 vLLM,推理框架生态还有几个重要成员:
SGLang ✨ 新秀
2024 年新推出的推理引擎,主打结构化生成(RadixAttention + 压缩有限状态机)。
适合:需要精确约束输出格式的场景(JSON、SQL、代码)
优势:结构化输出速度比 vLLM 快 3-7 倍,显存效率接近 vLLM
特点:RadixAttention 自动共享公共前缀树,比 vLLM 的 Prefix Caching 更细粒度
llama.cpp 经典
最早的本地推理方案,C++ 实现,纯 CPU/GPU 混合推理。
适合:无 GPU 环境、嵌入式设备、极致轻量
优势:跨平台(CPU-only 可跑)、GGUF 格式生态丰富
特点:Ollama 的底层引擎就是 llama.cpp
TGI 企业级
HuggingFace 的 Text Generation Inference,Docker 一键部署。
适合:需要快速搭建企业推理服务的团队
优势:HuggingFace 生态天然集成、Flash Attention、水印检测
特点:Docker 部署最简单,量化支持完善(GPTQ/AWQ/bitsandbytes) 📊 五大推理框架全景对比 | 维度 | Ollama 🦙 | vLLM ⚡ | SGLang ✨ | llama.cpp | TGI | | --- | --- | --- | --- | --- | --- | | 部署难度 | ⭐ 极简 | ⭐⭐⭐ 中等 | ⭐⭐⭐ 中等 | ⭐⭐ 简单 | ⭐⭐ Docker | | 硬件要求 | Mac/PC 4GB起 | NVIDIA 16GB+ | NVIDIA 16GB+ | CPU/GPU均可 | NVIDIA 16GB+ | | 并发吞吐 | 低 (~5 QPS) | 高 (100+ QPS) | 高 (100+ QPS) | 低 (~3 QPS) | 中 (30+ QPS) | | 显存效率 | 20-40% | 90%+ (PagedAtt) | 90%+ (RadixAtt) | 30-50% | 70-80% | | 结构化输出 | ⭐⭐ 一般 | ⭐⭐ 一般 | ⭐⭐⭐⭐⭐ 极快 | ⭐⭐ 一般 | ⭐⭐⭐ 良好 | | OpenAI兼容 | ✅ 完整 | ✅ 完整 | ✅ 完整 | ❌ 需自建 | ✅ 完整 | | 适用场景 | 开发/学习 | 企业生产 | 结构化输出 | 轻量/嵌入式 | HuggingFace生态 | ## 24.5 量化:让大模型跑在小机器上
7B 参数的模型 FP16 精度需要 14GB 显存,70B 需要 140GB——大部分企业没有这么多 GPU。量化(Quantization)是让大模型跑在小机器上的核心技术:降低参数精度(FP16 → INT8 → INT4),用更少的显存装更大的模型。
量化原理与精度损失
模型参数本质上是一堆浮点数矩阵。FP16 每个参数占 2 字节(16bit),INT8 占 1 字节(8bit),INT4 占 0.5 字节(4bit)。量化就是把这些高精度浮点数"压缩"到低精度整数: 📊 量化精度与显存对比(7B 参数模型为例) | 精度 | 每参数字节 | 7B 显存需求 | 推理速度 | 精度损失 | 适用场景 | | --- | --- | --- | --- | --- | --- | | FP16(原始) | 2 bytes | 14 GB | 基准 | 0% | GPU 集群生产部署 | | INT8 (GPTQ/AWQ) | 1 byte | 7 GB | 2-3x 加速 | ~1-2% | 生产部署首选 | | INT4 (Q4_K_M) | 0.5 byte | 3.5 GB | 3-4x 加速 | ~3-5% | 个人开发/学习 | #### 💡 量化的精度损失怎么理解?
INT8 量化精度损失约 1-2%,几乎不影响对话质量。INT4 损失约 3-5%,在简单对话场景下完全可用,但在以下场景可能不可接受:
- 数学推理:精度损失可能导致计算错误
- 代码生成:变量名、逻辑细微差异可能影响正确性
- 多语言混合:中文+英文混合场景下精度损失更明显
- Function Calling:参数格式错误率可能升高
实用原则:对话型 Agent 用 INT4 没问题,工具调用型 Agent 优先用 INT8 或 FP16。
主流量化格式
🔧 GGUF vs GPTQ vs AWQ — 三种量化格式对比 | 格式 | 支持框架 | 量化方法 | 精度级别 | 特点 | | --- | --- | --- | --- | --- | | GGUF | Ollama / llama.cpp | 基于 k-quant 的混合量化 | Q2_K 到 Q8_0 多档可选 | CPU/GPU 混合推理、单文件分发 | | GPTQ | vLLM / TGI / AutoGPTQ | 基于校准数据集的一阶量化 | INT4 / INT8 | GPU-only、精度好、vLLM原生支持 | | AWQ | vLLM / TGI | 激活感知的加权量化 | INT4 / INT8 | 保留重要通道权重、精度优于GPTQ | ## 24.6 推理框架选型决策
选推理框架不是"Ollama vs vLLM"的二元选择,而是根据你的场景匹配最合适的方案: 🎯 Agent 场景与推理框架匹配 | Agent 场景 | 推荐框架 | 推荐精度 | 理由 | | --- | --- | --- | --- | | 对话型 Agent(客服/FAQ) | Ollama | Q4_K_M | 对话场景 INT4 精度够用,Ollama 一键部署最快 | | 工具调用型 Agent(API 路由) | vLLM | GPTQ-AWQ INT8 | Function Calling 需要更高精度,INT8 + 高并发 | | 数据提取型 Agent(JSON/SQL) | SGLang | FP16/INT8 | 结构化输出速度极快,精度约束严格 | | 隐私合规型 Agent(金融/医疗) | vLLM + TGI | FP16 | 合规场景精度不可妥协,FP16 + GPU 集群 | ## 24.7 多 GPU 分布式推理
70B+ 参数模型单卡跑不了,需要多 GPU 分布式推理。核心挑战:模型怎么切分?GPU 之间怎么通信?通信开销怎么优化?
Tensor Parallel:模型分片并行
Tensor Parallel(张量并行)是最常用的多 GPU 推理方案:把模型的每一层矩阵按列切分到不同 GPU 上,每个 GPU 只算一部分,然后通过 AllReduce 操作汇总结果。
vLLM 多 GPU 启动
# === 2卡并行推理(单节点) ===
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-72B-Instruct \
--tensor-parallel-size 2 \ # 2张GPU切分模型
--gpu-memory-utilization 0.9 \
--max-model-len 8192
# === 4卡并行推理(单节点) ===
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-72B-Instruct \
--tensor-parallel-size 4 # 4张GPU切分模型
# === 多节点推理(跨机器) ===
# 需要先启动 Ray 集群
ray start --head --port=6379 # 主节点
ray start --address=主节点IP:6379 # 工作节点
# 启动 vLLM 多节点服务
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-72B-Instruct \
--tensor-parallel-size 8 \ # 8张GPU(跨2台机器)
--pipeline-parallel-size 2 # 2台机器流水线并行
💡 Tensor Parallel vs Pipeline Parallel
- Tensor Parallel(TP):同一层内按列切分,GPU 间每步都需要 AllReduce 通信。适合同一台机器内的多卡(NVLink 通信带宽高)
- Pipeline Parallel(PP):按层切分,不同 GPU 负责不同层,像流水线一样接力。适合跨机器(网络带宽有限,减少通信次数)
- 混合并行(TP+PP):大模型常用方案——先在同一机器内做 TP,再跨机器做 PP
vLLM 同时支持 TP 和 PP,SGLang 也支持 TP。Ollama 目前不支持分布式推理。
24.8 模型服务化与 Agent 接入
推理框架把模型跑起来了,但 Agent 怎么接入?核心原则:所有主流推理框架都兼容 OpenAI API 格式,Agent 代码只需改 base_url 和 model 名。
统一接入架构
from openai import OpenAI
from enum import Enum
class ModelBackend(Enum):
OPENAI = "https://api.openai.com/v1"
OLLAMA = "http://localhost:11434/v1"
VLLM = "http://gpu-server:8000/v1"
SGLANG = "http://sglang-server:30000/v1"
class AgentModelRouter:
"""Agent 模型路由器:根据任务类型自动选择推理后端"""
BACKEND_CONFIG = {
ModelBackend.OPENAI: {"api_key": "sk-xxx", "model": "gpt-4o"},
ModelBackend.OLLAMA: {"api_key": "ollama", "model": "qwen2:7b"},
ModelBackend.VLLM: {"api_key": "EMPTY", "model": "deepseek-v3"},
ModelBackend.SGLANG: {"api_key": "EMPTY", "model": "llama3-8b"},
}
def __init__(self, backend: ModelBackend = ModelBackend.OLLAMA):
config = self.BACKEND_CONFIG[backend]
self.client = OpenAI(
base_url=backend.value,
api_key=config["api_key"]
)
self.model = config["model"]
def chat(self, messages, tools=None, **kwargs):
"""统一调用接口,代码不变只切换后端"""
params = {"model": self.model, "messages": messages, **kwargs}
if tools:
params["tools"] = tools
return self.client.chat.completions.create(**params)
def switch_backend(self, backend: ModelBackend):
"""运行时动态切换后端"""
config = self.BACKEND_CONFIG[backend]
self.client = OpenAI(
base_url=backend.value,
api_key=config["api_key"]
)
self.model = config["model"]
# ===== 使用示例 =====
# 开发阶段用 Ollama
router = AgentModelRouter(ModelBackend.OLLAMA)
# 简单对话
result = router.chat([
{"role": "user", "content": "帮我查北京天气"}
])
print(result.choices[0].message.content)
# Function Calling
result = router.chat(
messages=[{"role": "user", "content": "查一下ORD123"}],
tools=[{
"type": "function",
"function": {
"name": "query_order",
"description": "查询订单状态",
"parameters": {
"type": "object",
"properties": {"order_id": {"type": "string"}},
"required": ["order_id"]
}
}
}]
)
# 上线切换到 vLLM(一行代码)
router.switch_backend(ModelBackend.VLLM)
result = router.chat([{"role": "user", "content": "帮我查北京天气"}])
import OpenAI from 'openai';
enum ModelBackend {
OPENAI = 'https://api.openai.com/v1',
OLLAMA = 'http://localhost:11434/v1',
VLLM = 'http://gpu-server:8000/v1',
SGLANG = 'http://sglang-server:30000/v1',
}
const BACKEND_CONFIG: Record = {
[ModelBackend.OPENAI]: { apiKey: 'sk-xxx', model: 'gpt-4o' },
[ModelBackend.OLLAMA]: { apiKey: 'ollama', model: 'qwen2:7b' },
[ModelBackend.VLLM]: { apiKey: 'EMPTY', model: 'deepseek-v3' },
[ModelBackend.SGLANG]: { apiKey: 'EMPTY', model: 'llama3-8b' },
};
class AgentModelRouter {
/** Agent 模型路由器:根据任务类型自动选择推理后端 */
private client: OpenAI;
private model: string;
constructor(backend: ModelBackend = ModelBackend.OLLAMA) {
const config = BACKEND_CONFIG[backend];
this.client = new OpenAI({ baseURL: backend, apiKey: config.apiKey });
this.model = config.model;
}
/** 统一调用接口,代码不变只切换后端 */
async chat(messages: any[], tools?: any[], kwargs?: any) {
const params: any = { model: this.model, messages, ...kwargs };
if (tools) params.tools = tools;
return await this.client.chat.completions.create(params);
}
/** 运行时动态切换后端 */
switchBackend(backend: ModelBackend) {
const config = BACKEND_CONFIG[backend];
this.client = new OpenAI({ baseURL: backend, apiKey: config.apiKey });
this.model = config.model;
}
}
// ===== 使用示例 =====
// 开发阶段用 Ollama
const router = new AgentModelRouter(ModelBackend.OLLAMA);
// 简单对话
const result = await router.chat([
{ role: 'user', content: '帮我查北京天气' }
]);
console.log(result.choices[0].message.content);
// Function Calling
const result2 = await router.chat(
[{ role: 'user', content: '查一下ORD123' }],
[{
type: 'function' as const,
function: {
name: 'query_order',
description: '查询订单状态',
parameters: {
type: 'object',
properties: { order_id: { type: 'string' } },
required: ['order_id']
}
}
}]
);
// 上线切换到 vLLM(一行代码)
router.switchBackend(ModelBackend.VLLM);
const result3 = await router.chat([{ role: 'user', content: '帮我查北京天气' }]);
package main
import (
"fmt"
openai "github.com/sashabaranov/go-openai"
)
type ModelBackend string
const (
BackendOpenAI ModelBackend = "https://api.openai.com/v1"
BackendOllama ModelBackend = "http://localhost:11434/v1"
BackendVLLM ModelBackend = "http://gpu-server:8000/v1"
BackendSGLang ModelBackend = "http://sglang-server:30000/v1"
)
type BackendConfig struct {
APIKey string
Model string
}
// AgentModelRouter Agent 模型路由器
type AgentModelRouter struct {
client *openai.Client
model string
}
var backendConfigs = map[ModelBackend]BackendConfig{
BackendOpenAI: {APIKey: "sk-xxx", Model: "gpt-4o"},
BackendOllama: {APIKey: "ollama", Model: "qwen2:7b"},
BackendVLLM: {APIKey: "EMPTY", Model: "deepseek-v3"},
BackendSGLang: {APIKey: "EMPTY", Model: "llama3-8b"},
}
func NewAgentModelRouter(backend ModelBackend) *AgentModelRouter {
config := backendConfigs[backend]
cfg := openai.DefaultConfig(config.APIKey)
cfg.BaseURL = string(backend)
return &AgentModelRouter{
client: openai.NewClientWithConfig(cfg),
model: config.Model,
}
}
// Chat 统一调用接口
func (r *AgentModelRouter) Chat(messages []openai.ChatCompletionMessage) (string, error) {
resp, err := r.client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{
Model: r.model,
Messages: messages,
})
if err != nil {
return "", err
}
return resp.Choices[0].Message.Content, nil
}
// SwitchBackend 运行时动态切换后端
func (r *AgentModelRouter) SwitchBackend(backend ModelBackend) {
config := backendConfigs[backend]
cfg := openai.DefaultConfig(config.APIKey)
cfg.BaseURL = string(backend)
r.client = openai.NewClientWithConfig(cfg)
r.model = config.Model
}
import com.openai.client.OpenAIClient;
import com.openai.client.OpenAIClientConfig;
import com.openai.models.*;
import java.util.*;
public class AgentModelRouter {
/** Agent 模型路由器:根据任务类型自动选择推理后端 */
enum ModelBackend {
OPENAI("https://api.openai.com/v1"),
OLLAMA("http://localhost:11434/v1"),
VLLM("http://gpu-server:8000/v1"),
SGLANG("http://sglang-server:30000/v1");
final String url;
ModelBackend(String url) { this.url = url; }
}
static final Map BACKEND_CONFIG = Map.of(
ModelBackend.OPENAI, new String[]{"sk-xxx", "gpt-4o"},
ModelBackend.OLLAMA, new String[]{"ollama", "qwen2:7b"},
ModelBackend.VLLM, new String[]{"EMPTY", "deepseek-v3"},
ModelBackend.SGLANG, new String[]{"EMPTY", "llama3-8b"}
);
private OpenAIClient client;
private String model;
public AgentModelRouter(ModelBackend backend) {
String[] config = BACKEND_CONFIG.get(backend);
OpenAIClientConfig cfg = OpenAIClientConfig.builder()
.baseUrl(backend.url)
.apiKey(config[0])
.build();
this.client = new OpenAIClient(cfg);
this.model = config[1];
}
/** 统一调用接口,代码不变只切换后端 */
public ChatCompletion chat(List messages) {
ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
.model(model)
.messages(messages)
.build();
return client.chat().completions().create(params);
}
/** 运行时动态切换后端 */
public void switchBackend(ModelBackend backend) {
String[] config = BACKEND_CONFIG.get(backend);
OpenAIClientConfig cfg = OpenAIClientConfig.builder()
.baseUrl(backend.url)
.apiKey(config[0])
.build();
this.client = new OpenAIClient(cfg);
this.model = config[1];
}
}
混合策略:关键场景用旗舰,辅助场景用开源
生产环境中最务实的方案是混合部署——不是所有任务都需要旗舰模型: 🎯 混合部署:成本降 70%,质量不掉
- 80% 简单任务(FAQ、分类、简单提取)→ 本地模型 Qwen2:7b (Ollama/vLLM),成本 ≈ 0
- 15% 中等任务(多轮对话、工具调用)→ 本地模型 DeepSeek-V3 (vLLM INT8),成本 ≈ GPU 电费
- 5% 复杂任务(复杂推理、关键决策)→ 云端 GPT-4o,按量付费,但只有 5% 的调用
总成本 ≈ 5% × GPT-4o 价格 + GPU 运维费,比纯云端方案节省 70%+。
24.9 生产级推理服务部署
推理框架跑起来只是第一步,生产级部署还需要:高可用、自动扩缩容、监控告警、安全加固。
vLLM 生产部署模板
Docker Compose — vLLM 生产部署
# docker-compose.yml
version: '3.8'
services:
vllm-server:
image: vllm/vllm-openai:latest
container_name: vllm-server
runtime: nvidia
environment:
- NVIDIA_VISIBLE_DEVICES=0,1 # 使用GPU 0和1
- MODEL=Qwen/Qwen2.5-7B-Instruct
- TENSOR_PARALLEL_SIZE=2
- GPU_MEMORY_UTILIZATION=0.9
- MAX_MODEL_LEN=8192
ports:
- "8000:8000"
volumes:
- /data/models:/models # 模型缓存目录
command: >
--model Qwen/Qwen2.5-7B-Instruct
--served-model-name qwen2-7b
--tensor-parallel-size 2
--gpu-memory-utilization 0.9
--max-model-len 8192
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 2
capabilities: [gpu]
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/v1/models"]
interval: 30s
timeout: 10s
retries: 3
# 可选:负载均衡(多实例)
nginx-lb:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- vllm-server
# 可选:监控
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
关键监控指标
📊 推理服务必须监控的 6 个指标 | 指标 | 含义 | 告警阈值 | 优化方向 | | --- | --- | --- | --- | | TTFT(首 Token 延迟) | 用户发送请求到收到第一个Token的时间 | > 2s | Prefix Caching、Prefill 批处理 | | TPS(每秒 Token 数) | 单请求的生成速度 | 50% | 扩容 GPU、连续批处理 | | GPU 显存利用率 | 已用显存 / 总显存 | 95% | 调整 PagedAttention 参数 | | 请求成功率 | 成功请求数 / 总请求数 | < 99% | 超时兜底、降级策略 | | KV Cache 命中率 | 复用 KV Cache 的比例 | < 30% | Prefix Caching、System Prompt 共享 | ## 24.10 2026 推理优化前沿技术
前面的章节覆盖了推理框架的基础选型与部署。但 2025-2026 年,随着 DeepSeek-V3、Qwen3-MoE 等模型的爆发,推理优化技术本身成了面试高频考点。这一节聚焦三个前沿方向:MoE 推理优化、投机解码、以及 KV Cache 量化等工程加速技术。 🧭 为什么这一节重要?
2026 年面试官不再只问"vLLM 和 Ollama 区别",而是追问:
- MoE 模型参数量 671B,为什么推理成本却能和 70B Dense 模型差不多?
- 投机解码的加速比取决于什么?为什么不是无限制加速?
- KV Cache 量化有哪些方案?FP8 vs INT8 vs INT4 各有什么取舍?
24.10.1 MoE(Mixture of Experts)推理优化
MoE(混合专家模型)是 2025-2026 年大模型的主流架构趋势。DeepSeek-V3(671B 参数)、Qwen3-MoE、Mixtral 8x22B 都采用 MoE 架构。核心思想:不是所有参数都参与每次推理,而是动态激活一部分"专家"子网络。 🧠 MoE 核心原理:稀疏激活
传统 Dense 模型(如 Llama3-70B):每次推理,700 亿参数全部参与矩阵运算。
MoE 模型(如 DeepSeek-V3 671B):每次推理,只有约 37B 参数被激活——因为每个 Token 只路由到 Top-K 个专家(通常 K=8),其余专家不参与计算。
💡 MoE 为什么能降低推理成本?
关键公式:推理计算量 ∝ 激活参数量,而非总参数量。
- DeepSeek-V3:总参数 671B,激活参数 ≈ 37B → 推理计算量相当于 37B Dense 模型
- 对比 Dense 671B 模型:计算量降低 18 倍
- 对比 Llama3-70B Dense:参数量大了 10 倍,但推理计算量只多了 ~50%
代价:显存占用仍然需要装下全部 671B 参数(因为不知道哪个专家会被选中),这是 MoE 推理的主要挑战——计算便宜了,但显存更贵了。
专家路由与负载均衡
MoE 推理的核心挑战是专家负载均衡——如果某些专家被频繁选中而其他专家闲置,会导致:
- GPU 利用率不均:热门专家所在的 GPU 成为瓶颈,冷门专家的 GPU 空转
- 显存浪费:所有专家都要常驻显存,但使用频率差异巨大
- 推理延迟波动:负载不均导致不同请求的延迟差异大 🔧 负载均衡策略 | 策略 | 原理 | 适用场景 | | --- | --- | --- | | 辅助损失(Aux Loss) | 训练时加入负载均衡损失项,惩罚专家选择不均匀 | 训练阶段(DeepSeek-V3 采用) | | 专家并行(Expert Parallel) | 把不同专家分布到不同 GPU 上,每个 GPU 负责一部分专家 | 推理阶段,多 GPU 部署 | | 动态专家分配 | 运行时监控专家负载,动态迁移热门专家到空闲 GPU | 长尾负载不均场景 | | 共享专家(Shared Expert) | 设置一个始终激活的共享专家处理通用特征,路由专家只处理 specialized 部分 | DeepSeek-V3 的创新设计 | 🔬 DeepSeek-V3 MoE 架构实践
DeepSeek-V3 是 2025 年 MoE 推理优化的标杆案例:
- 总参数 671B,激活参数仅 37B——用 Dense 模型的推理成本跑出接近 GPT-4o 的效果
- 256 个路由专家 + 1 个共享专家,每个 Token 选 Top-8 路由专家
- 共享专家始终激活,处理通用语言知识;路由专家处理 specialized 领域能力
- 无辅助损失的负载均衡:创新性地用偏置项动态调整路由概率,避免 aux loss 对主任务的干扰
- 多 Token 预测(MTP):训练时同时预测多个未来 Token,推理时可配合投机解码加速
实际推理成本:DeepSeek-V3 的每百万 Token 价格约为 GPT-4o 的 1/10,这就是 MoE 架构的威力���
24.10.2 Speculative Decoding(投机解码)
投机解码是 2025-2026 年推理加速的明星技术。核心思想:用小模型快速生成草稿,大模型验证修正,实现超越大模型自身的推理速度。 🎯 投机解码原理:Draft Model + Target Model 协作
传统自回归解码每生成一个 Token 需要一次完整的前向传播。投机解码的巧妙之处在于:
- Draft Model(草稿模型):参数量小(如 0.5B),生成速度快,一次生成 K 个候选 Token(如 K=4)
- Target Model(目标模型):参数量大(如 72B),精度高,并行验证这 K 个 Token(只需一次前向传播)
- 接受/拒绝采样:逐个比较 Draft 和 Target 的输出分布。如果 Draft 预测的 Token 在 Target 的分布中也有较高概率,则接受;否则拒绝,并用 Target 的分布重新采样
💡 为什么投机解码能加速?
关键洞察:大模型验证 K 个 Token 的成本 ≈ 生成 1 个 Token 的成本(因为可以并行计算)。
- 如果 K=4 个候选全部被接受 → 一次前向传播输出了 5 个 Token(4 个接受 + 1 个修正),等效加速 5 倍
- 如果只有 2 个被接受 → 等效加速 3 倍
- 如果全部被拒绝 → 退化为正常解码,无加速但也无损失
加速比取决于 Draft Model 的预测准确率(接受率),这是投机解码的核心瓶颈。 📊 投机解码加速比的影响因素 | 因素 | 影响 | 优化方向 | | --- | --- | --- | | Draft Model 与 Target Model 的相似度 | 两个模型输出分布越接近,接受率越高,加速比越大 | 用同系列小模型(如 Qwen2-0.5B → Qwen2-72B) | | 草稿长度 K | K 太小→加速不够;K 太大→后面的 Token 接受率下降 | 动态调整 K(通常 4-8) | | 任务类型 | 重复性高的任务(代码、模板文本)接受率高;创造性任务接受率低 | 代码生成、结构化输出场景收益最大 | | Draft Model 的推理速度 | 小模型太慢会抵消加速收益 | Draft Model 应至少比 Target 快 5-10 倍 | Python — vLLM 投机解码启用
# === vLLM 启用投机解码(需要 vLLM v0.6+) ===
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-72B-Instruct \
--speculative-model Qwen/Qwen2.5-0.5B-Instruct \ # Draft Model
--num-speculative-tokens 5 \ # 草稿长度 K=5
--speculative-draft-tensor-parallel-size 1 \ # Draft Model 单卡
--tensor-parallel-size 4 \ # Target Model 4卡
--gpu-memory-utilization 0.9
# === 效果对比 ===
# 不开投机解码:72B 模型 ~40 tok/s
# 开启投机解码:~100-120 tok/s(接受率 ~70% 时)
# 代码生成场景:~150 tok/s(接受率更高)
🔬 2026 前沿:Self-Speculative Decoding
传统投机解码需要两个模型(Draft + Target)。2025-2026 年的新趋势是单模型投机解码:
- Layer Skip:用同一个模型的前几层当"Draft Model"(跳过部分中间层),完整模型当"Target Model"
- Medusa Heads:在模型上额外训练多个预测头,一次预测多个未来 Token,无需独立 Draft Model
- EAGLE:用轻量级头网络预测大模型的隐藏状态,接受率比传统投机解码高 20%+
- DeepSeek-V3 MTP:训练时就内置多 Token 预测能力,推理时天然支持投机解码
优势:无需维护两个模型,显存占用更低,部署更简单。
24.10.3 其他推理优化技术
除了 MoE 和投机解码,2026 年生产环境还有三个高频使用的优化技术: ⚡ 三大工程加速技术 | 技术 | 原理 | 收益 | 支持框架 | | --- | --- | --- | --- | | KV Cache 量化 | 把 KV Cache 从 FP16 压缩到 FP8/INT8/INT4,减少显存占用 | 显存占用降低 2-4 倍,可服务更多并发 | vLLM、SGLang、TGI | | Prefix Caching | 缓存相同 prompt 前缀的 KV Cache,后续请求直接复用 | 首 Token 延迟降低 80%,System Prompt 场景效果显著 | vLLM、SGLang | | Continuous Batching | 动态组 batch,新请求随时加入,完成的请求立即退出,不等齐 | GPU 利用率最大化,吞吐量提升 2-4 倍 | vLLM、SGLang、TGI | #### KV Cache 量化方案详解
KV Cache 是推理时显存占用的大头——上下文越长,KV Cache 越大。对于一个 72B 模型、32K 上下文的请求,KV Cache 可能占到总显存的 50%+。量化 KV Cache 是提升并发的关键手段: 📊 KV Cache 量化方案对比 | 方案 | 精度 | 显存节省 | 精度损失 | 特点 | | --- | --- | --- | --- | --- | | FP8 | 8-bit 浮点 | ~2x | <1% | NVIDIA H100 原生支持,精度最佳,硬件要求高 | | INT8 | 8-bit 整数 | ~2x | ~1% | 通用性好,大多数 GPU 支持,生产首选 | | INT4 | 4-bit 整数 | ~4x | ~3-5% | 显存节省最大,但长上下文场景精度损失明显 | | 混合精度 | FP8+INT4 | ~3x | ~1-2% | 重要层用 FP8,次要层用 INT4,精度与显存兼顾 | Shell — vLLM 启用 KV Cache 量化 + Prefix Caching
# === vLLM 启用 KV Cache FP8 量化 ===
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-72B-Instruct \
--kv-cache-dtype fp8 \ # KV Cache 量化为 FP8
--enable-prefix-caching \ # 启用 Prefix Caching
--tensor-parallel-size 4 \
--gpu-memory-utilization 0.9 \
--max-model-len 32768 # 支持更长上下文
# === 效果对比 ===
# 不开 KV Cache 量化:72B 模型 32K 上下文,最多并发 ~10 请求
# 开启 FP8 量化:并发提升到 ~20 请求(2x)
# 开启 INT4 量化:并发提升到 ~40 请求(4x),但精度有一定损失
# + Prefix Caching:相同 System Prompt 的请求首 Token 延迟降低 80%
🔗 技术组合效果
这些优化技术不是互斥的,可以叠加使用:
- 基线:72B Dense 模型,FP16,无优化 → ~40 tok/s,并发 ~10
- + Continuous Batching → 并发 ~30(吞吐 3x)
- + PagedAttention → 显存利用率 90%+,并发 ~50
- + KV Cache FP8 → 显存再降 2x,并发 ~100
- + Prefix Caching → 首 Token 延迟降低 80%
- + 投机解码 → 生成速度提升 2-3x
- 换成 MoE 模型(DeepSeek-V3) → 计算量降低 18x,推理成本骤降
2026 年的生产级推理服务,通常是以上技术的组合,而非单选。 📋 八股总结 — 面试高频考点
Q1:为什么需要推理框架?模型文件不能直接用吗?
模型文件只是权重矩阵,还需要推理框架把它变成可调用服务:加载到 GPU、处理 Token、执行矩阵运算、解码输出、提供 API 接口、管理并发和显存。没有推理框架,你需要手动写 PyTorch 代码处理显存分配和并发调度。
Q2:Ollama 和 vLLM 的核心区别?各自适合什么场景?
Ollama:极简部署,Mac/PC 即可,一条命令启动,适合个人开发/学习/小规模使用。vLLM:工业级引擎,PagedAttention 显存利用率 90%+,连续批处理吞吐最大化,适合企业生产/高并发。核心区别在于:Ollama 追求易用,vLLM 追求性能。
Q3:PagedAttention 解决了什么问题?
传统推理中每个请求的 KV Cache 需要连续显存空间,预分配浪费+碎片化导致显存利用率只有 20-40%。PagedAttention 把 KV Cache 切成固定大小的页,像 OS 的虚拟内存一样按需分配、跨请求共享(Copy-on-Write),消除碎片,显存利用率提升到 90%+。
Q4:INT4 量化精度损失多少?什么场景下量化不可接受?
INT4 量化精度损失约 3-5%,对话场景下完全可用。但以下场景不可接受:① 数学推理——精度损失可能导致计算错误;② 代码生成——细微差异影响正确性;③ Function Calling——参数格式错误率升高;④ 金融/医疗合规——精度不可妥协。实用原则:对话型 Agent 用 INT4,工具调用型 Agent 用 INT8,合规型 Agent 用 FP16。
Q5:Agent 从 GPT 切换到本地模型为什么只需改一行?
因为所有主流推理框架(Ollama/vLLM/SGLang/TGI)都兼容 OpenAI API 格式。Agent 代码用的是 OpenAI SDK,只需把 base_url 从 api.openai.com 改为 localhost:11434(Ollama)或 gpu-server:8000(vLLM),model 从 gpt-4o 改为本地模型名,其余代码完全不变。
Q6:Tensor Parallel 和 Pipeline Parallel 的区别?
TP 在同一层内按列切分模型矩阵,GPU 间每步都需要 AllReduce 通信,适合同一机器内的多卡(NVLink 高带宽)。PP 按层切分,不同 GPU 负责不同层像流水线接力,通信少,适合跨机器(网络带宽有限)。大模型常用混合方案 TP+PP:先同机器内 TP,再跨机器 PP。
Q7:SGLang 的核心优势是什么?什么场景比 vLLM 更好?
SGLang 的核心优势是结构化生成——通过 RadixAttention(更细粒度的前缀共享)+ 压缩有限状态机,在需要精确约束输出格式(JSON、SQL、代码)的场景下,结构化输出速度比 vLLM 快 3-7 倍。数据提取型 Agent(输出 JSON/SQL)首选 SGLang。
Q8:混合部署策略为什么能节省 70% 成本?
核心逻辑:80% 简单任务(FAQ/分类/提取)用本地开源模型(成本≈GPU运维费),15% 中等任务用本地 INT8 量化模型,只有 5% 复杂推理任务才调用 GPT-4o。总成本 = 5%×GPT价格 + GPU费,远低于 100% 用 GPT。关键是 Agent 框架要支持动态模型路由。
Q9:MoE 模型参数量 671B,为什么推理成本却能和 70B Dense 模型差不多?
MoE 的核心是稀疏激活:虽然总参数 671B,但每个 Token 只路由到 Top-K 个专家(如 K=8),激活参数仅 ~37B。推理计算量 ∝ 激活参数量而非总参数量,所以计算成本相当于 37B Dense 模型。代价是显存——所有 671B 参数都要常驻显存(因为不知道哪个专家会被选中),所以 MoE 是"计算便宜、显存贵"。DeepSeek-V3 通过共享专家 + 无辅助损失负载均衡进一步优化,实际推理成本约为 GPT-4o 的 1/10。
Q10:投机解码的加速比取决于什么?为什么不能无限制加速?
加速比取决于 Draft Model 的预测接受率和草稿长度 K。大模型并行验证 K 个 Token 的成本 ≈ 生成 1 个 Token,如果全部接受则等效加速 K+1 倍。不能无限制加速的原因:① K 越大,后面的 Token 接受率越低(小模型预测越远越不准);② Draft Model 本身也有推理开销,K 太大时小模型的生成时间不可忽略;③ 接受率取决于两个模型输出分布的相似度,创造性任务接受率天然较低。实际加速比通常在 2-3x,代码生成等高重复场景可达 4-5x。
Q11:KV Cache 量化有哪些方案?生产环境怎么选?
主要有四种方案:① FP8(精度损失 <1%,显存节省 2x,需 H100+ 硬件,精度最佳);② INT8(精度损失 ~1%,显存节省 2x,通用性好,生产首选);③ INT4(精度损失 3-5%,显存节省 4x,长上下文场景精度损失明显);④ 混合精度(重要层 FP8 + 次要层 INT4,精度与显存兼顾)。生产环境选择原则:有 H100 选 FP8,通用 GPU 选 INT8,极端显存约束选 INT4,追求均衡选混合精度。