← 返回目录 模块 8 / 8

7.5 AI Agent 与工具使用

7.5.1 Agent 架构

核心概念

AI Agent(智能体)是以大语言模型为核心大脑(Brain),结合工具使用(Tool Use)、规划(Planning)和记忆(Memory)等模块,能够自主感知环境、做出决策并执行行动的智能系统。Agent 的能力边界远超纯对话模型——它不仅能"说",还能"做"。

核心四模块

graph TD
    subgraph AI_Agent ["AI Agent"]
        Brain["Brain (推理+决策)"]
        LLM["LLM (核心模型)"]
        Tools["Tools (工具集)"]
        Planning["Planning (规划策略)"]
        Memory["Memory (记忆系统)"]
        ST["短期/长期记忆存储"]
    end
    Brain --> LLM
    Brain --> Tools
    Brain --> Planning
    Brain --> Memory
    Memory --> ST
  1. Brain(LLM):负责理解用户意图、做出决策、生成行动计划。核心能力包括推理、上下文理解和指令遵循。
  2. Tool Use(工具使用):Agent 调用外部 API 和工具的能力,使 LLM 突破纯文本生成的限制,与真实世界交互。
  3. Planning(规划):将复杂任务分解为可执行的子步骤,支持动态调整和错误恢复。
  4. Memory(记忆):管理 Agent 的上下文信息,包括短期记忆(对话历史中的关键信息)和长期记忆(持久化存储的知识和经验)。

7.5.2 Function Calling / Tool Use

核心概念

OpenAI Tool Calling 协议

OpenAI 定义了标准的 function calling 格式,已成为业界事实标准:

# Agent 定义可用工具
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "获取指定城市的当前天气",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "城市名称"},
                    "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
                },
                "required": ["city"]
            }
        }
    }
]

# LLM 判断是否需要调用工具
response = client.chat.completions.create(
    model="qwen2.5-72b",
    messages=[{"role": "user", "content": "北京今天冷吗?"}],
    tools=tools,
    tool_choice="auto"  # auto: 模型自主决定; required: 必须调用工具
)

# 模型输出 tool call
# response: {
#   "tool_calls": [{
#       "id": "call_xxx",
#       "function": {"name": "get_weather", "arguments": '{"city": "北京", "unit": "celsius"}'}
#   }]
# }

# Agent 执行工具并将结果返回给 LLM
tool_result = get_weather(city="北京", unit="celsius")
# 将结果作为新 message 追加到对话
messages.append(response.choices[0].message)
messages.append({
    "role": "tool",
    "content": str(tool_result),
    "tool_call_id": "call_xxx"
})

# LLM 根据工具结果生成最终回复
final_response = client.chat.completions.create(
    model="qwen2.5-72b",
    messages=messages,
    tools=tools
)

vLLM 的 Tool Calling 支持

vLLM 通过 OpenAI 兼容 API 原生支持 function calling:

# vLLM 服务端支持的 function calling(通过 OpenAI 兼容 API)
# 使用 vLLM 的 chat/tool 端点
curl http://localhost:8000/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "meta-llama/Llama-3.1-70B-Instruct",
        "messages": [
            {"role": "user", "content": "搜索一下最近的 AI 新闻"}
        ],
        "tools": [{
            "type": "function",
            "function": {
                "name": "search_web",
                "description": "在互联网上搜索信息",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "query": {"type": "string"}
                    },
                    "required": ["query"]
                }
            }
        }]
    }'

底层机制:

  • vLLM 将 tools 定义序列化为 system prompt 格式化的工具描述
  • 模型在生成过程中输出 tool_calls 结构化输出
  • 支持 JSON mode 和 grammar-constrained generation 来确保工具调用格式正确

支持的模型:需要经过指令微调且支持 function calling 的模型(如 Llama-3.1-Instruct、Qwen-2.5-Instruct、DeepSeek-V2-Chat 等)。

7.5.3 Planning 策略

核心概念

ReAct(Reasoning + Acting)

ReAct 是当前最广泛使用的 Agent 规划框架,将推理(Reasoning)和行动(Acting)交替进行:

Thought: 用户想知道北京今天是否冷。我需要先查询天气。
Action: get_weather({"city": "北京", "unit": "celsius"})
Observation: {"temperature": 5, "condition": "晴"}
Thought: 北京今天温度 5°C,属于较冷的天气。我应该建议用户多穿衣服。
Final Answer: 北京今天气温 5°C,比较冷,建议穿厚外套。

ReAct 循环:Thought → Action → Observation → Thought → Action → ... → Final Answer

Chain-of-Thought(CoT)

CoT 是让模型在给出最终答案前显式展示推理过程的提示技术:

Q: 小明有 10 个苹果,给了小红 3 个,又从超市买了 5 个。他总共有多少个?
A:
一开始有 10 个苹果。
给了小红 3 个,剩下 10 - 3 = 7 个。
买了 5 个,现在有 7 + 5 = 12 个。
所以小明总共有 12 个苹果。

CoT vs ReAct:CoT 只有"思考"没有"行动";ReAct 在思考之外还会调用工具获取新信息,适合需要与外部环境交互的场景。

Tree-of-Thought(ToT)

ToT 扩展了 CoT 的线性推理,维护一个"推理树"并同时探索多个分支:

思考分支 1: ... ❌ (推理错误)
              ↓
初始问题 → → 思考分支 2: ... → 思考 2a: ... ✓ (找到答案)
              ↓
思考分支 3: ... → 思考 3a: ... → 思考 3b: ... (仍在进行中)

ToT 在每个推理步骤生成多个候选思路,使用评估函数(如 LLM 自身或启发式方法)评估每个分支的可行性,并剪枝掉低质量分支。计算成本是 CoT 的 N 倍(N = 分支数 × 深度),但适合需要多步探索的复杂问题。

三种策略对比

策略推理结构工具交互计算成本错误恢复适用场景
CoT线性链无低无数学、逻辑、常识推理
ReAct推理-行动交替循环是中通过新 Tool 输出纠正信息获取、问答、搜索
ToT树形搜索可选高探索多个分支复杂问题求解、设计

7.5.4 Memory 系统

核心概念

三级记忆模型

受认知科学启发,Agent 的记忆系统通常分为三级:

短期记忆 (Working Memory)
├── 当前对话上下文(Context Window 内)
├── 当前任务的中间状态和变量
└── 生命周期: 当前回合结束即清除

工作记忆 (Episodic Buffer)
├── 当前对话轮次的关键信息
├── 最近完成的操作和结果
└── 生命周期: 会话存活期

长期记忆 (Long-term Memory)
├── 用户偏好和历史行为模式
├── 领域知识和经验积累
└── 生命周期: 跨会话持久化

实现方式

短期记忆:直接利用 LLM 的 context window,将历史对话和中间状态拼接到当前的 prompt 中。

长期记忆:

  • 向量数据库存储:将过去交互的关键信息编码为 embedding,需要时通过语义检索获取
  • 知识图谱存储:提取实体和关系,构建结构化的知识网络
  • 文件系统存储:将记忆序列化为 JSON/Markdown 文件,按时间或主题组织
# Agent 记忆的向量检索实现(简化)
class AgentMemory:
    def __init__(self, vector_db, llm_client):
        self.vector_db = vector_db
        self.llm = llm_client

    def add_memory(self, text, metadata=None):
        # 将重要信息编码为向量并存储
        embedding = self.llm.embeddings.create(input=text).data[0].embedding
        self.vector_db.insert(embedding, text, metadata)

    def recall(self, query, k=5):
        # 基于当前上下文检索相关的历史记忆
        query_embedding = self.llm.embeddings.create(input=query).data[0].embedding
        results = self.vector_db.search(query_embedding, top_k=k)
        return [r.text for r in results]

7.5.5 Multi-agent 系统

核心概念

Multi-agent 系统由多个 Agent 协作完成复杂任务。每个 Agent 负责一个专门的子任务或领域,通过消息传递和任务协调实现 1+1>2 的效果。

主流框架对比

框架核心思想通信机制编排方式适用场景
AutoGen多 Agent 对话式协作自然语言消息可编程对话图研究、原型开发
CrewAI角色扮演式协作任务分配 + 工具共享YAML 配置自动化工作流
LangGraph有状态图计算边传递状态状态机生产级复杂流程

AutoGen 示例

# AutoGen 的多 Agent 协作
from autogen import AssistantAgent, UserProxyAgent, GroupChat, GroupChatManager

# 定义三个专用 Agent
planner = AssistantAgent(
    name="Planner",
    system_message="你是一个计划制定者,负责分解任务为子步骤。",
    llm_config={"config_list": [{"model": "gpt-4", "api_key": "..."}]}
)

coder = AssistantAgent(
    name="Coder",
    system_message="你是一个 Python 程序员,负责编写代码。",
    llm_config={"config_list": [{"model": "gpt-4", "api_key": "..."}]}
)

critic = AssistantAgent(
    name="Critic",
    system_message="你是一个代码评审员,负责检查代码质量。",
    llm_config={"config_list": [{"model": "gpt-4", "api_key": "..."}]}
)

# 创建群组对话
group_chat = GroupChat(
    agents=[planner, coder, critic],
    messages=[],
    max_round=10
)
manager = GroupChatManager(groupchat=group_chat, llm_config={...})

# 启动协作
user_proxy = UserProxyAgent(name="User", ...)
user_proxy.initiate_chat(
    manager,
    message="帮我写一个计算斐波那契数列的 Python 脚本"
)

Multi-agent 架构设计原则

  1. 单一职责:每个 Agent 负责一个明确定义的子领域,避免职责重叠
  2. 明确通信协议:Agent 之间的消息格式需要结构化(而非纯自然语言),减少歧义
  3. 冲突解决机制:当多个 Agent 的输出不一致时,需要有仲裁策略(如投票、超级 Agent 裁决)
  4. 状态共享:关键全局状态(如任务进度、已确认的事实)需要在 Agent 间同步

7.5.6 MCP(Model Context Protocol)

核心概念

MCP(Model Context Protocol)是 Anthropic 在 2024 年底提出的开放标准协议,旨在解决 AI 模型与外部工具和数据源之间的标准化连接问题。它相当于"AI 应用的 USB-C 接口"——为模型提供一个统一的方式来发现、调用和管理外部工具和数据。

架构

graph LR
    LLM["LLM (Host)"]
    Client["MCP Client (应用层)"]
    Server["MCP Server (工具/数据)"]
    Tools["Tools"]
    Resources["Resources"]

    LLM <--> Client
    Client <--> Server
    Server --> Tools
    Server --> Resources

核心组件:

  1. MCP Host:宿主应用(如 Claude Desktop 或 VS Code 的 Claude 插件),负责与模型交互
  2. MCP Client:通用客户端抽象,管理 MCP Server 的连接和通信
  3. MCP Server:工具和数据源的标准化适配器,提供:
    • Tools(工具):模型可调用的功能(如搜索、数据库查询、文件操作)
    • Resources(资源):模型可读取的数据(如文档、配置、代码)
    • Prompts(提示):预定义的交互模板

关键特性

特性MCPOpenAI Function Calling传统 API 集成
标准化开放标准,厂商中立OpenAI 专有无标准
工具发现自动(server 声明)手动(应用定义)手动
安全性隔离的 server 进程应用内执行无隔离
多工具组合天然支持需手动编排需手动编排
资源暴露结构化资源暴露仅支持工具调用无

MCP 与 vLLM 的关系

  • MCP 解决的是工具接入标准问题,vLLM 解决的是模型推理效率问题
  • vLLM 可以作为 MCP Host 中的推理引擎
  • vLLM 的 API Server 本身可作为 OpenAI-compatible endpoint 被 MCP Client 使用
  • 两者互补而非竞争:vLLM 提供高效的推理,MCP 提供标准化的工具接口

7.6 多模态(Multimodal)

7.6.1 Vision-Language Models(VLM)

核心概念

视觉-语言模型(Vision-Language Model, VLM)是一种能够同时处理图像和文本输入的多模态模型。典型架构为:图像编码器提取视觉特征 → 连接器对齐模态 → 语言模型生成输出。

主流 VLM 架构

标准 VLM 架构:

Image → Vision Encoder (ViT/CLIP) → Vision Tokens
                                              │
                                              ▼
                                    Connector/Projector
                                              │
                                              ▼
                              Text Embeddings + Vision Embeddings
                                              │
                                              ▼
                                    Language Model (LLM)
                                              │
                                              ▼
                                     Generated Text

代表模型

模型视觉编码器连接器语言模型特色
LLaVACLIP ViT-L/14简单线性投影LLaMA/Vicuna简洁高效,开创性工作
LLaVA-NeXTCLIP ViT-L/14多层 MLPLLaMA-3/Phi-3支持高分辨率输入
Qwen2-VLSigLIP ViTQwenVLBlock (Cross-Attention)Qwen2动态分辨率,视频理解
InternVL 2InternViTMLP + PerceiverInternLM2超大视觉编码器(6B)
CLIPViT 或 ResNet对比学习 Head无(仅对齐训练)对比预训练,非生成式

7.6.2 图像编码器

核心概念

Vision Transformer(ViT)

ViT(Vision Transformer)将图像切分为固定大小的 patches(如 16×16),并将每个 patch linear projection 为 embedding,然后通过标准 Transformer 编码器处理。

Input Image (224x224x3)
    │
    ▼
Patch Embedding: 14×14=196 patches, each 16×16×3 → 196×768
    │
    ▼
Position Embedding + [CLS] Token
    │
    ▼
Transformer Encoder × L layers
    │
    ▼
Output: 196+1 tokens × hidden_dim

ViT vs CNN:

特性ViTCNN (ResNet)
感受野全局(self-attention)局部(卷积核)
归纳偏置少(需要更多数据)多(平移不变性)
参数效率高(共享较少)中
大模型扩展好有平台期

CLIP 视觉编码器

CLIP(Contrastive Language-Image Pre-training)的视觉编码器可以是 ViT 或 ResNet。它通过对比学习将图像和文本对齐到同一个联合嵌入空间。

训练目标(InfoNCE 损失):

对于 batch 中的 N 个(image, text)对:

\mathcal{L}_{\text{CLIP}} = -\frac{1}{2N} \left[ \sum_{i=1}^{N} \log \frac{\exp(I_i \cdot T_i / \tau)}{\sum_{j=1}^{N} \exp(I_i \cdot T_j / \tau)} + \sum_{i=1}^{N} \log \frac{\exp(T_i \cdot I_i / \tau)}{\sum_{j=1}^{N} \exp(T_i \cdot I_j / \tau)} \right]

其中 I_i 是图像嵌入,T_i 是文本嵌入,\tau 是温度参数。

CLIP 向量空间的语义属性(通过对比学习获得):

  • "狗的图片"的嵌入 ≈ "狗"的文本嵌入
  • 跨模态检索:用文本搜索图像或用图像搜索文本

SigLIP

SigLIP(Sigmoid Loss for Language Image Pre-training)是 CLIP 的改进变体。使用 sigmoid 损失替代 CLIP 的对比损失,训练更高效:

\mathcal{L}_{\text{SigLIP}} = -\frac{1}{N} \sum_{i=1}^{N} \sum_{j=1}^{N} \log \frac{1}{1 + e^{-z_{ij} \cdot (I_i \cdot T_j - b)}}

其中 z_{ij} = 1 当 i=j(正样本),z_{ij} = -1 当 i\neq j(负样本)。SigLIP 不需要全局归一化(softmax over batch),批大小 N 可以更小,训练效率更高。

7.6.3 多模态对齐

核心概念

投影层(Projection Layer)

最简单的连接器。将视觉编码器的输出映射到语言模型的输入嵌入空间:

H_{\text{proj}} = W_{\text{proj}} \cdot H_{\text{vision}} + b_{\text{proj}}

其中 H_{\text{vision}} \in \mathbb{R}^{N \times d_{\text{vision}}},W_{\text{proj}} \in \mathbb{R}^{d_{\text{vision}} \times d_{\text{lm}}}。

这是 LLaVA 的核心设计理念——仅用一个可学习的线性投影层实现视觉和文本的对齐。简单但有效,因为 LLM 有足够的容量"学习"理解视觉 token。

Q-Former

Q-Former(Querying Transformer)是 BLIP-2 中提出的更复杂的连接器。它使用一组可学习的 query 向量,通过交叉注意力从视觉特征中"查询"相关信息:

Visual Features (from frozen vision encoder)
          │
          ▼
    ┌─────────────────┐
    │  Q-Former       │
    │  ┌───────────┐  │
    │  │ Queries   │  │  ← 可学习的查询向量
    │  │ (32-64个)  │  │
    │  │           │  │
    │  │ Cross-    │  │
    │  │ Attention │  │  ← queries 与 visual features 交互
    │  └───────────┘  │
    └────────┬────────┘
             │
             ▼
    Fixed number of visual tokens → Language Model

Q-Former 的优势:

  • 输出的视觉 token 数固定(如 32 或 64 个),与输入图像分辨率无关
  • 通过交叉注意力提取与任务最相关的视觉信息
  • 更适合处理高分辨率或变分辨率图像

7.6.4 vLLM 的多模态支持

vLLM 特性

vLLM 的多模态架构

vLLM 通过 SupportsMultiModal 接口和 multimodal 模块支持 VLM 推理:

# vLLM 的多模态模型注册
_MULTIMODAL_MODELS = {
    "LlavaForConditionalGeneration": ("llava", "LlavaForConditionalGeneration"),
    "LlavaNextForConditionalGeneration": ("llava_next", "LlavaNextForConditionalGeneration"),
    "Qwen2VLForConditionalGeneration": ("qwen2_vl", "Qwen2VLForConditionalGeneration"),
    "InternVLChatModel": ("internvl", "InternVLChatModel"),
    "CLIPModel": ("clip", "CLIPEmbeddingModel"),
    "SiglipModel": ("siglip", "SiglipEmbeddingModel"),
}

pixel_values 处理流程

vLLM 的多模态输入处理遵循严格的流水线:

Image Input
    │
    ▼
Image Processor (HuggingFace transformers)
    │  预处理: resize, normalize, tensor conversion
    ▼
pixel_values: torch.Tensor [batch, 3, 336, 336]
    │
    ▼
Vision Encoder (ViT/CLIP/SigLIP)
    │  编码为视觉 token
    ▼
image_embeds: torch.Tensor [num_vision_tokens, hidden_dim]
    │
    ▼
_merge_multimodal_embeddings
    │  按 multimodal mask 插入视觉 token
    ▼
inputs_embeds (text + vision)
    │
    ▼
Language Model

代码实现:

class LlavaForConditionalGeneration(nn.Module):
    def forward(self, input_ids, positions, pixel_values=None, ...):
        # 1. 文本 embedding
        inputs_embeds = self.language_model.get_input_embeddings()(input_ids)

        # 2. 如果有图像输入,处理视觉 token
        if pixel_values is not None:
            image_inputs = self._parse_and_validate_inputs(
                pixel_values=pixel_values,
                ...
            )
            # 通过 CLIP vision tower 编码
            image_embeds = self.vision_tower(image_inputs["pixel_values"])
            # 通过投影层映射到语言模型嵌入空间
            image_embeds = self.multi_modal_projector(image_embeds)

            # 3. 合并文本和视觉嵌入
            inputs_embeds = _merge_multimodal_embeddings(
                inputs_embeds, image_embeds, is_multimodal
            )

        # 4. 标准语言模型前向传播
        return self.language_model(inputs_embeds=inputs_embeds, ...)

vLLM 多模态 API

# 通过 OpenAI 兼容 API 使用视觉模型
curl http://localhost:8000/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "llava-hf/llava-v1.6-mistral-7b-hf",
        "messages": [
            {
                "role": "user",
                "content": [
                    {"type": "image_url", "image_url": {"url": "https://example.com/cat.jpg"}},
                    {"type": "text", "text": "请描述这张图片"}
                ]
            }
        ]
    }'

vLLM 多模态支持的功能限制

功能纯文本模型多模态模型
PagedAttention完整支持支持(视觉 token 也被 block 管理)
Continuous Batching完整支持支持
Chunked Prefill支持部分支持(视觉 token 处理限制)
Prefix Caching完整支持不支持(视觉输入导致不同的 block hash)
Speculative Decoding支持不支持
LoRA支持部分模型支持

7.6.5 常见多模态模型

核心概念

LLaVA-NeXT

LLaVA(Large Language and Vision Assistant)系列是最广泛使用的开源 VLM 之一。

LLaVA-NeXT 的关键改进:

  • 高分辨率输入支持(336×336 → 最大 672×672 或 4×336 拼接)
  • 使用 AnyRes 策略将高分辨率图像分割为多个子图
  • 使用 Llama-3 或 Phi-3 作为语言模型

InternVL 2

InternVL 2 是目前性能最强的开源 VLM 之一,视觉编码器达到 6B 参数:

  • 视觉编码器:InternViT (6B 参数,300×300 patch)
  • 连接器:MLP + Perceiver Resampler
  • 语言模型:InternLM2 (1.8B ~ 20B)

在 MMMU、MathVista 等基准上超过 GPT-4V。

Qwen2-VL

Qwen2-VL 是阿里通义千问的多模态版本:

  • 视觉编码器:SigLIP ViT (动态分辨率)
  • 连接器:QwenVLBlock(交叉注意力 + 多层感知器)
  • 支持动态分辨率(将图像缩放到不同尺寸,提取多尺度特征)
  • 支持视频输入(帧采样 + 时间位置编码)

7.7 模型压缩与优化

7.7.1 Pruning(剪枝)

核心概念

剪枝(Pruning)通过移除模型中不重要的权重来减小模型大小和计算成本。根据粒度的不同,分为结构化剪枝和非结构化剪枝。

非结构化剪枝

逐权重剪枝,将低于阈值的权重置零:

W_{\text{pruned}} = W \odot M, \quad M_{ij} = \begin{cases} 1 & \text{if } |W_{ij}| > \tau \\ 0 & \text{otherwise} \end{cases}

其中 \tau 是剪枝阈值(如权重绝对值分布的 top-90% 分位数),M 是掩码矩阵。

特点:

  • 压缩比高(可达到 90% 以上的稀疏度)
  • 权重矩阵变为稀疏格式,需要专用硬件或稀疏库加速
  • 通用 GPU 上加速不明显(非结构化稀疏利用率低)

结构化剪枝

按通道、行或注意力头移除权重:

W_{\text{structured}} = W[I_{\text{keep}}, :]

其中 I_{\text{keep}} 是根据重要性评分(如权重的 L1/L2 范数、梯度幅度、激活值统计)选出的保留通道索引。

常见结构化剪枝粒度:

剪枝粒度单位移除方式加速效果精度影响
注意力头Head移除完整的注意力头中等通常可控
隐藏维度Feature移除完整的隐藏维度高较大
FFN 中间维度Neuron移除 MLP 中间层的神经元高较大
层Layer移除完整 Transformer 层极高很大

特点:

  • 压缩比相对较低(通常 20-50%)
  • 权重矩阵保持稠密格式,无需特殊硬件
  • 在通用 GPU 上即可获得实质性加速

剪枝后的微调恢复

直接剪枝后模型精度会下降,需要通过微调恢复:

# 剪枝 + 微调的三步流程
# Step 1: 计算权重重要性
importance = compute_weight_importance(model, calibration_data)

# Step 2: 应用剪枝掩码
for name, param in model.named_parameters():
    if name in prunable_layers:
        threshold = get_threshold(importance[name], sparsity_target)
        mask[name] = (importance[name] > threshold).float()
        param.data *= mask[name]

# Step 3: 微调恢复精度
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-5)
for batch in training_data:
    loss = criterion(model(batch))
    loss.backward()
    # 确保剪枝的权重在梯度更新后仍保持为零
    for name, param in model.named_parameters():
        if name in mask:
            param.grad *= mask[name]
    optimizer.step()

7.7.2 Distillation(蒸馏)

核心概念

知识蒸馏(Knowledge Distillation)是使用一个更大的"教师模型"(Teacher Model)来指导一个小型"学生模型"(Student Model)的训练。学生模型通过学习教师模型的输出分布,获得比单独训练更好的性能。

Logit-based Distillation

学生模型不仅学习真实标签,还学习教师模型的 softmax 输出分布(logits)。核心损失函数是 Hinton 等人提出的蒸馏损失:

\mathcal{L}_{\text{KD}} = \alpha \cdot \mathcal{L}_{\text{CE}}(y, \sigma(z_s)) + (1 - \alpha) \cdot \tau^2 \cdot \mathcal{L}_{\text{KL}}\left( \sigma\left(\frac{z_t}{\tau}\right), \sigma\left(\frac{z_s}{\tau}\right) \right)

其中:

  • z_t、z_s:教师和学生模型的 logits
  • \tau:温度参数(控制 softmax 的"软硬"程度,\tau > 1 使分布更平滑)
  • \sigma:softmax 函数
  • \alpha:两项损失的权重平衡
  • \mathcal{L}_{\text{CE}}:交叉熵损失(真实标签)
  • \mathcal{L}_{\text{KL}}:KL 散度(教师 vs 学生分布)

高温度的作用:当 \tau 较大时,softmax 输出的概率分布更加平滑,包含了更多的"暗知识"(dark knowledge),如教师模型认为哪些错误类别与正确类别更相似。

Feature-based Distillation

不仅匹配输出分布,还匹配中间层的特征表示:

\mathcal{L}_{\text{feature}} = \sum_{l \in \mathcal{L}_{\text{align}}} \| f_l^s - W_l f_l^t \|_2^2

其中 f_l^s 和 f_l^t 是学生和教师模型在第 l 层的隐藏状态,W_l 是适配维度差异的线性投影。

蒸馏 vs 剪枝 vs 量化对比

维度蒸馏剪枝量化
原理学习教师输出分布移除不重要权重降低数值精度
压缩方式可使用更小的学生架构移除权重通道/元素使用更少 bit 表示
是否需重新训练是需微调恢复不一定(PTQ 无需)
常见压缩比2-10x2-4x2-4x
精度损失通常最小(教师指导)中高(高稀疏度时)低(FP8/INT8)
与硬件关系无关需稀疏硬件/N:M需 Tensor Core 支持

7.7.3 量化感知训练(QAT)

核心概念

量化感知训练(Quantization-Aware Training, QAT)是在训练过程中模拟低精度推理的计算误差,让模型参数适应量化噪声。与训练后量化(PTQ)不同,QAT 将量化视为训练的一部分,通常可以获得更好的精度-效率权衡。

Fake Quantization 训练流程

QAT 使用"fake quantization"在训练的前向传播中模拟量化效果,但反向传播仍然使用全精度梯度:

前向传播:
W_fp32 → FakeQuant(W_fp32, scale, zero_point) → W_int8/dequant → W_fp32 (近似)
                                                                      │
                                                                      ▼
                                                            x @ W_fp32 (量化后的值)
                                                                      │
                                                                      ▼
                                                                  损失计算

反向传播:
损失 ← 全精度梯度(使用 Straight-Through Estimator, STE)
       |
       └── ∂Loss/∂W_fp32 ≈ ∂Loss/∂FakeQuant(W_fp32)  (STE 近似)

FakeQuant 算子的核心操作:

W_{\text{fake}} = \text{round}\left( \frac{W}{\Delta} \right) \cdot \Delta

其中 \Delta = \frac{\max(|W|)}{2^{N-1} - 1} 是量化步长,N 是目标位宽(如 8 位)。W_{\text{fake}} 是量化和反量化后的结果,在训练中用于前向传播。

STE(Straight-Through Estimator):round 操作的导数为零(或不存在),无法进行反向传播。STE 将 round 操作的梯度近似为"直通"(即恒等映射):

\frac{\partial \mathcal{L}}{\partial W} \approx \frac{\partial \mathcal{L}}{\partial W_{\text{fake}}}

QAT vs PTQ 对比

维度PTQ(训练后量化)QAT(量化感知训练)
是否需要训练否是
所需数据少量校准数据(~1K samples)训练数据(~10K+ samples)
计算成本极低(几分钟)中等(额外训练 10-20% 时间)
精度保留通常较好(INT8 损失 <1%)更好(接近 FP16 精度)
适用极端量化差(INT4 损失大)好(INT4 可接近 FP16)
灵活性固定量化方案可优化 scale/zero_point

量化方法的压缩比

精度位数内存节省(vs FP16)推理加速(典型)精度影响
FP1616基线基线基线
FP8 (E4M3)8~50%~1.5-2x<1% 损失
INT88~50%~1.5-2x<1% 损失
INT4 (AWQ/GPTQ)4~75%~2-3x1-3% 损失
INT4 + FP16 混合4-16灵活~2x可控
NF4 (QLoRA)4~75%~1.5x微调后接近基线

7.7.4 各压缩方法综合对比

对比总结
压缩方法压缩比精度损失训练成本推理加速硬件约束适用场景
非结构化剪枝5-10x (90%)2-5%高(需微调)弱(通用 GPU)稀疏硬件/NVIDIA N:M模型存储压缩
结构化剪枝2-4x1-3%高(需微调)好无延迟敏感场景
Logit 蒸馏2-10x0-2%高(完整训练)好(学生小模型)无部署小模型
PTQ (INT8)2x<1%极低1.5-2xINT8 Tensor Core快速部署
PTQ (INT4)4x1-3%低2-3x部分 GPU大模型部署
QAT (INT4)4x<1%中2-3x部分 GPU生产级部署
AWQ/GPTQ4x1-2%低(微调 scale)2-3x部分 GPU流行方案
混合方法8-16x2-5%极高3-5x多种约束叠加端侧部署

混合压缩(如剪枝 + 量化 + 蒸馏)可以叠加压缩收益,但精度损失也会叠加。典型的端侧部署方案是:先在超大模型上进行蒸馏得到中型教师,然后进行结构化剪枝和 INT4 量化,最终得到能在手机上运行的模型。

7.8 生产部署基础概念

7.8.1 vLLM 环境变量与配置体系

vLLM 特性

核心启动参数

vLLM 的服务化配置参数覆盖模型加载、推理调度、内存管理和分布式执行等各方面:

# vLLM 服务启动的完整配置示例
python -m vllm.entrypoints.openai.api_server \
    # 模型与精度
    --model meta-llama/Llama-3.1-70B-Instruct \
    --dtype bfloat16 \
    --kv-cache-dtype fp8 \              # KV Cache 量化

    # 内存管理
    --gpu-memory-utilization 0.90 \      # GPU 显存利用率上限
    --max-model-len 65536 \              # 最大序列长度
    --max-num-seqs 256 \                 # 最大并发请求数

    # 调度优化
    --enable-chunked-prefill \           # 开启 Chunked Prefill
    --enable-prefix-caching \            # 开启 Prefix Caching

    # 分布式推理
    --tensor-parallel-size 4 \           # 张量并行度
    --pipeline-parallel-size 2 \         # 流水线并行度

    # 性能调优
    --block-size 16 \                    # KV Cache block 大小
    --max-num-batched-tokens 4096 \      # 单批最大 token 数
    --max-num-seqs 256 \

    # 服务配置
    --port 8000 \
    --uvicorn-log-level info

关键配置参数详解

参数默认值作用域说明
gpu-memory-utilization0.90内存GPU 显存用于模型的百分比(含权重 + KV Cache)
max-model-len(模型默认)内存最大序列长度,超出此长度的请求被拒绝
max-num-seqs256调度batch 中的最大请求数
max-num-batched-tokens2048调度Chunked Prefill 的单批最大 token 数
block-size16内存PagedAttention 的 block token 数
enable-chunked-prefillFalse调度是否启用 Chunked Prefill 混合调度
enable-prefix-cachingFalse缓存是否启用基于 block hash 的 Prefix Cache
tensor-parallel-size1分布式张量并行 GPU 数量
pipeline-parallel-size1分布式流水线并行 GPU 数量
kv-cache-dtypeauto内存KV Cache 精度(auto/FP8/FP8_E4M3)
quantizationNone精度模型权重量化方法(awq/gptq/fp8)
max-loras0LoRA同时加载的 LoRA 适配器数量
enable-loraFalseLoRA是否启用 LoRA 支持

7.8.2 Kubernetes 基础

核心概念

Kubernetes(K8s)是容器编排平台,是 LLM 服务生产部署的事实标准。

基本架构

graph TD
    subgraph Kubernetes_Cluster ["Kubernetes Cluster"]
        subgraph Node1 ["Node 1"]
            PodA["Pod: vLLM-A"]
        end
        subgraph Node2 ["Node 2"]
            PodB["Pod: vLLM-B"]
        end
        subgraph Node3 ["Node 3"]
            PodC["Pod: Router"]
        end
        Service["Service (负载均衡)"]
    end
    PodA --> Service
    PodB --> Service
    PodC --> Service

核心资源对象

资源作用在 vLLM 部署中的用途
Pod最小部署单元,包含一个或多个容器每个 vLLM 实例运行在一个 Pod 中
Service将一组 Pod 暴露为稳定的网络端点对外暴露 vLLM 的 API endpoint
Deployment声明式 Pod 管理,支持滚动更新管理 vLLM Pod 的生命周期和版本
Ingress外部 HTTP/S 流量到 Service 的路由配置域名、TLS 终止、路径路由
ConfigMap非机密性配置存储存储 vLLM 的启动参数和配置
Secret机密配置存储(API Key 等)存储模型仓库的访问凭证
HPA基于指标自动扩缩 Pod根据请求队列长度自动扩缩 vLLM

vLLM Deployment YAML 示例

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vllm-llama-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: vllm-llama
  template:
    metadata:
      labels:
        app: vllm-llama
    spec:
      containers:
      - name: vllm
        image: lmcache/vllm-openai:latest
        command: ["python", "-m", "vllm.entrypoints.openai.api_server"]
        args:
          - "--model"
          - "meta-llama/Llama-3.1-8B-Instruct"
          - "--dtype"
          - "bfloat16"
          - "--gpu-memory-utilization"
          - "0.90"
          - "--max-num-seqs"
          - "64"
        ports:
        - containerPort: 8000
        resources:
          requests:
            nvidia.com/gpu: 1
            memory: "64Gi"
            cpu: "10"
          limits:
            nvidia.com/gpu: 1
            memory: "80Gi"
            cpu: "16"
        readinessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 30
          periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: vllm-service
spec:
  selector:
    app: vllm-llama
  ports:
  - port: 8000
    targetPort: 8000
  type: ClusterIP

7.8.3 自动扩缩容

核心概念

HPA(Horizontal Pod Autoscaler)

HPA 基于观察到的指标自动调整 Pod 副本数。在 vLLM 部署中,通常使用 KEDA(Kubernetes Event-driven Autoscaling)实现基于自定义指标(如请求队列长度)的更精确扩缩容。

基于 KEDA 的 vLLM HPA 配置:

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: vllm-scaledobject
spec:
  scaleTargetRef:
    name: vllm-llama-deployment
  minReplicaCount: 1
  maxReplicaCount: 10
  triggers:
  - type: prometheus
    metadata:
      serverAddress: http://prometheus:9090
      metricName: vllm_num_requests_waiting
      query: |
        sum(rate(vllm:num_requests_waiting_total[2m]))
      threshold: "5"
  advanced:
    restoreToOriginalReplicaCount: false
    horizontalPodAutoscalerConfig:
      behavior:
        scaleDown:
          stabilizationWindowSeconds: 360  # 缩容冷却窗口(避免抖动)
          policies:
          - type: Percent
            value: 50
            periodSeconds: 60
        scaleUp:
          stabilizationWindowSeconds: 0
          policies:
          - type: Pods
            value: 2
            periodSeconds: 30

扩缩容决策逻辑:

  • 扩容条件:当等待队列长度 > 5 且持续 > 30 秒后触发扩容
  • 缩容条件:当等待队列长度保持 < 3 且持续 > 6 分钟后触发缩容
  • 冷却窗口:缩容冷却 360 秒,避免因请求波动频繁启停

VPA(Vertical Pod Autoscaler)

VPA 调整 Pod 的资源请求(CPU/内存/GPU),而非副本数。针对 vLLM 场景:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: vllm-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: vllm-llama-deployment
  updatePolicy:
    updateMode: "Off"  # 仅提供建议,不自动调整
  resourcePolicy:
    containerPolicies:
    - containerName: "*"
      controlledResources: ["memory", "cpu"]
      controlledValues: RequestsAndLimits

GPU 扩缩容的特殊性:Kubernetes 中 GPU 是稀缺的"扩展资源",HPA 无法基于 GPU 利用率直接扩缩。实际做法是:

  1. 通过 Prometheus 采集 GPU 指标(DCGM Exporter)
  2. 根据请求队列长度间接推断 GPU 压力
  3. 使用 KEDA 的 prometheus trigger 实现 GPU 感知扩缩容

7.8.4 监控体系

核心概念

Prometheus 指标

vLLM 暴露 Prometheus 格式的内置指标:

指标类别指标名类型说明
延迟vllm:ttft_secondsHistogram首 token 延迟分布
延迟vllm:tpot_secondsHistogram每 token 延迟分布
延迟vllm:e2e_request_latency_secondsHistogram端到端请求延迟
吞吐vllm:num_requests_totalCounter总请求数
吞吐vllm:num_prompt_tokens_totalCounter总 prompt token 数
吞吐vllm:num_generation_tokens_totalCounter总生成 token 数
队列vllm:num_requests_waitingGauge等待队列长度
队列vllm:num_requests_runningGauge运行中请求数
内存vllm:gpu_cache_usage_percGaugeKV Cache 使用率
内存vllm:gpu_cache_sizeGaugeKV Cache 总容量

ServiceMonitor 配置(自动发现 vLLM 指标端点):

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: vllm-monitor
spec:
  selector:
    matchLabels:
      app: vllm-llama
  endpoints:
  - port: metrics
    interval: 10s
    path: /metrics

Grafana 面板

Production Stack 提供预配置的 Grafana Dashboard,包含以下面板:

  1. 请求延迟分布:TTFT / TPOT / E2E 的 p50/p95/p99 曲线
  2. 吞吐量监控:tokens/s、requests/s 的时间序列
  3. 队列状态:等待/运行中请求数
  4. KV Cache 状态:Cache 使用率、block 分配情况
  5. GPU 资源:GPU 利用率、显存使用、温度

告警规则示例

groups:
- name: vllm_alerts
  rules:
  - alert: HighTTFT
    expr: histogram_quantile(0.95, rate(vllm:ttft_seconds_bucket[5m])) > 2
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "TTFT 超过 2 秒 (p95)"

  - alert: HighQueueDepth
    expr: vllm:num_requests_waiting > 100
    for: 1m
    labels:
      severity: critical
    annotations:
      summary: "等待队列超过 100"

  - alert: GPUMemoryPressure
    expr: vllm:gpu_cache_usage_perc > 0.95
    for: 1m
    labels:
      severity: warning
    annotations:
      summary: "KV Cache 使用率超过 95%"

7.8.5 负载均衡

核心概念

路由策略

策略原理优势劣势适用场景
轮询顺序分发到各实例实现简单,负载理论上均衡不考虑实例状态差异无状态、缓存无关场景
最少连接分发到活跃连接最少的实例动态适应负载不均仅考虑连接数请求处理时间差异大的场景
一致性哈希对请求 key 哈希后映射到实例相同 key 路由到同一实例节点变化时部分请求重路由需要会话亲和性的场景
GPU 感知路由综合 KV Cache、队列、利用率决策最大化缓存命中率需要复杂调度逻辑生产级 LLM 部署

GPU 感知路由的调度决策流程

Gateway API Inference Extension 的 EPP(Endpoint Picker)实现了智能路由:

路由决策过滤器链:

1. 关键性检查 (Criticality Check)
   └── 关键请求 → 进入下一阶段
   └── 非关键请求 → 直接判断是否有容量

2. 低队列筛选 (Low Queuing Filter)
   └── 筛选 queue < 50 的实例

3. LoRA 亲和性检查 (LoRA Affinity Check)
   └── 筛选已加载所需 LoRA 的实例

4. 最少队列筛选 (Least Queuing Filter)
   └── 选择队列最短的实例

5. 最少 KV Cache 筛选 (Least KV Cache Filter)
   └── 选择 KV Cache 利用率最低的实例

最终选择:经过所有筛选后的最优实例

vLLM Production Stack 的路由配置

# Round-robin 路由
routerSpec:
  routingStrategy: "round-robin"

# 会话亲和性路由(一致性哈希)
routerSpec:
  routingStrategy: "session"

# Prefix-aware 路由(最大化 KV Cache 命中)
routerSpec:
  routingStrategy: "prefix-aware"

# KV-aware 路由(按 KV Cache 压力分配)
routerSpec:
  routingStrategy: "kv-aware"

7.8.6 灰度发布

核心概念

概念对比

策略原理切换速度回滚成本资源消耗适用场景
Rolling Update逐个替换旧版本 Pod慢(逐步)低极低(无额外资源)日常更新
Blue-Green同时运行新旧两套环境,一次性切换瞬时极低(切换回旧版)高(双倍资源)关键服务变更
Canary新版接收小比例流量,逐步增加到 100%渐进低低(少量额外 Pod)重大更新、模型升级

Rolling Update(滚动更新)

Kubernetes Deployment 原生支持:

apiVersion: apps/v1
kind: Deployment
spec:
  replicas: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1           # 最多额外启动 1 个新 Pod
      maxUnavailable: 0     # 滚动期间保证所有旧 Pod 可用
  template:
    spec:
      containers:
      - name: vllm
        image: vllm:v2.0.0  # 更新为新版本镜像

更新流程:

  1. 启动 1 个新版本 Pod(vllm:v2.0.0)
  2. 新 Pod ready 后,终止 1 个旧版本 Pod(vllm:v1.0.0)
  3. 重复直到所有 Pod 都更新为新版本
  4. 如果新版本异常(如 readiness probe 失败),自动暂停回滚

Blue-Green Deployment

# Blue (旧版本) — 仍然服务的实例
apiVersion: apps/v1
kind: Deployment
metadata:
  name: vllm-blue
spec:
  replicas: 5
  template:
    spec:
      containers:
      - name: vllm
        image: vllm:v1.0.0

---
# Green (新版本) — 部署但未接入流量
apiVersion: apps/v1
kind: Deployment
metadata:
  name: vllm-green
spec:
  replicas: 5
  template:
    spec:
      containers:
      - name: vllm
        image: vllm:v2.0.0

---
# Service selector 指向 blue
apiVersion: v1
kind: Service
metadata:
  name: vllm-service
spec:
  selector:
    version: blue

切换流程:

  1. 部署 Green 环境,进行集成测试和模型精度验证
  2. 验证通过后,更新 Service selector 指向 version: green
  3. 流量瞬时切换到新版
  4. 保留 Blue 环境一段时间用于回滚

Canary Release(金丝雀发布)

通过 Service Mesh(如 Istio)或网关配置流量权重:

# 使用 Istio VirtualService 实现金丝雀
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: vllm-canary
spec:
  hosts:
  - vllm.example.com
  http:
  - route:
    - destination:
        host: vllm-stable
        subset: v1
      weight: 90
    - destination:
        host: vllm-canary
        subset: v2
      weight: 10

渐进式流量迁移:

Phase 1: 旧版 100%    → 没有流量进入金丝雀
Phase 2: 旧版 90%     → 金丝雀承载 10% 流量(监控错误率和延迟)
Phase 3: 旧版 50%     → 金丝雀承载 50%(扩大验证范围)
Phase 4: 旧版 0%      → 全部流量到金丝雀(旧版下线)

模型升级的特殊考量:LLM 模型升级(如 LLaMA-3 8B → LLaMA-4 8B)的金丝雀发布需要:

  1. 对齐评估:在金丝雀上运行 MMLU、HumanEval 等基准测试,确保新模型的推理质量不降级
  2. 性能监控:对比金丝雀和稳定版的 TTFT/TPOT/吞吐量,确保新模型不会降低服务性能
  3. 输入兼容性:检查新模型的 tokenizer 是否与旧版本兼容(vocab 变化可能导致 corruption)
← 上一模块
高级 AI(上)
返回目录 →
封面与导航