模型工程(微调与部署)¶
一句话:模型工程把"通用大模型"调教成"业务专用模型"并低成本部署——核心是 LoRA/SFT 微调、私有化部署(vLLM/Ollama/TGI)、Prompt 工程与 Token 成本优化;彭超案例做到幻觉率 -30%、Token 成本 -45%、响应延迟 < 800ms(P95)。
概念¶
调用云端通用 API 是起点,但企业级 Agent 往往要解决三类问题,催生模型工程:
- 领域表现不够:通用模型在专业领域(金融尽调、客服话术)易幻觉、不懂术语 → 微调(SFT/LoRA);
- 数据合规/成本:敏感数据不能出域、API 调用费贵 → 私有化部署;
- 延迟与稳定性:云 API 延迟波动、有不可控风险 → 私有化推理 + 双活热备。
LoRA(Low-Rank Adaptation) 是最常用的参数高效微调(PEFT)方法。它的核心思想:不训练全部参数,只在原模型权重旁注入两个小矩阵 A、B,只训练这些低秩增量。原权重 W 冻结,等效更新为 W + ΔW = W + B·A,其中 B·A 是低秩分解。
- rank(秩 r)的含义:r 决定增量矩阵的"秩",即能学到的改动的"自由度"。r 越小参数越少、训练越快、越易过拟合不足;r 越大表达能力越强、但更贵、更易过拟合。彭超案例用 rank=16,是常见的平衡档(8/16/32/64)。
- LoRA vs 全参 SFT:全参 SFT 训练全部参数,效果上限高但显存/数据/算力成本量级更高,且容易"灾难性遗忘";LoRA 成本低、可插拔(一个基座挂多个 LoRA 适配器)、易回滚,适合大多数业务定制。
SFT(Supervised Fine-Tuning,监督微调) 用"输入-输出"配对数据教模型按期望方式回答。报告里彭超做的是 "LoRA + SFT 精调"——用 LoRA 这种高效方式做 SFT。
私有化部署三选型:
| 方案 | 定位 | 适用 |
|---|---|---|
| vLLM | 高吞吐推理引擎(PagedAttention、连续批处理),面向生产高并发 | 企业级生产、QPS 高、要榨干显存吞吐 |
| Ollama | 本地一键跑模型,面向开发者/单机快速验证 | 本地开发、Demo、单机小流量 |
| TGI(Text Generation Inference) | HuggingFace 出品,生产级推理,支持张量并行 | 生产部署、与 HF 生态紧耦合 |
一句话区分:vLLM 重吞吐、Ollama 重易用、TGI 重 HF 生态兼容。彭超案例生产用的是 vLLM(高并发 + 双活)。
原理¶
模型工程的真正难点不在"会调 LoRA 库",而在数据飞轮驱动持续迭代。彭超案例建立了 "用户反馈 + AI 审计 + CoT 归因"负样本挖掘管道:
- 用户反馈:用户点踩、纠错、低评分,是最直接的负信号来源;
- AI 审计:对 Agent 产出做自动审计(规则 + 模型判分),发现事实错误/合规问题;
- CoT 归因:把错误沿思维链回溯,定位是哪一步(检索/规划/执行/审核)引入了问题,而非笼统"模型不行"。
这三路信号汇成负样本池,反过来驱动两类迭代:Prompt 工程(改系统提示、Few-shot 示例、工具描述)与 SFT 数据迭代(把纠正后的正例加入训练集)。持续闭环后,彭超做到幻觉率 -30%、Token 成本 -45%、P95 延迟 < 800ms。
Token 成本 -45% 的常见手段:Prompt 压缩与精简(去冗余示例、合并上下文)、上下文裁剪(只留相关片段)、小模型分流(简单 query 用小模型、复杂才上大模型)、缓存命中(相同 query/工具结果复用)。
// 概念示意:私有化 vLLM 推理接入(Spring 风格),与云端 API 双活
public class DualActiveInference {
private final OpenAiLanguageModel cloudApi; // 云端 API(OpenAI 兼容)
private final OpenAiLanguageModel localVllm; // 私有化 vLLM(OpenAI 兼容协议)
public String infer(String prompt, QueryComplexity complexity) {
// 简单 query 走本地(省成本、低延迟),复杂走云端(强能力)
OpenAiLanguageModel backend = complexity == QueryComplexity.SIMPLE
? localVllm : cloudApi;
try {
return backend.generate(prompt); // 主路
} catch (Exception e) {
// 双活热备:主路失败切备路
return (backend == localVllm ? cloudApi : localVllm).generate(prompt);
}
}
}
/** LoRA 微调(离线,示意):rank=16,冻结基座只训低秩增量 */
// 实际训练多在 Python 侧用 LLaMA-Factory / PEFT 完成;
// Java 侧负责推理时加载 LoRA adapter + 调度。
# 概念示意:LoRA 微调(PEFT)+ vLLM 部署 + 数据飞轮
from peft import LoraConfig, get_peft_model
# 1. LoRA 微调:rank=16,只训低秩增量,基座冻结
def build_lora(base_model):
lora_cfg = LoraConfig(
r=16, # rank:增量矩阵的秩
lora_alpha=32, # 缩放系数,通常 2*r
target_modules=["q_proj", "v_proj"], # 注入注意力的投影层
lora_dropout=0.05,
task_type="CAUSAL_LM",
)
return get_peft_model(base_model, lora_cfg) # 冻结基座 + 注入 A/B
def finetune(train_pairs):
# train_pairs 来自数据飞轮:用户反馈 + AI 审计 + CoT 归因 挖出的正负样本
model = build_lora(load_base("Qwen2-7B"))
trainer.train(model, train_pairs) # SFT 监督微调
# 2. vLLM 部署:高吞吐,生产主力
from vllm import LLM
llm = LLM(model="./merged-qwen2-7b", enable_lora=True,
max_loras=4) # 一个基座挂多个 LoRA 适配器,可插拔
# 3. 数据飞轮:负样本挖掘驱动 Prompt / SFT 迭代
def data_flywheel(session_logs):
negatives = []
for log in session_logs:
if log.user_feedback < 0: # 用户点踩
negatives.append((log, "user_feedback"))
if audit_engine.has_issue(log.output): # AI 审计
negatives.append((log, "audit"))
# CoT 归因:沿思维链定位出错步骤,决定改 Prompt 还是补 SFT 数据
for log, src in negatives:
step = cot_attribution(log)
if step in ("prompt", "tool_desc"):
prompt_patch(log) # 改系统提示/Few-shot/工具描述
else:
sft_dataset.add(log.corrected) # 纠正后加入 SFT 训练集
实战要点¶
- rank 是自由度,不是"越大越好":rank 小训练快但欠拟合,大表达强但贵且过拟合。常见 8/16/32,按任务复杂度试;一个基座挂多 LoRA 比多个全参模型省得多。
- LoRA 优先于全参 SFT:业务定制场景 LoRA 性价比远高于全参,且可插拔、易回滚、少灾难性遗忘。全参 SFT 留给"必须深度重塑模型行为"的少数场景。
- 部署选型看场景:生产高并发选 vLLM(吞吐),本地开发选 Ollama(易用),HF 生态紧耦合选 TGI——讲清定位差异比笼统说"部署过大模型"有说服力。
- Token 成本 -45% 靠系统性优化:Prompt 精简 + 上下文裁剪 + 小模型分流 + 缓存,组合拳,不是单一银弹。配合简单/复杂 query 分流也是降延迟(P95 < 800ms)的手段。
- 数据飞轮是模型工程的核心竞争力:微调一次容易,"持续闭环迭代"难。把用户反馈、AI 审计、CoT 归因串成负样本挖掘管道,是 -30% 幻觉率的真正来源,也是面试深挖点。
- 不要只说"会微调":报告把微调列为前沿基线要素,但只列术语不讲 rank 含义、不讲数据来源、不讲效果归因,会被判关键词堆砌。
本节相关题目¶
| 难度 | 题目 | 链接 |
|---|---|---|
| 基础 | 什么是 LoRA、rank 影响什么 | → 题库 |
| 进阶 | LoRA vs 全参 SFT;vLLM/Ollama/TGI 定位差异;数据飞轮驱动迭代 | → 题库 |
| 深度 | "幻觉率 -30%/Token -45%/P95<800ms"归因与口径 | → 题库 |