5.3 能力扩展概览
多模态后训练(VLM/LLaVA)、工具使用与智能体(函数调用/MCP)、知识编辑(参数编辑/RAG)三大能力扩展方向
后训练不仅可以提升模型的对话和推理能力,还可以为模型注入全新的能力维度。本节概览三大能力扩展方向:多模态理解、工具使用与智能体、知识编辑。
多模态后训练
VLM 架构:视觉 + 语言的融合
视觉语言模型(Vision-Language Model, VLM)的核心挑战是如何将视觉信息"翻译"为语言模型能理解的 token 序列。当前主流架构由三个模块组成:
图像 → [视觉编码器 (ViT)] → 视觉 token 序列
↓
[投影模块 (MLP/Cross-Attention)]
↓
文本 → [Tokenizer] → 文本 token ──→ [LLM 骨干] → 回复| 模块 | 作用 | 典型实现 | 参数量 |
|---|---|---|---|
| 视觉编码器 | 提取图像特征 | ViT-L/14 (CLIP), SigLIP | 300M-600M |
| 投影模块 | 对齐视觉和语言表征空间 | 2-层 MLP 或 Cross-Attention | 10M-100M |
| LLM 骨干 | 理解多模态输入并生成文本 | Qwen3, Llama, Vicuna | 1.5B-70B |
关键设计决策:视觉 token 的数量直接影响推理成本。一张 224x224 的图像经 ViT-L/14 处理后产生 256 个 token;高分辨率图像(如 Qwen3-VL 支持的动态分辨率)可能产生 1000+ 个 token。
LLaVA 两阶段训练范式
LLaVA(Liu et al., NeurIPS 2023)确立了 VLM 后训练的经典两阶段流程:
Stage 1 — 视觉-语言对齐预训练
目标:让投影模块学会将视觉特征映射到 LLM 能理解的空间。
- 训练数据:大量图像-文本对(如 LAION、CC3M),约 600K 条
- 训练策略:冻结视觉编码器和 LLM,仅训练投影模块
- 训练目标:标准的 next-token prediction,但输入包含视觉 token
- 计算量:较小(仅训练投影层),约 4-8 小时(8 x A100)
# Stage 1 伪代码
for image, caption in alignment_data:
visual_tokens = vision_encoder(image) # 冻结
projected = projection_module(visual_tokens) # 可训练
text_tokens = tokenizer(caption)
input_embeds = concat(projected, text_tokens)
loss = llm(input_embeds, labels=text_tokens) # LLM 冻结
loss.backward() # 仅更新 projection_moduleStage 2 — 视觉指令微调
目标:让整个 VLM 学会理解视觉相关的指令并生成高质量回复。
- 训练数据:视觉指令数据(如 LLaVA-Instruct-150K),包含图片 + 问题 + 回答
- 训练策略:冻结视觉编码器,同时训练投影模块和 LLM(可用 LoRA)
- 数据类型:
- 图像描述(describe this image)
- 视觉问答(what color is the car?)
- 视觉推理(which object is closer?)
- OCR 和文档理解
# Stage 2 伪代码 - 使用 LoRA 微调 LLM
for image, instruction, response in instruct_data:
visual_tokens = vision_encoder(image) # 冻结
projected = projection_module(visual_tokens) # 可训练
text_tokens = tokenizer(instruction)
input_embeds = concat(projected, text_tokens)
loss = llm_with_lora(input_embeds, labels=response_tokens) # LoRA 可训练
loss.backward()代表模型
| 模型 | 发布方 | 视觉编码器 | LLM 骨干 | 特色 |
|---|---|---|---|---|
| Qwen3-VL | 阿里通义 | 自研 ViT | Qwen3 | 动态分辨率、视频理解、原生工具调用 |
| LLaVA-OneVision | UW-Madison | SigLIP | Qwen2.5 | 统一图像/视频/多图理解 |
| InternVL3 | 上海 AI Lab | InternViT | InternLM3 | 开源最强多模态模型之一 |
| GPT-4o | OpenAI | 未公开 | GPT-4 | 商业闭源标杆 |
| Claude 3.5 Sonnet | Anthropic | 未公开 | Claude | 强大的视觉理解和推理 |
DPO 减少视觉幻觉
VLM 面临的一个严重问题是视觉幻觉(Visual Hallucination)——模型"看到"图像中不存在的内容。例如,当被问及"图中有几个人?"时,模型可能编造不存在的人物。
用 DPO 缓解幻觉的思路:
- 收集图片 + 问题
- 让 VLM 生成多个回答
- 用人工或自动工具标注哪些回答有幻觉(rejected)、哪些忠实于图像(chosen)
- 在这些偏好对上做 DPO 训练
其中 表示输入图像。
LLaVA-RLHF 是首个将 RLHF 应用于 VLM 的工作,通过人类偏好数据训练奖励模型,有效降低了幻觉率。后续的 RLHF-V 和 RLAIF-V 进一步使用 AI 反馈替代人类反馈,降低标注成本。
多模态后训练代码示例
# 使用 Qwen3-VL 进行视觉问答的推理示例
from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor
model = Qwen2_5_VLForConditionalGeneration.from_pretrained(
"Qwen/Qwen3-VL-2B-Instruct",
torch_dtype=torch.bfloat16,
device_map="auto",
)
processor = AutoProcessor.from_pretrained("Qwen/Qwen3-VL-2B-Instruct")
messages = [
{
"role": "user",
"content": [
{"type": "image", "image": "https://example.com/photo.jpg"},
{"type": "text", "text": "请详细描述这张图片的内容。"},
],
}
]
text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
inputs = processor(text=text, images=[image], return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_new_tokens=256)
response = processor.decode(outputs[0], skip_special_tokens=True)工具使用与智能体
函数调用范式
让 LLM 使用外部工具是扩展其能力的关键途径。函数调用(Function Calling)的标准流程:
工具定义:以 JSON Schema 格式描述可用工具的名称、参数和功能
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的当前天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,如 '北京'"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位"
}
},
"required": ["city"]
}
}
}模型决策:模型根据用户输入决定是否调用工具、调用哪个工具、传入什么参数
{
"function_call": {
"name": "get_weather",
"arguments": "{\"city\": \"北京\", \"unit\": \"celsius\"}"
}
}执行与返回:系统执行函数调用,将结果返回给模型
{
"role": "tool",
"content": "{\"temperature\": 25, \"condition\": \"晴朗\", \"humidity\": 40}"
}最终回复:模型基于工具返回的结果生成自然语言回复
"北京当前天气晴朗,气温 25 摄氏度,湿度 40%。适合户外活动!"
训练方法:在工具调用对话数据上进行 SFT
工具调用能力的训练本质上是特殊格式的 SFT——让模型学会在合适的时机输出结构化的函数调用:
# 工具调用训练数据格式示例
training_sample = {
"messages": [
{
"role": "system",
"content": "你是一个有用的助手。你可以使用以下工具:\n"
"[get_weather, search_web, calculate]"
},
{
"role": "user",
"content": "明天北京会下雨吗?"
},
{
"role": "assistant",
"content": None,
"tool_calls": [{
"type": "function",
"function": {
"name": "get_weather",
"arguments": '{"city": "北京", "forecast": true}'
}
}]
},
{
"role": "tool",
"name": "get_weather",
"content": '{"forecast": "明天多云转晴,降水概率 10%"}'
},
{
"role": "assistant",
"content": "根据天气预报,明天北京多云转晴,降水概率仅 10%,不太可能下雨。"
}
]
}Qwen3 原生工具调用与 MCP 支持
Qwen3 在后训练中加入了大量工具调用数据,原生支持函数调用和 MCP(Model Context Protocol):
- BFCL 排行榜(Berkeley Function-Calling Leaderboard):Qwen3 在开源模型中排名领先
- MCP 协议:统一的工具接口标准,支持动态工具发现和调用
- 多工具协调:支持在一次推理中调用多个工具、处理工具间的依赖关系
# Qwen3 函数调用示例
from transformers import AutoModelForCausalLM, AutoTokenizer
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-1.7B", device_map="auto")
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-1.7B")
tools = [
{
"type": "function",
"function": {
"name": "search_knowledge_base",
"description": "搜索内部知识库获取相关信息",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "搜索关键词"},
"top_k": {"type": "integer", "description": "返回结果数量"}
},
"required": ["query"]
}
}
}
]
messages = [
{"role": "system", "content": "You are a helpful assistant with access to tools."},
{"role": "user", "content": "帮我查一下 LoRA 微调的最佳学习率是多少?"}
]
# 使用 apply_chat_template 自动格式化工具定义
text = tokenizer.apply_chat_template(
messages, tools=tools, tokenize=False, add_generation_prompt=True
)
inputs = tokenizer(text, return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_new_tokens=256)
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(response)ToolACE:8B 模型超越 GPT-4
ToolACE(Liu et al., ICLR 2025)展示了一个令人瞩目的结果:通过高质量的工具调用训练数据,一个 8B 参数的模型在函数调用准确率上超越了 GPT-4。
ToolACE 的核心方法:
- 自动化数据生成管道:用 LLM 生成多样化的工具定义和调用场景
- 多层验证:对生成的工具调用数据进行语法检查、参数类型验证、逻辑一致性检查
- 难度递进:从单工具简单调用到多工具链式调用,逐步增加训练难度
- 错误修正数据:故意引入错误的工具调用,训练模型识别和修正
| 模型 | BFCL 准确率 | 参数量 | 训练数据量 |
|---|---|---|---|
| GPT-4-turbo | 83.2% | ~1.8T (推测) | 未公开 |
| ToolACE-8B | 84.7% | 8B | ~26K |
| Gorilla-7B | 79.8% | 7B | ~16K |
| Qwen3-1.7B | ~75% | 1.7B | 未公开 |
约束解码:保证输出合法 JSON
工具调用要求模型输出严格合法的 JSON 格式。约束解码(Constrained Decoding)在推理时强制模型的输出满足预定义的语法规则:
其中 是在当前上下文下语法允许的下一个 token 集合。
主流实现:
- Outlines:基于有限状态机(FSM)的约束解码库
- vLLM guided decoding:vLLM 内置的 JSON Schema 约束解码
- SGLang:支持正则表达式约束的高性能推理框架
# 使用 Outlines 进行约束解码
import outlines
model = outlines.models.transformers("Qwen/Qwen3-1.7B")
# 定义 JSON Schema
schema = {
"type": "object",
"properties": {
"name": {"type": "string"},
"arguments": {"type": "object"}
},
"required": ["name", "arguments"]
}
generator = outlines.generate.json(model, schema)
result = generator("Call the weather tool for Beijing")
# 保证输出一定是合法的 JSON智能体循环(Agent Loop)
工具调用的高级形态是智能体循环——模型可以多步使用工具来完成复杂任务:
用户请求 → 模型思考 → 调用工具 A → 获得结果 A
→ 模型思考 → 调用工具 B(结果 A) → 获得结果 B
→ 模型思考 → 生成最终回复这种多步推理 + 多步工具调用的模式,正是当前 AI Agent 研究的核心范式。
知识编辑
当 LLM 中包含过时或错误的知识时,如何高效地更新?主要有两种路径:
参数编辑方法
直接修改模型权重来更新特定事实知识,无需重新训练整个模型。
代表方法:
| 方法 | 核心思想 | 优点 | 缺点 |
|---|---|---|---|
| ROME (Rank-One Model Editing) | 定位存储特定事实的 MLP 层,用秩1更新修改权重 | 精确、高效 | 仅适合单个事实修改 |
| MEMIT (Mass Editing Memory) | ROME 的批量版本,同时编辑多个事实 | 支持批量编辑 | 编辑数量受限 |
| MEND | 使用超网络学习编辑方向 | 灵活 | 需要额外训练超网络 |
ROME 的核心思想:
Transformer 的 MLP 层可以视为 键-值存储器(key-value memory):
其中 是"键"(知识的索引), 是"值"(知识的内容)。
要修改一个事实(如"埃菲尔铁塔位于巴黎" → "埃菲尔铁塔位于伦敦"),只需对 做一个秩1更新:
其中 是目标事实对应的键向量, 是期望的新值向量。
参数编辑的局限性:
- 连锁效应——修改一个事实可能意外影响相关知识(如修改"法国首都"可能影响"法语国家"相关知识)
- 规模限制——大量编辑会导致模型性能整体下降
- 难以验证——难以确保编辑不会引入其他错误
RAG(检索增强生成)
RAG(Retrieval-Augmented Generation)不修改模型参数,而是在推理时从外部知识库检索相关信息,附加到模型的输入中:
知识库构建:将文档切分为 chunk,使用嵌入模型(如 bge-large)编码为向量,存入向量数据库(如 FAISS、Milvus)
检索:对用户查询进行编码,在向量数据库中搜索最相似的 top-k 个 chunk
增强生成:将检索到的 chunk 作为上下文附加到 prompt 中,让 LLM 基于检索内容生成回复
# RAG 基本流程示例
from langchain.vectorstores import FAISS
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 1. 构建知识库
documents = load_documents("knowledge_base/")
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = text_splitter.split_documents(documents)
embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-large-zh-v1.5")
vectorstore = FAISS.from_documents(chunks, embeddings)
# 2. 检索相关内容
query = "Qwen3 的后训练流程是什么?"
relevant_docs = vectorstore.similarity_search(query, k=3)
# 3. 增强生成
context = "\n".join([doc.page_content for doc in relevant_docs])
prompt = f"""基于以下参考信息回答问题:
参考信息:
{context}
问题:{query}
回答:"""
# 送入 LLM 生成回复
response = llm.generate(prompt)使用场景对比
| 维度 | 参数编辑 | RAG | 重新微调 |
|---|---|---|---|
| 修改范围 | 少量特定事实 | 大规模知识库 | 全面知识更新 |
| 模型参数 | 直接修改 | 不修改 | 重新训练 |
| 响应延迟 | 无额外延迟 | 增加检索延迟 | 无额外延迟 |
| 知识更新成本 | 极低 | 低(更新向量库) | 高(重新训练) |
| 准确性控制 | 中等(可能有连锁影响) | 高(可追溯来源) | 高(但需大量数据) |
| 幻觉风险 | 可能引入新幻觉 | 可通过引用降低 | 取决于数据质量 |
| 适合场景 | 纠正个别错误事实 | 企业知识库、FAQ | 大规模领域适配 |
实践建议:在大多数实际应用中,RAG 是首选方案——它不修改模型参数,可追溯信息来源,且知识更新成本极低。参数编辑更适合学术研究场景。如果需要大规模的领域知识注入,则应考虑在领域数据上进行 SFT/continued pre-training。
知识编辑与后训练的关系
从广义上看,知识编辑也是后训练的一种形式:
- 参数编辑 → 最小粒度的参数更新(修改几个权重)
- LoRA 微调 → 中等粒度的参数更新(训练低秩适配器)
- 全参数微调 → 最大粒度的参数更新(更新所有权重)
- RAG → 不更新参数,而是在推理时动态注入知识("即时后训练")
它们形成了一个从"精确但有限"到"全面但昂贵"的知识更新谱系。
三大能力扩展对比总表
| 能力扩展 | 核心技术 | 训练方法 | 代表模型/工作 | 后训练中的角色 |
|---|---|---|---|---|
| 多模态理解 | ViT + 投影 + LLM | 两阶段 SFT + DPO | Qwen3-VL, LLaVA, InternVL3 | 从"读文字"扩展到"看图片" |
| 工具使用 | JSON Schema 函数调用 | 工具调用 SFT | Qwen3, ToolACE, Gorilla | 从"知道"扩展到"能做" |
| 知识编辑 | 参数编辑 / RAG | ROME / 向量检索 | ROME, MEMIT, RAG 系统 | 从"固定知识"扩展到"可更新" |
本节小结
- 多模态后训练通过 VLM 架构和两阶段训练(对齐 + 指令微调)让 LLM 具备视觉理解能力,DPO 可有效减少视觉幻觉
- 工具使用通过函数调用范式扩展 LLM 的行动能力,Qwen3 原生支持 MCP 和函数调用,ToolACE 证明了小模型也能超越 GPT-4
- 知识编辑提供了更新模型知识的两种路径:参数编辑(精确但有限)和 RAG(灵活且可追溯)
- 这三大扩展方向都可以与核心后训练技术(SFT、DPO、GRPO)结合使用,构成完整的 LLM 能力体系