Skip to content

微调与私有化部署 ​

绝大多数「我们需要微调」的需求,其实是RAG 或 Prompt 没做好。 这篇先讲什么时候真的该微调,再讲怎么做、怎么部署、怎么算钱。

一、先判断:微调是不是你需要的 ​

你的问题该用什么
模型不知道你们公司的业务知识RAG(知识时效性强、要引用来源)
输出格式总是不对Prompt + 结构化输出(JSON Mode),实在不行再微调
语气/风格要像某个角色Prompt 写人设,微调是加分项
某类任务要稳定达到高准确率(分类、抽取、改写)微调
要降低延迟/成本(用小模型替代大模型)微调小模型(蒸馏)
数据不能出内网私有化部署(未必需要微调)

一条经验:先 Prompt,再 RAG,最后微调。微调是「改模型的行为」,不是「塞知识」—— 用微调记知识,会遇到更新困难、幻觉、以及「问细节就崩」的问题。

二、微调能改什么、不能改什么 ​

能不能
输出格式、风格、语气记住大量事实性知识(会编)
特定任务的模式(分类口径、抽取规范)实时信息
减少对长 Prompt 的依赖解决「推理能力不足」(那是模型规模问题)
让小模型逼近大模型在窄任务上的表现通用能力全面提升

三、SFT 的数据怎么造 ​

数据三条来源 ​

来源质量成本
人工标注(专家写)最高最贵
业务日志清洗(真实问答 + 人工修正)高中
强模型生成 + 人工筛选(蒸馏)中低

数据格式(对话式 SFT) ​

json
{"messages": [
  {"role": "system", "content": "你是客服助手,只回答退换货相关问题。"},
  {"role": "user", "content": "耳机坏了能退吗"},
  {"role": "assistant", "content": "7 天内非人为损坏可退,请提供订单号。"}
]}
{"messages": [
  {"role": "system", "content": "你是客服助手,只回答退换货相关问题。"},
  {"role": "user", "content": "耳机坏了能退吗"},
  {"role": "assistant", "content": "7 天内非人为损坏可退,请提供订单号。"}
]}

五条数据纪律 ​

  1. 量不是关键,一致性才是:500 条高质量 > 5000 条噪声;
  2. 覆盖边界:正例之外要有「不该回答时怎么拒绝」的样本;
  3. 去重:重复样本会让模型过拟合到特定表述;
  4. 划分验证集:训练/验证/测试分开,测试集绝不参与调参;
  5. 清洗掉模型自身错误(用模型生成的数据要先筛,否则错误会被固化)。

四、LoRA 与 QLoRA ​

全参数微调要更新所有参数(7B 模型也要几十 GB 显存)。LoRA 的思路:冻结原模型,只训练很小的低秩矩阵。

原始权重 W(冻结)  +  ΔW = B·A(低秩,可训练)
h = Wx + (α/r)·BAx
原始权重 W(冻结)  +  ΔW = B·A(低秩,可训练)
h = Wx + (α/r)·BAx
参数含义常用值
r(rank)低秩维度,越大容量越强8 / 16 / 32
alpha缩放系数,通常 = 2r16 / 32
target_modules加到哪些层q_proj/k_proj/v_proj/o_proj(或全部线性层)
dropout防过拟合0.05 ~ 0.1
learning_rate学习率(比全参大)1e-4 ~ 3e-4

QLoRA = LoRA + 4bit 量化基座(NF4),让 7B 模型能在单卡 24GB 上训练。

python
# 伪代码(transformers + peft)
model = load_quantized("qwen2-7b", load_in_4bit=True)     # QLoRA
model = get_peft_model(model, LoraConfig(
    r=16, lora_alpha=32, lora_dropout=0.05,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
    task_type="CAUSAL_LM",
))
trainer.train()
model.save_pretrained("out/lora")     # 只存几十 MB 的 adapter
# 伪代码(transformers + peft)
model = load_quantized("qwen2-7b", load_in_4bit=True)     # QLoRA
model = get_peft_model(model, LoraConfig(
    r=16, lora_alpha=32, lora_dropout=0.05,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
    task_type="CAUSAL_LM",
))
trainer.train()
model.save_pretrained("out/lora")     # 只存几十 MB 的 adapter

优势:显存小、训练快、adapter 只有几十 MB,可热插拔多套。 代价:容量有限,复杂任务不如全参;推理时多一次矩阵乘(可合并进原权重)。

五、训练流程与坑 ​

造数据 → 划分集 → 基线评测(不微调先测一遍!)→ 训练 → 验证集看 loss
      → 测试集评测(规则 + judge)→ 人工抽检 → 上线灰度
造数据 → 划分集 → 基线评测(不微调先测一遍!)→ 训练 → 验证集看 loss
      → 测试集评测(规则 + judge)→ 人工抽检 → 上线灰度

必须先跑基线:不微调前测一遍,否则你不知道微调到底提升了多少(甚至可能变差)。

坑表现处理
过拟合训练 loss 降、验证 loss 升减 epoch、加 dropout、减 r
灾难性遗忘通用能力下降混入通用数据、降低学习率
格式崩坏输出不带标签了检查模板是否与推理一致
数据泄漏测试集分数虚高严格切分、去重
模板不一致线上效果远差于训练训练与推理用同一 chat template

六、私有化部署:四种形态 ​

形态说明适用
裸模型 + 推理框架vLLM / SGLang 起服务,自己封装 API有运维能力
一体化平台平台包办部署、监控、扩缩容中小团队
一体机厂商交付硬件 + 模型强合规、无运维
云上专属实例云厂商托管的独享资源弹性需求

七、推理优化(部署侧最值钱的部分) ​

手段原理收益
PagedAttention(vLLM)KV Cache 分页管理,消除碎片吞吐 2~4 倍
Continuous Batching请求动态进出批高并发下吞吐大涨
量化(INT8/FP8/AWQ/GPTQ)权重降精度显存降一半,速度升,质量略降
KV Cache 复用 / prefix caching相同系统提示复用缓存长 system prompt 场景显著
投机解码(speculative)小模型起草、大模型校验延迟降低
张量并行大模型切到多卡能跑更大模型

关键指标:TTFT(首字延迟)、TPOT(每 token 时间)、吞吐(tokens/s)、显存占用。 注意:量化会带来质量损失,必须用量化后的模型重跑评测集,不能沿用原分数。

八、成本怎么算 ​

显存 ≈ 参数量 × 精度字节数(FP16: 2B/参数)+ KV Cache
  · 7B FP16 ≈ 14GB(还要给 KV Cache 留 10~20GB)
  · 7B INT4 ≈ 4GB

吞吐估算:单卡 A100 跑 7B + vLLM,batch 下可达 2000~4000 tokens/s(视输入长度)
成本 ≈ 单卡时价 × 小时数 / 总 token 数
显存 ≈ 参数量 × 精度字节数(FP16: 2B/参数)+ KV Cache
  · 7B FP16 ≈ 14GB(还要给 KV Cache 留 10~20GB)
  · 7B INT4 ≈ 4GB

吞吐估算:单卡 A100 跑 7B + vLLM,batch 下可达 2000~4000 tokens/s(视输入长度)
成本 ≈ 单卡时价 × 小时数 / 总 token 数

国产/开源模型自建 vs 调 API 的分水岭:日调用量稳定且大(比如日均千万 token 以上)、或有数据不出内网要求时,自建才划算;否则 API 更省心。

九、速查 ​

问题答案
什么时候该微调要稳定格式/风格/窄任务准确率,或蒸馏小模型
什么时候不该要模型「知道」业务知识 → 用 RAG
顺序Prompt → RAG → 微调
LoRA 是什么冻结原模型,只训低秩矩阵(几十 MB 的 adapter)
QLoRA 加了什么4bit 量化基座,单卡可训 7B
微调前必须做什么先跑基线评测
最常见的坑数据不一致、模板不一致、灾难性遗忘
部署用什么vLLM / SGLang(PagedAttention + 连续批处理)
量化后要注意必须重跑评测集,分数会变
什么时候自建量大稳定 + 数据不出内网