很多团队给指令微调加上Curriculum Learning后,最先看到的是 loss 下降更快、吞吐更平稳,评审会上也容易把这当成“训练终于更聪明了”。⚠️ 真正到线上,问题却会反着来:简单问答更顺,复杂推理、长回答和工具约束场景反而更容易漂。🎯
课程学习为什么容易把前期指标优化成假象
很多实现只做一件事:把短样本、单轮样本和高频模板排在前面。🔍 这样确实能让前1 k - 2 kstep 的梯度更稳定,但也会让模型过早适应“短、浅、格式统一”的分布。等难样本后置进入,优化器面对的已不是同一条任务曲线,而是一次分布切换。🧠
更隐蔽的问题在Replay Ratio。📌 如果课程阶段切换后,早期见过的易样本持续出现,晚到的难样本占比又不够,模型会把 easy pattern 学得越来越硬,把真正影响上线质量的长链推理、拒答边界和结构化约束学得越来越晚。表面是 loss 还在降,实质是 hard slice 一直没补齐。📉
一组 7 B SFT 回放比调学习率更说明问题
这次回放的是7 B指令微调任务,数据量52万条,序列长度8192。🧪 基线组使用全量随机混采;方案二采用 easy-first 单向课程;方案三改为三段Difficulty Bucket,并给 hard bucket 保留18%的 replay floor。结果很直接,前期看起来最漂亮的方案,终盘并不好。📊
| 方案 | 前 2 k step 验证 loss | Hard set 通过率 | 长回答格式通过率 | 典型现象 |
|---|---|---|---|---|
| 全量随机混采 | 1.93 | 81% | 88% | 收敛稳,但前期不惊艳 |
| easy-first 单向课程 | 1.84 | 72% | 79% | 前期快,后期 hard slice 回落 |
| bucket + replay floor | 1.88 | 85% | 90% | 前期略慢,终盘最稳 |
这组数据最容易打破的误区,是把前期 loss 速度当成课程学习的唯一收益。📍 easy-first 方案几乎总会更好看,因为短样本、固定模板和低冲突回答更容易拟合;可一旦上线任务更接近 hard bucket,之前省下来的训练噪声,会在后期以泛化缺口的形式补回来。🚨
最关键的观察不是“课程学习没用”,而是它不能只是排序开关。✅ 真正稳的做法,是把课程阶段、样本难度和 hard replay 一起建模:每个 bucket 单独看 loss、拒答率和格式通过率,只要 hard slice 连续两轮不涨,就提前抬高 replay,而不是继续迷信 easy-first。🛠️
defsample_mix(step,total_steps):phase=step/total_steps easy=0.55ifphase<0.2else0.35medium=0.27ifphase<0.2else0.37hard=0.18ifphase<0.2else0.28replay=max(0.18,hard)return{"easy":easy,"medium":medium,"hard":hard,"replay_floor":replay}生产里要把课程预算做成回放控制
生产里更值得默认化的,是课程预算而不是课程神话。🔒 难度分桶最好同时看回答长度、工具步数、拒答冲突和人工返修率;阶段切换不要按固定 step 硬切,而要看 hard bucket 的增益是否真正追上。📎 如果 hard slice 没有单独记录,团队就会一直被总 loss 误导。🧩
笔者认为,未来3 - 6个月更有效的方向,不是更复杂的课程名字,而是把Replay Ratio做成训练门禁。🚀 把课程学习从“先喂简单题”升级成“持续控制任务分布”,收益才会真正留到上线阶段,而不是只留在前几千步的报表里。💡
如果团队现在的课程学习还只是“先喂简单题,再喂难题”,最该补的不是更细的难度标签,而是:难样本有没有被持续、可审计地回放进主训练轨迹。你们现在盯的,是前2 kstep 的漂亮 loss,还是最终 hard slice 的真实通过率?💬