Java 程序员第 50 阶段16:微调范式对比表:PT/SFT/RLHF/DPO
1. 四个范式不是升级关系,而是三层不同抽象:PT 建底座、SFT 教格式、偏好对齐调取舍
在大模型工程落地里,这个话题绕不开。很多 Java 同学刚接触时容易只看结论、不究原理,一旦线上出问题就无从下手。先把「为什么重要」说清楚,后面才好理解它怎么用。
四个范式经常被讲成一条“越来越先进”的升级路线,这是个危险的误解。它们解决的是三类完全不同的问题:预训练(PT)解决“模型会不会说话、知不知道世界”,SFT 解决“模型听不听话、输出格式对不对”,RLHF/DPO 解决“两个都对的回答里,模型更偏向哪一个”。抽象层不同,就不存在谁替代谁——就像问“数据库和缓存谁更好”一样,问题本身不成立。
判断该用哪个,只问三个问题,顺序不能乱。
第一问:是“不知道”还是“不听话”?让模型答一份内部制度文档,如果它答不出条款号,这是知识缺失,正确答案是 RAG 或继续预训练(CPT);微调只会让它把训练那一刻的知识焊死在权重里,第二天制度更新就全错。如果它知道内容,但输出格式乱七八糟、该用 JSON 却写成散文,这才是 SFT 的靶子。
第二问:问题出在“格式”还是“取舍”?格式能用规则校验(JSON 能不能解析、字段全不全、长度在不在区间),这类问题 SFT 几百条高质量样本就能把不合规率压到 2% 以下。但“两个回答都合规、都正确,业务方更喜欢 A”这种偏好,规则校验不出来,必须有成对比较数据,才进入 RLHF/DPO 的地盘。
第三问:数据够不够撑起这个范式?SFT 标的是“标准答案”,标注员照着规范写就行,可以外包、可以用强模型蒸馏;偏好对标的是“判断力”,标注员得能分辨两个都不错的回答谁更好,标注员之间的一致性(Kappa)经常只有 0.4–0.6,需要多人投票和仲裁才能用。样本量不够就硬上偏好对齐,最常见的结果是模型学会了某个标注员的怪癖,而不是业务偏好。
工程上还有一条被反复验证的路径:prompt + RAG → SFT(优先 LoRA)→ 偏好对齐。每一步都要先证明“上一步已经到顶”,因为越往后,迭代周期从小时级涨到天级,回滚成本从改一个配置涨到重训一个模型。

图 16-1 微调范式对比表:PT/SFT/RLHF/DPO——全局视角
2. 目标函数拆开看:交叉熵、loss mask、Bradley-Terry 与 DPO 的闭式解
先用一句话给概念下定义,再划清它的能力边界——什么它能做、什么它做不了。边界感比死记公式更重要。
四个范式的差别,最终都落在损失函数上。看懂四行公式,比看十篇科普有用。
PT 是标准的自回归语言建模:L_PT = −Σ log P(x_t | x_<t),序列里每个 token 都贡献 loss,包括标点和格式符号。这就是基座模型“会写但不会听指令”的原因——它学的是“下一个 token 该是什么”,不是“用户要我干什么”。
SFT 形式上还是同一个交叉熵,但加了一步关键的 loss masking:只对 assistant 回复区间的 token 算 loss,system 和 user 的 token 全部 mask 掉(label 置 -100)。这一步做错是新手最常见的坑:把 prompt 也算进 loss,模型会学成“复述用户问题”,线上表现就是答非所问地先把问题抄一遍。
RLHF 分两段。第一段训奖励模型,基于 Bradley-Terry 假设:同一 prompt 下,chosen 优于 rejected 的概率等于两者奖励差的 sigmoid,L_RM = −E[ log σ( r(x,y_w) − r(x,y_l) ) ]。注意 RM 学的是相对排序,单条回答的绝对分数没有意义,只有差值才有意义。第二段是 PPO,目标 J = E[r(x,y)] − β·KL(π_θ ‖ π_ref):前一项让它讨好 RM,后一项把它拴在参考模型附近,防止为了刷分把语言能力刷崩。
DPO 的天才之处是绕开了 RM。带 KL 约束的策略优化有闭式解 π*(y|x) ∝ π_ref(y|x)·exp(r(x,y)/β),反解出 r 再代回 Bradley-Terry,同一 prompt 下配分函数 Z(x) 在差值里被消掉,得到 L_DPO = −E[ log σ( β·log(π_θ(y_w)/π_ref(y_w)) − β·log(π_θ(y_l)/π_ref(y_l)) ) ]。整条链路只要 policy 和 reference 两个模型,没有在线采样、没有价值网络、没有单独的 RM。
但 DPO 不是“免费午餐”。它的梯度权重与隐式奖励的估计误差挂钩:当模型已经把 chosen 和 rejected 分得很开时,这一对的梯度趋近于零;分不开的“难对”反而权重最大。这意味着偏好对里的噪声(标注手滑、两个回答其实差不多)会被放大,也是后来 IPO(换成平方损失抑制过拟合)、KTO(不需要成对,只要好坏标签)、ORPO(SFT 与偏好对齐合成一步)这些变体出现的原因。
3. 数据与算力差多少:三个数量级的 token,两个数量级的成本
它不是黑盒,拆开看就是几个清晰的步骤。下面按执行顺序逐步说明,建议结合你自己的业务场景在脑子里走一遍。
把四个范式的资源量级摆在一起,选型时就不容易被“我们也要做 RLHF”这种话带偏。
数据量差三个数量级。PT 是万亿 token 级,SFT 是千到十万条指令,偏好对齐是万到百万对。注意单位不同:PT 按 token,SFT 按“条”(一条可能几百 token),偏好按“对”。很多团队汇报“SFT 用了 100 万条”,一算 token 才发现是把同一份数据套了多种 prompt 模板做增强,真实覆盖的场景可能只有几千个——指标好看,泛化很差。
标注成本差一个数量级。SFT 可以外包、可以靠强模型蒸馏、可以半自动构造;偏好对不行,它要求标注者具备业务判断力,而且必须处理“两个都不错”的模糊情形。经验上,5 千对高质量偏好数据的标注成本,大致相当于 5 万条 SFT 样本。
算力差别最直观。全参 SFT 训一个 7B 模型至少 8 卡 A100/H800,13B 以上要考虑 ZeRO-3 或 FSDP;LoRA 把可训练参数压到 1% 以下,单张 24G 卡就能跑 7B。RLHF-PPO 的痛点在显存常驻:actor、critic、reward、reference 四个模型同时在册,70B 级别光 fp16 权重每份就约 140GB,四份叠起来再算优化器状态和激活,落地基本是多机集群。DPO 只要 policy 和 reference,reference 甚至可以只做前向、不存梯度,单机多卡就能训。
时间尺度也不一样:PT 数周到数月,全参 SFT 数小时到数天,LoRA 几十分钟到几小时,DPO 通常几小时,PPO 因为要在线和反复调参,常常是“跑一周调两周”。
这张账算下来,结论很清楚:对绝大多数业务团队,能靠 prompt 和 RAG 解决的就不要动权重;必须动权重时先上 LoRA-SFT;只有当“格式已达标、纯粹是偏好问题”且样本充足时,才轮到偏好对齐。把顺序倒过来做,预算和时间都填不满这个坑。

图 16-2 微调范式对比表:PT/SFT/RLHF/DPO——处理流程
4. Java 工程侧如何落地(含代码示例)
对 Java 工程师来说,最终要落到代码和工程集成上。下面给出可运行的骨架,重点是理解「数据流怎么走、异常怎么兜」。
Java 工程师在这条链路里的位置,不是“跑训练脚本”,而是三件事:选型判定、训练编排、验收门禁。训练本身交给算法同学或训练平台(LLaMA-Factory、ms-swift、云厂商微调服务),Java 侧负责把“要不要微调、用哪种范式、训完能不能放量”变成可执行、可审计的逻辑。
第一件事是把需求翻译成画像。业务方说“模型不好用”,这句话没有信息量,要拆成可度量的四个率:格式不合规率、跑题率、知识缺失率,以及“两个回答都合规但业务更偏好 A”的比例。前三个能从线上日志和规则校验直接算,第四个只能靠人工成对评估。四个率算不出来,就不该开训——因为训完也没法证明变好了。
第二件事是编排。一次微调任务的完整输入应该被固化成 manifest:数据集版本哈希、范式、超参、基座模型版本、chat template 版本、评测集版本。这不是洁癖,是复现的前提。线上效果不对时,第一件事就是确认“这个模型到底是用哪份数据、哪个基座训出来的”,manifest 缺失就只能重训。
第三件事是门禁,也是 Java 侧最有价值的部分,因为训练平台不会替你判断“能不能上线”。门禁必须区分硬指标和软指标:格式通过率、事实性得分是硬指标,退化一律否决;成对胜率是软指标,要显著提升才放量。这条区分极其重要——偏好对齐最常见的副作用就是“更讨喜但更不守格式”,只看胜率,你会放量一个把 JSON 写成散文的模型。
下面这段代码把选型判据和验收门禁写成了可单测的形式,实际项目里直接挂在发布流水线前面。

图 16-4 微调范式对比表:PT/SFT/RLHF/DPO——调用链路
5. 与相近方案的对比取舍:什么时候根本不该微调
它不是唯一解法,和它容易混淆的还有几个方案。一张表看清区别与取舍,选型时才不踩坑。
选型表容易背,难的是判断“什么时候根本不该微调”。先说不微调的两种情形:知识时效性强(政策、价格、库存、工单状态),正确答案是 RAG;任务能被确定性规则覆盖(金额计算、权限判断、流程流转),正确答案是代码。这两种情况硬上微调,得到的是一个“看起来懂了但会算错”的模型,比直接报错更危险,因为错误不再可预测。
再看表里最容易被忽略的一列——“典型翻车”。PT 的翻车是灾难性遗忘和知识过期;全参 SFT 的翻车是过拟合到训练集话术、通用能力掉点;LoRA 的翻车是只学到表层风格、复杂推理没变;PPO 的翻车是 reward hacking(奖励分数一路涨,人工看回答越来越差);DPO 的翻车是偏好对噪声被放大,以及长度偏置(模型学会“越长越好”,堆套话)。
有一组对照值得记牢:RAG 和微调不是竞争关系。RAG 改的是“模型能看到什么”,微调改的是“模型习惯怎么回答”。前者延迟高、可解释、可审计、知识可秒级更新;后者延迟低、风格稳、但知识一旦过期就得重训。真实系统里两者叠加:RAG 供事实,SFT 供格式与话术,偏好对齐供取舍。

图 16-3 微调范式对比表:PT/SFT/RLHF/DPO——方案对比
关键参数与调优
| 参数 / 判据 | 作用 | 建议起点 | 调错的表现 |
|---|---|---|---|
| labeledPairs | 决定能否全参微调 | <500 用 LoRA;≥5000 再考虑全参 | 样本少硬上全参→验证集 loss 反弹 |
| preferencePairs | 决定偏好对齐是否可行 | DPO ≥5k;PPO ≥50k | 几百对硬训→学成标注员怪癖 |
| loss mask | 只对回复区间算 loss | 必须开(其余 label=-100) | 不开→模型学会复述用户问题 |
| β(DPO) | 控制偏离 reference 的强度 | 0.1(区间 0.01–0.5) | 过大→几乎学不动;过小→语言能力崩 |
| KL 系数(PPO) | 拴住策略别离参考模型太远 | 0.02–0.1,可自适应 | 过小→reward hacking;过大→学不动 |
| learning rate | 学习率 | 全参 1e-5–2e-5;LoRA 1e-4–3e-4 | 过大→loss 震荡、格式崩;过小→欠拟合 |
| epoch | 训练轮数 | SFT 2–3;DPO 1–2 | 轮数过多→复述训练集原话 |
| LoRA r / alpha | 适配器容量与缩放 | r=8–16,alpha=2r | r 过小→学不动;过大→等同全参的过拟合 |
| formatPass 门限 | 硬指标门禁 | 0.98 且不低于基线 0.5pt | 不设→放量「更讨喜但不守格式」的模型 |
| winRate 门限 | 软指标门禁 | ≥0.55 才放量 | 只看胜率→忽略格式与事实性退化 |
6. 生产环境踩坑与面试高频点
真正用过的人,踩过的坑都差不多。这里把最常见的几个和对应的面试追问列出来,提前避坑、也方便复盘。
这一节的坑,基本都是“看起来做对了,实际上差了关键一步”。
最隐蔽的一类是数据泄漏。评测集和训练集来自同一批标注,或者用同一个强模型蒸馏出的答案做训练、又拿它做评测,指标会漂亮到不真实,上线立刻打回原形。正确做法是评测集单独人工标注、单独版本管理,且与训练集做近似去重(n-gram 或 embedding 相似度都行)。
第二类是基座与 tokenizer 版本没锁。同一个模型名,不同时间拉下来的权重可能已经换了小版本,chat template 也可能变。tokenizer 一变,SFT 的 loss mask 位置整体偏移,训练 loss 照样下降,效果却极差——这类问题几乎无法从训练日志看出来,只能靠固定版本 + 哈希校验避免。
第三类是对齐过度的连锁反应。偏好对齐把拒答率刷上去以后,业务侧会报“模型变笨了,很多正常问题都不答”,这时正确的修法不是继续加 SFT 数据,而是回退对齐强度、补“应当回答”的正样本、放宽 system prompt 里的边界描述。
面试问这块,重点从来不在背公式,而在“你能不能判断该用哪个、以及怎么证明变好了”。下面把高频问法整理成四组。
踩坑清单
| 现象 | 根因 | 修法 |
|---|---|---|
| 训练 loss 一路下降,线上却答非所问 | loss mask 没开,模型在学复述 prompt | 只对 assistant 区间算 loss,其余 label 置 -100 |
| SFT 之后通用能力明显下降 | 全参微调 + 数据全是单场景,无通用数据混入 | 混入 5–10% 通用指令数据;样本少先上 LoRA |
| DPO 后回答越写越长,还爱堆套话 | 长度偏置:偏好对里长回答更常被选中 | 偏好对按长度分层采样;或用 SimPO/ORPO 抑制长度偏置 |
| 评测指标 0.9+,上线大幅回落 | 训练集与评测集同源,或同门模型互评 | 评测集独立人工标注、单独版本管理,并与训练集去重 |
| 同一个模型名,两次训练结果差异很大 | 基座权重或 chat template 漂移,tokenizer 变了 | 锁定权重哈希与 template,写进 manifest |
| PPO 奖励涨,人工看回答越来越差 | reward hacking:策略找到 RM 的漏洞 | 加 KL 惩罚、定期人工成对评估、RM 同步迭代 |
| 微调后知识全是旧的 | 用微调替代 RAG,知识被焊进权重 | 时效性知识走检索;微调只负责格式与话术 |
| LoRA 合并后效果掉一截 | merge 精度不当或漏合并部分 adapter | 合并后跑同一套评测集回归,退化超 1pt 不放量 |
面试追问与答法
Q:SFT 和 RLHF 到底谁更重要?
A:看阶段,也看问题类型。SFT 决定上限——模型没见过的好格式、好话术,偏好对齐也变不出来;偏好对齐决定取舍——两个都合格的回答里选哪个,SFT 教不了。工程上的经验比例是:只要格式和术语问题,SFT 就够,别上偏好对齐;只有当“格式已经 98% 合规,业务还嫌回答不自然、不贴心”时,才值得投入偏好数据。反过来说,SFT 数据质量差,偏好对齐只会把差的风格学得更牢。
Q:DPO 能完全替代 PPO 吗?
A:不能。差别不在效果上限,而在信息通道。DPO 是纯离线方法,只能学偏好数据里出现过的模式;PPO 能在训练中持续采样探索,还能接入过程奖励(代码是否跑通、检索是否命中、工具调用是否成功),这类“可验证奖励”是 DPO 拿不到的。看业界选择就很清楚:开源模型的后训练大量用 DPO 家族(DPO/IPO/KTO/ORPO/SimPO),闭源旗舰仍以 PPO 系为主,正是这个边界决定的。
Q:偏好对要多少才够?
A:不看绝对数量,看“难对”比例。5 千对里如果 80% 的 chosen 明显优于 rejected,模型几百步就把它们分开了,梯度趋零,学不到细粒度偏好;反过来 3 千对“两个都合格、只差一点”的难对,效果往往更好。实操建议:5k–20k 起步,标注时明确要求“两个都合格”的情形也要选出更优的一个,并保留 10% 做一致性校验。
Q:什么时候用 LoRA,什么时候全参?
A:三条判断线。数据量:<1 万条基本只能 LoRA,否则过拟合跑不掉。目标类型:学格式、学话术、学术语 → LoRA;注入大量新知识(继续预训练)→ 全参。资源与风险:通用能力不能掉、卡不够 → LoRA;模型容量本身不够、必须扩能力 → 全参。另外别忘了 LoRA 的隐性成本:推理时要多一步 merge,merge 精度和 adapter 遗漏是线上事故高发点,合并后必须跑同一套评测集回归。
/**
* Java 程序员第 50 阶段16:微调范式对比表:PT/SFT/RLHF/DPO
* Java 侧不训模型,但要回答两个问题:
* 1) 这次到底该用哪种范式(还是根本不该微调)
* 2) 训完之后凭什么判定「可以放量」
* 把选型判据与验收门禁写成可单测的代码,避免「领导说要微调」就直接开训。
*/
public final class FineTunePlanner {
/** 需求画像:每一项都能从线上日志或评测集回填,禁止拍脑袋填 */
public record Demand(String scene,
int labeledPairs, // 可用 SFT 样本条数
int preferencePairs, // 可用偏好对条数
double formatFailRate, // 线上格式不合规率
double offTopicRate, // 线上跑题/超范围率
double knowledgeMissRate, // 线上「答不出」率
boolean canMaintainRewardModel) { }
public enum Paradigm { PROMPT_RAG, SFT_LORA, SFT_FULL, DPO, RLHF_PPO }
/** 选型判据:先问缺什么 → 再问有多少数据 → 最后才问用哪个算法 */
public Paradigm decide(Demand d) {
// ① 知识缺失优先补检索:知识天天更新,微调只会把「今天的知识」焊死在权重里
if (d.knowledgeMissRate() > 0.15 && d.formatFailRate() < 0.05) {
return Paradigm.PROMPT_RAG;
}
// ② 格式与话术问题用 SFT;样本不足 500 条先上 LoRA,避免过拟合与灾难性遗忘
if (d.formatFailRate() >= 0.05 || d.offTopicRate() >= 0.10) {
return d.labeledPairs() < 500 ? Paradigm.SFT_LORA : Paradigm.SFT_FULL;
}
// ③ 格式已达标、只是「答得不够讨喜」,才轮到偏好对齐
if (d.preferencePairs() >= 5_000) {
// PPO 要在线采样 + 长期维护奖励模型,团队接不住就老实做 DPO
return (d.preferencePairs() >= 50_000 && d.canMaintainRewardModel())
? Paradigm.RLHF_PPO : Paradigm.DPO;
}
throw new IllegalStateException("证据不足:先补评测集与失败样本,再谈微调");
}
/** 评测报告:硬指标看绝对值,软指标看成对胜率 */
public record Report(double formatPass, double factScore, double winRate, double refuseRate) { }
public static final double MIN_FORMAT_PASS = 0.98; // 硬阈值:低于即否决
public static final double MIN_WIN_RATE = 0.55; // 软阈值:成对比较胜率
public static final double MAX_REFUSE_RATE = 0.08; // 过度拒答红线
public boolean releasable(String scene, Report base, Report cand) {
List<String> block = new ArrayList<>();
if (cand.formatPass() < MIN_FORMAT_PASS) {
block.add("格式通过率 %.3f 低于硬阈值 %.2f".formatted(cand.formatPass(), MIN_FORMAT_PASS));
}
// 硬指标退化一律否决:偏好对齐最常见副作用就是「更讨喜但更不守格式」
if (cand.formatPass() < base.formatPass() - 0.005) {
block.add("格式通过率相对基线退化");
}
if (cand.factScore() < base.factScore() - 0.01) {
block.add("事实性得分退化,疑似 reward hacking");
}
if (cand.winRate() < MIN_WIN_RATE) {
block.add("成对胜率 %.3f 未达阈值 %.2f".formatted(cand.winRate(), MIN_WIN_RATE));
}
if (cand.refuseRate() > MAX_REFUSE_RATE) {
block.add("拒答率 %.3f 超红线,疑似对齐过度".formatted(cand.refuseRate()));
}
if (!block.isEmpty()) {
log.warn("scene={} 不放量: {}", scene, block);
return false;
}
log.info("scene={} 允许放量 winRate={}", scene, cand.winRate());
return true;
}
}
| 范式 | 优化目标 | 数据形态与量级 | 算力与显存 | 解决什么问题 | 典型翻车 |
|---|---|---|---|---|---|
| PT 预训练 | 自回归交叉熵,全序列算 loss | 万亿 token 无标注语料 | 千卡·周级 | 基座的语言能力与世界知识 | 灾难性遗忘、知识过期、成本失控 |
| CPT 继续预训练 | 同 PT,领域语料 + 混入通用语料 | 十亿–百亿 token | 百卡·日级 | 注入领域知识或新语言 | 通用能力掉点、遗忘 |
| SFT 全参 | 交叉熵,仅 assistant 区间算 loss | 5k–10 万条指令-回答 | 8 卡 A100/H800 起 | 指令遵循、输出格式、话术 | 过拟合训练集话术、通用能力退化 |
| SFT LoRA | 同上,仅低秩适配器可训 | 500–1 万条 | 单卡 24G 可跑 7B | 低成本学格式与风格 | 只学到表层风格,复杂推理没变 |
| RLHF-PPO | RM 打分 + KL 约束的策略梯度 | 5 万对以上偏好 + 在线采样 | 四模型常驻,多机集群 | 精细偏好,可接入过程奖励 | reward hacking、训练不稳、调参周期长 |
| DPO | 成对偏好的分类式损失,无 RM | 5k–10 万对偏好 | policy + reference,单机多卡 | 稳定、可复现的偏好对齐 | 偏好对噪声放大、长度偏置、离线无探索 |
更多推荐

所有评论(0)