LLM 后训练实践
第5课:压缩部署与扩展

5.3 能力扩展概览

多模态后训练(VLM/LLaVA)、工具使用与智能体(函数调用/MCP)、知识编辑(参数编辑/RAG)三大能力扩展方向

后训练不仅可以提升模型的对话和推理能力,还可以为模型注入全新的能力维度。本节概览三大能力扩展方向:多模态理解、工具使用与智能体、知识编辑。

多模态后训练

VLM 架构:视觉 + 语言的融合

视觉语言模型(Vision-Language Model, VLM)的核心挑战是如何将视觉信息"翻译"为语言模型能理解的 token 序列。当前主流架构由三个模块组成:

图像 → [视觉编码器 (ViT)] → 视觉 token 序列

                            [投影模块 (MLP/Cross-Attention)]

文本 → [Tokenizer] → 文本 token ──→ [LLM 骨干] → 回复
模块作用典型实现参数量
视觉编码器提取图像特征ViT-L/14 (CLIP), SigLIP300M-600M
投影模块对齐视觉和语言表征空间2-层 MLP 或 Cross-Attention10M-100M
LLM 骨干理解多模态输入并生成文本Qwen3, Llama, Vicuna1.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_module

Stage 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阿里通义自研 ViTQwen3动态分辨率、视频理解、原生工具调用
LLaVA-OneVisionUW-MadisonSigLIPQwen2.5统一图像/视频/多图理解
InternVL3上海 AI LabInternViTInternLM3开源最强多模态模型之一
GPT-4oOpenAI未公开GPT-4商业闭源标杆
Claude 3.5 SonnetAnthropic未公开Claude强大的视觉理解和推理

DPO 减少视觉幻觉

VLM 面临的一个严重问题是视觉幻觉(Visual Hallucination)——模型"看到"图像中不存在的内容。例如,当被问及"图中有几个人?"时,模型可能编造不存在的人物。

用 DPO 缓解幻觉的思路:

  1. 收集图片 + 问题
  2. 让 VLM 生成多个回答
  3. 用人工或自动工具标注哪些回答有幻觉(rejected)、哪些忠实于图像(chosen)
  4. 在这些偏好对上做 DPO 训练
LVLM-DPO=E[logσ(βlogπθ(yfaithfulx,I)πref(yfaithfulx,I)βlogπθ(yhallucx,I)πref(yhallucx,I))]\mathcal{L}_{\text{VLM-DPO}} = -\mathbb{E}\left[\log\sigma\left(\beta\log\frac{\pi_\theta(y_{\text{faithful}}|x, I)}{\pi_{\text{ref}}(y_{\text{faithful}}|x, I)} - \beta\log\frac{\pi_\theta(y_{\text{halluc}}|x, I)}{\pi_{\text{ref}}(y_{\text{halluc}}|x, I)}\right)\right]

其中 II 表示输入图像。

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 的核心方法

  1. 自动化数据生成管道:用 LLM 生成多样化的工具定义和调用场景
  2. 多层验证:对生成的工具调用数据进行语法检查、参数类型验证、逻辑一致性检查
  3. 难度递进:从单工具简单调用到多工具链式调用,逐步增加训练难度
  4. 错误修正数据:故意引入错误的工具调用,训练模型识别和修正
模型BFCL 准确率参数量训练数据量
GPT-4-turbo83.2%~1.8T (推测)未公开
ToolACE-8B84.7%8B~26K
Gorilla-7B79.8%7B~16K
Qwen3-1.7B~75%1.7B未公开

约束解码:保证输出合法 JSON

工具调用要求模型输出严格合法的 JSON 格式。约束解码(Constrained Decoding)在推理时强制模型的输出满足预定义的语法规则:

P(tit<i)={Pmodel(tit<i)if tiValid(t<i)0otherwiseP(t_i | t_{<i}) = \begin{cases} P_{\text{model}}(t_i | t_{<i}) & \text{if } t_i \in \text{Valid}(t_{<i}) \\ 0 & \text{otherwise} \end{cases}

其中 Valid(t<i)\text{Valid}(t_{<i}) 是在当前上下文下语法允许的下一个 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):

MLP(x)=Wprojσ(Wfcx)=Vσ(KTx)\text{MLP}(x) = W_{\text{proj}} \cdot \sigma(W_{\text{fc}} \cdot x) = V \cdot \sigma(K^T \cdot x)

其中 K=WfcTK = W_{\text{fc}}^T 是"键"(知识的索引),V=WprojV = W_{\text{proj}} 是"值"(知识的内容)。

要修改一个事实(如"埃菲尔铁塔位于巴黎" → "埃菲尔铁塔位于伦敦"),只需对 VV 做一个秩1更新:

V=V+(vVk)kTkTkV' = V + \frac{(v^* - V k^*) k^{*T}}{k^{*T} k^*}

其中 kk^* 是目标事实对应的键向量,vv^* 是期望的新值向量。

参数编辑的局限性

  1. 连锁效应——修改一个事实可能意外影响相关知识(如修改"法国首都"可能影响"法语国家"相关知识)
  2. 规模限制——大量编辑会导致模型性能整体下降
  3. 难以验证——难以确保编辑不会引入其他错误

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 + DPOQwen3-VL, LLaVA, InternVL3从"读文字"扩展到"看图片"
工具使用JSON Schema 函数调用工具调用 SFTQwen3, ToolACE, Gorilla从"知道"扩展到"能做"
知识编辑参数编辑 / RAGROME / 向量检索ROME, MEMIT, RAG 系统从"固定知识"扩展到"可更新"

本节小结

  1. 多模态后训练通过 VLM 架构和两阶段训练(对齐 + 指令微调)让 LLM 具备视觉理解能力,DPO 可有效减少视觉幻觉
  2. 工具使用通过函数调用范式扩展 LLM 的行动能力,Qwen3 原生支持 MCP 和函数调用,ToolACE 证明了小模型也能超越 GPT-4
  3. 知识编辑提供了更新模型知识的两种路径:参数编辑(精确但有限)和 RAG(灵活且可追溯)
  4. 这三大扩展方向都可以与核心后训练技术(SFT、DPO、GRPO)结合使用,构成完整的 LLM 能力体系