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
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 通过 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"]
}
}
}]
}'
底层机制:
tool_calls 结构化输出支持的模型:需要经过指令微调且支持 function calling 的模型(如 Llama-3.1-Instruct、Qwen-2.5-Instruct、DeepSeek-V2-Chat 等)。
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
CoT 是让模型在给出最终答案前显式展示推理过程的提示技术:
Q: 小明有 10 个苹果,给了小红 3 个,又从超市买了 5 个。他总共有多少个?
A:
一开始有 10 个苹果。
给了小红 3 个,剩下 10 - 3 = 7 个。
买了 5 个,现在有 7 + 5 = 12 个。
所以小明总共有 12 个苹果。
CoT vs ReAct:CoT 只有"思考"没有"行动";ReAct 在思考之外还会调用工具获取新信息,适合需要与外部环境交互的场景。
ToT 扩展了 CoT 的线性推理,维护一个"推理树"并同时探索多个分支:
思考分支 1: ... ❌ (推理错误)
↓
初始问题 → → 思考分支 2: ... → 思考 2a: ... ✓ (找到答案)
↓
思考分支 3: ... → 思考 3a: ... → 思考 3b: ... (仍在进行中)
ToT 在每个推理步骤生成多个候选思路,使用评估函数(如 LLM 自身或启发式方法)评估每个分支的可行性,并剪枝掉低质量分支。计算成本是 CoT 的 N 倍(N = 分支数 × 深度),但适合需要多步探索的复杂问题。
| 策略 | 推理结构 | 工具交互 | 计算成本 | 错误恢复 | 适用场景 |
|---|---|---|---|---|---|
| CoT | 线性链 | 无 | 低 | 无 | 数学、逻辑、常识推理 |
| ReAct | 推理-行动交替循环 | 是 | 中 | 通过新 Tool 输出纠正 | 信息获取、问答、搜索 |
| ToT | 树形搜索 | 可选 | 高 | 探索多个分支 | 复杂问题求解、设计 |
受认知科学启发,Agent 的记忆系统通常分为三级:
短期记忆 (Working Memory)
├── 当前对话上下文(Context Window 内)
├── 当前任务的中间状态和变量
└── 生命周期: 当前回合结束即清除
工作记忆 (Episodic Buffer)
├── 当前对话轮次的关键信息
├── 最近完成的操作和结果
└── 生命周期: 会话存活期
长期记忆 (Long-term Memory)
├── 用户偏好和历史行为模式
├── 领域知识和经验积累
└── 生命周期: 跨会话持久化
短期记忆:直接利用 LLM 的 context window,将历史对话和中间状态拼接到当前的 prompt 中。
长期记忆:
# 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]
Multi-agent 系统由多个 Agent 协作完成复杂任务。每个 Agent 负责一个专门的子任务或领域,通过消息传递和任务协调实现 1+1>2 的效果。
| 框架 | 核心思想 | 通信机制 | 编排方式 | 适用场景 |
|---|---|---|---|---|
| AutoGen | 多 Agent 对话式协作 | 自然语言消息 | 可编程对话图 | 研究、原型开发 |
| CrewAI | 角色扮演式协作 | 任务分配 + 工具共享 | YAML 配置 | 自动化工作流 |
| LangGraph | 有状态图计算 | 边传递状态 | 状态机 | 生产级复杂流程 |
# 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 脚本"
)
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
核心组件:
| 特性 | MCP | OpenAI Function Calling | 传统 API 集成 |
|---|---|---|---|
| 标准化 | 开放标准,厂商中立 | OpenAI 专有 | 无标准 |
| 工具发现 | 自动(server 声明) | 手动(应用定义) | 手动 |
| 安全性 | 隔离的 server 进程 | 应用内执行 | 无隔离 |
| 多工具组合 | 天然支持 | 需手动编排 | 需手动编排 |
| 资源暴露 | 结构化资源暴露 | 仅支持工具调用 | 无 |
视觉-语言模型(Vision-Language Model, VLM)是一种能够同时处理图像和文本输入的多模态模型。典型架构为:图像编码器提取视觉特征 → 连接器对齐模态 → 语言模型生成输出。
标准 VLM 架构:
Image → Vision Encoder (ViT/CLIP) → Vision Tokens
│
▼
Connector/Projector
│
▼
Text Embeddings + Vision Embeddings
│
▼
Language Model (LLM)
│
▼
Generated Text
| 模型 | 视觉编码器 | 连接器 | 语言模型 | 特色 |
|---|---|---|---|---|
| LLaVA | CLIP ViT-L/14 | 简单线性投影 | LLaMA/Vicuna | 简洁高效,开创性工作 |
| LLaVA-NeXT | CLIP ViT-L/14 | 多层 MLP | LLaMA-3/Phi-3 | 支持高分辨率输入 |
| Qwen2-VL | SigLIP ViT | QwenVLBlock (Cross-Attention) | Qwen2 | 动态分辨率,视频理解 |
| InternVL 2 | InternViT | MLP + Perceiver | InternLM2 | 超大视觉编码器(6B) |
| CLIP | ViT 或 ResNet | 对比学习 Head | 无(仅对齐训练) | 对比预训练,非生成式 |
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:
| 特性 | ViT | CNN (ResNet) |
|---|---|---|
| 感受野 | 全局(self-attention) | 局部(卷积核) |
| 归纳偏置 | 少(需要更多数据) | 多(平移不变性) |
| 参数效率 | 高(共享较少) | 中 |
| 大模型扩展 | 好 | 有平台期 |
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(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 可以更小,训练效率更高。
最简单的连接器。将视觉编码器的输出映射到语言模型的输入嵌入空间:
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(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 的优势:
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"),
}
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, ...)
# 通过 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": "请描述这张图片"}
]
}
]
}'
| 功能 | 纯文本模型 | 多模态模型 |
|---|---|---|
| PagedAttention | 完整支持 | 支持(视觉 token 也被 block 管理) |
| Continuous Batching | 完整支持 | 支持 |
| Chunked Prefill | 支持 | 部分支持(视觉 token 处理限制) |
| Prefix Caching | 完整支持 | 不支持(视觉输入导致不同的 block hash) |
| Speculative Decoding | 支持 | 不支持 |
| LoRA | 支持 | 部分模型支持 |
LLaVA(Large Language and Vision Assistant)系列是最广泛使用的开源 VLM 之一。
LLaVA-NeXT 的关键改进:
InternVL 2 是目前性能最强的开源 VLM 之一,视觉编码器达到 6B 参数:
在 MMMU、MathVista 等基准上超过 GPT-4V。
Qwen2-VL 是阿里通义千问的多模态版本:
剪枝(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 是掩码矩阵。
特点:
按通道、行或注意力头移除权重:
W_{\text{structured}} = W[I_{\text{keep}}, :]其中 I_{\text{keep}} 是根据重要性评分(如权重的 L1/L2 范数、梯度幅度、激活值统计)选出的保留通道索引。
常见结构化剪枝粒度:
| 剪枝粒度 | 单位 | 移除方式 | 加速效果 | 精度影响 |
|---|---|---|---|---|
| 注意力头 | Head | 移除完整的注意力头 | 中等 | 通常可控 |
| 隐藏维度 | Feature | 移除完整的隐藏维度 | 高 | 较大 |
| FFN 中间维度 | Neuron | 移除 MLP 中间层的神经元 | 高 | 较大 |
| 层 | Layer | 移除完整 Transformer 层 | 极高 | 很大 |
特点:
直接剪枝后模型精度会下降,需要通过微调恢复:
# 剪枝 + 微调的三步流程
# 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()
知识蒸馏(Knowledge Distillation)是使用一个更大的"教师模型"(Teacher Model)来指导一个小型"学生模型"(Student Model)的训练。学生模型通过学习教师模型的输出分布,获得比单独训练更好的性能。
学生模型不仅学习真实标签,还学习教师模型的 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),如教师模型认为哪些错误类别与正确类别更相似。
不仅匹配输出分布,还匹配中间层的特征表示:
\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 是适配维度差异的线性投影。
| 维度 | 蒸馏 | 剪枝 | 量化 |
|---|---|---|---|
| 原理 | 学习教师输出分布 | 移除不重要权重 | 降低数值精度 |
| 压缩方式 | 可使用更小的学生架构 | 移除权重通道/元素 | 使用更少 bit 表示 |
| 是否需重新训练 | 是 | 需微调恢复 | 不一定(PTQ 无需) |
| 常见压缩比 | 2-10x | 2-4x | 2-4x |
| 精度损失 | 通常最小(教师指导) | 中高(高稀疏度时) | 低(FP8/INT8) |
| 与硬件关系 | 无关 | 需稀疏硬件/N:M | 需 Tensor Core 支持 |
量化感知训练(Quantization-Aware Training, QAT)是在训练过程中模拟低精度推理的计算误差,让模型参数适应量化噪声。与训练后量化(PTQ)不同,QAT 将量化视为训练的一部分,通常可以获得更好的精度-效率权衡。
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}}}| 维度 | PTQ(训练后量化) | QAT(量化感知训练) |
|---|---|---|
| 是否需要训练 | 否 | 是 |
| 所需数据 | 少量校准数据(~1K samples) | 训练数据(~10K+ samples) |
| 计算成本 | 极低(几分钟) | 中等(额外训练 10-20% 时间) |
| 精度保留 | 通常较好(INT8 损失 <1%) | 更好(接近 FP16 精度) |
| 适用极端量化 | 差(INT4 损失大) | 好(INT4 可接近 FP16) |
| 灵活性 | 固定量化方案 | 可优化 scale/zero_point |
| 精度 | 位数 | 内存节省(vs FP16) | 推理加速(典型) | 精度影响 |
|---|---|---|---|---|
| FP16 | 16 | 基线 | 基线 | 基线 |
| FP8 (E4M3) | 8 | ~50% | ~1.5-2x | <1% 损失 |
| INT8 | 8 | ~50% | ~1.5-2x | <1% 损失 |
| INT4 (AWQ/GPTQ) | 4 | ~75% | ~2-3x | 1-3% 损失 |
| INT4 + FP16 混合 | 4-16 | 灵活 | ~2x | 可控 |
| NF4 (QLoRA) | 4 | ~75% | ~1.5x | 微调后接近基线 |
| 压缩方法 | 压缩比 | 精度损失 | 训练成本 | 推理加速 | 硬件约束 | 适用场景 |
|---|---|---|---|---|---|---|
| 非结构化剪枝 | 5-10x (90%) | 2-5% | 高(需微调) | 弱(通用 GPU) | 稀疏硬件/NVIDIA N:M | 模型存储压缩 |
| 结构化剪枝 | 2-4x | 1-3% | 高(需微调) | 好 | 无 | 延迟敏感场景 |
| Logit 蒸馏 | 2-10x | 0-2% | 高(完整训练) | 好(学生小模型) | 无 | 部署小模型 |
| PTQ (INT8) | 2x | <1% | 极低 | 1.5-2x | INT8 Tensor Core | 快速部署 |
| PTQ (INT4) | 4x | 1-3% | 低 | 2-3x | 部分 GPU | 大模型部署 |
| QAT (INT4) | 4x | <1% | 中 | 2-3x | 部分 GPU | 生产级部署 |
| AWQ/GPTQ | 4x | 1-2% | 低(微调 scale) | 2-3x | 部分 GPU | 流行方案 |
| 混合方法 | 8-16x | 2-5% | 极高 | 3-5x | 多种约束叠加 | 端侧部署 |
混合压缩(如剪枝 + 量化 + 蒸馏)可以叠加压缩收益,但精度损失也会叠加。典型的端侧部署方案是:先在超大模型上进行蒸馏得到中型教师,然后进行结构化剪枝和 INT4 量化,最终得到能在手机上运行的模型。
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-utilization | 0.90 | 内存 | GPU 显存用于模型的百分比(含权重 + KV Cache) |
max-model-len | (模型默认) | 内存 | 最大序列长度,超出此长度的请求被拒绝 |
max-num-seqs | 256 | 调度 | batch 中的最大请求数 |
max-num-batched-tokens | 2048 | 调度 | Chunked Prefill 的单批最大 token 数 |
block-size | 16 | 内存 | PagedAttention 的 block token 数 |
enable-chunked-prefill | False | 调度 | 是否启用 Chunked Prefill 混合调度 |
enable-prefix-caching | False | 缓存 | 是否启用基于 block hash 的 Prefix Cache |
tensor-parallel-size | 1 | 分布式 | 张量并行 GPU 数量 |
pipeline-parallel-size | 1 | 分布式 | 流水线并行 GPU 数量 |
kv-cache-dtype | auto | 内存 | KV Cache 精度(auto/FP8/FP8_E4M3) |
quantization | None | 精度 | 模型权重量化方法(awq/gptq/fp8) |
max-loras | 0 | LoRA | 同时加载的 LoRA 适配器数量 |
enable-lora | False | LoRA | 是否启用 LoRA 支持 |
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 |
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
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
扩缩容决策逻辑:
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 利用率直接扩缩。实际做法是:
vLLM 暴露 Prometheus 格式的内置指标:
| 指标类别 | 指标名 | 类型 | 说明 |
|---|---|---|---|
| 延迟 | vllm:ttft_seconds | Histogram | 首 token 延迟分布 |
| 延迟 | vllm:tpot_seconds | Histogram | 每 token 延迟分布 |
| 延迟 | vllm:e2e_request_latency_seconds | Histogram | 端到端请求延迟 |
| 吞吐 | vllm:num_requests_total | Counter | 总请求数 |
| 吞吐 | vllm:num_prompt_tokens_total | Counter | 总 prompt token 数 |
| 吞吐 | vllm:num_generation_tokens_total | Counter | 总生成 token 数 |
| 队列 | vllm:num_requests_waiting | Gauge | 等待队列长度 |
| 队列 | vllm:num_requests_running | Gauge | 运行中请求数 |
| 内存 | vllm:gpu_cache_usage_perc | Gauge | KV Cache 使用率 |
| 内存 | vllm:gpu_cache_size | Gauge | KV 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
Production Stack 提供预配置的 Grafana Dashboard,包含以下面板:
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%"
| 策略 | 原理 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|---|
| 轮询 | 顺序分发到各实例 | 实现简单,负载理论上均衡 | 不考虑实例状态差异 | 无状态、缓存无关场景 |
| 最少连接 | 分发到活跃连接最少的实例 | 动态适应负载不均 | 仅考虑连接数 | 请求处理时间差异大的场景 |
| 一致性哈希 | 对请求 key 哈希后映射到实例 | 相同 key 路由到同一实例 | 节点变化时部分请求重路由 | 需要会话亲和性的场景 |
| GPU 感知路由 | 综合 KV Cache、队列、利用率决策 | 最大化缓存命中率 | 需要复杂调度逻辑 | 生产级 LLM 部署 |
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 利用率最低的实例
最终选择:经过所有筛选后的最优实例
# 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"
| 策略 | 原理 | 切换速度 | 回滚成本 | 资源消耗 | 适用场景 |
|---|---|---|---|---|---|
| Rolling Update | 逐个替换旧版本 Pod | 慢(逐步) | 低 | 极低(无额外资源) | 日常更新 |
| Blue-Green | 同时运行新旧两套环境,一次性切换 | 瞬时 | 极低(切换回旧版) | 高(双倍资源) | 关键服务变更 |
| Canary | 新版接收小比例流量,逐步增加到 100% | 渐进 | 低 | 低(少量额外 Pod) | 重大更新、模型升级 |
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 # 更新为新版本镜像
更新流程:
vllm:v2.0.0)vllm:v1.0.0)# 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
切换流程:
version: green通过 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)的金丝雀发布需要: