9959 字
约 33 分钟
1
第24章 推理框架与模型服务化

第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,追求均衡选混合精度。

第24章 推理框架与模型服务化
http://www.clxhxhhr.top/posts/726/
作者
clxstart
发布于
2026-09-18
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。