大模型训练这两年已经从“能跑通”进化到“要跑好”SFT监督微调和RL强化学习基本上成了提升模型能力的两个必答题。但我在跟很多刚入行的同学交流时发现大部分人要么停留在“知道有这么回事”要么被一堆GRPO、KL散度、reward hacking的术语劝退。这篇文章不绕弯子直接把我自己调模型时踩过的坑、验证过有效的方法从数据准备到超参选择再到问题排查串成一条可以照着操作的路线。不敢说看完你就能调出顶级模型但至少能让你少走几个月的弯路。这更适合正在做模型微调实践、或者准备从SFT往RL方向进阶的算法工程师和独立开发者。哪怕你是刚接触大模型的小白只要懂一点深度学习的皮毛也可以对照着一步步来。1. 先想清楚SFT和RL分别解决什么问题1.1 预训练、SFT、RLHL各自的分工很多刚入门的朋友容易把这几件事混成一个概念其实它们解决的是完全不同的阶段问题。预训练是让模型学会语言本身目标是预测下一Token这个阶段的模型像是一个读过海量资料、但不知道怎么回答问题的“博学者”。它知道知识但不知道人类期待它以什么格式、什么口吻、什么结构来回应。SFT就是在预训练模型的基础上给一批“问题-标准回答”的成对数据让模型模仿这些示例学会怎么回答。这一步的核心是模仿模型从中学到的不只是内容更重要的是回答的结构、风格和信息组织方式。我做SFT时有个很直观的感受如果数据里都是分点回答、步骤清晰的格式模型就会大概率主动往这个格式靠哪怕内容并不需要这样组织。这既是优势也是需要警惕的地方——格式过拟合在SFT里非常常见。RL则是把“模仿”升级为“目标优化”。SFT只要求模型“像示例一样回答”但示例往往不是最优回答。有些任务光是模仿不够还需要模型在探索中去发现更好的策略。RL通过设计奖励信号让模型在生成过程中反复试错逐步提高得分。RL调的是策略让模型不仅会说人话还会说“能拿到更高奖励的人话”。这里有个关键认知SFT更像是给模型打地基RL是在这地基上装修。地基没打好RL再怎么优化也很难突破上限。我在实际项目中见过好几例SFT阶段数据质量一般然后寄希望于RL去救结果奖励一路涨、真实效果却稀烂。原因很简单RL是在SFT给出的策略附近探索基础策略本身有问题探索方向也就偏了。1.2 什么时候该用SFT什么时候必须上RL需要明确一点不是所有场景都需要RL。如果任务类型是“格式改写”“抽取摘要”“分类打标”SFT就能很好解决因为这些任务的核心是理解并遵循指令正确答案空间比较明确。我在做结构化信息抽取的Demo时只做了SFT效果就已经远超直接用预训练模型根本不需要碰RL。但如果任务是开放式生成比如让模型写代码、写故事、做数学推理、让回答更符合人类偏好这时候“标准答案”很难定义那就需要RL登场了。RL的核心价值在于当无法穷举出所有好答案时让模型自己在搜索空间里探索并通过奖励信号学会哪个方向更容易获得高分。比如数学推理SFT数据里只有一种解题路径但最优秀的路径可能并不在训练集里RL就能在探索中找出那类被训练数据忽略的更优策略。另外还有一种情况值得用RL——需要抑制模型的某些倾向。比如SFT之后模型可能过于啰嗦什么都拆成一二三也可以用RL的奖励函数设计来引导模型学会更简洁的表达。甚至token预算、格式约束这类偏工程的问题也能通过奖励设计变成模型自己学会的“习惯”这比写硬编码规则要鲁棒得多。我个人的决策参考表大致是这样的任务类型推荐路径原因指令遵循、格式提取、分类仅SFT标准答案明确模仿即可开放生成、创意写作、通用对话SFT RL偏好优化需要探索高分策略数学推理、代码生成SFT RL过程/结果奖励需要发现超越样本的更优路径急需控制长度、格式等风格属性SFT 轻量RL奖励可以直接代显式属性数据量非常小几百条以内仅SFT甚至考虑few-shotRL需要更多探索空间现在还流行绕过SFT直接做RL的玩法比如一些从基座直接强化学习的方案。我试过一轮在小数据集上确实可行但对奖励设计的要求很高模型容易进入“自由发挥”的乱飘状态。对大多数人来说先SFT再RL仍然是性价比最高的路径。1.3 一个完整的训练流程长什么样先给你一张我平时跑项目的流程图谱帮你建立整体感。注意这里不涉及任何代码只讲流程基座模型选型数据准备与清洗SFT阶段第一轮SFT训练 → 生成候选模型评测与筛选 → 决定进入RL还是继续优化SFT数据构建奖励模型或使用规则奖励/外部打分器RL训练PPO或GRPO等多轮评估与人工盲测防退化检查通用能力是否下降上线与持续迭代这套流程我跑过很多遍最核心的心得是评估节点一定要前置。不要等RL训练完才想起来做评测而是SFT出来一个版本就立刻拿去测测完决定下一步动作这样能省掉大量白训的时间。2. SFT细节拆解数据质量比你想象的更重要2.1 数据数量几千条也能做大文章很多人一上来就问“SFT需要多少数据”好像这是个固定值。不存在的。以我自己的实验经验来看在基座模型能力比较强的前提下精心整理的四五千条高质量指令数据效果经常会好过直接用网上的百万级混合数据集。原因在于SFT的核心目标是教模型“遵循指令的格式和风格”而不是教知识——知识已经在预训练阶段存进去了。SFT数据的作用更像是一个“使用说明书”告诉模型怎么把已经学会的东西拿出来用。所以我给自己定了个数据原则能用5000条解决的事绝不上10万条。数据少意味着更容易做质量控制更容易排查bad case训练成本也更低迭代速度反而更快。当然这不意味着数据越少越好。如果任务本身覆盖了多个领域、多种语言、多种格式数据量需要相应上调但优先把每个维度的多样性做够而不是简单求多。2.2 指令数据的四个质量维度我在清洗SFT数据时会重点核查四件事第一格式一致性。同一个数据集的指令头如果一会儿是“请回答下面的问题”一会儿是“你是一名助手”模型就会学到不稳定的服从行为。我处理时会统一改成一套模板比如全部使用“### 指令... ### 回答...”的结构实测格式统一后模型遵循指令的稳定性有明显提升。第二答案完整性。别只看开头几句要通读整个回答。我踩过最大的坑是一个数学问答数据集的答案是错的但模型照单全收学会了错误解法。所以在SFT阶段答案的准确性怎么强调都不为过。你要记得模型不会分辨数据里的对错它只会学到“这样答会被表扬”。第三多样性覆盖。同样是“讲个笑话”这个指令我得确保训练集里既有短笑话、也有段子式回答、还有绕口令式的回答。多样性是防止模型过拟合到单一回答模式的关键。第四复杂性分层。简单指令和复杂指令要有合理的配比。全上简单指令模型就只能做简单任务全上复杂指令基础能力可能不稳。我常用631的配比——六成普通难度三成偏复杂一成极端困难。2.3 模板设计不要忽略这一层SFT里有个很容易被忽视的细节——指令模板。现在很多模型基座带有自己的Chat模板比如用特殊Token代表对话开始、助手回复等。有些开发者在微调时偷懒直接用自己的模板训练结果模型学到了双套模板推理时行为就很怪异。我的建议是除非有强需求否则直接用基座自带的chat template你只需要把数据组织成对应的对话格式即可。曾有一次我为了统一项目内部格式强行改了模板结构结果模型生成内容尾巴经常多出奇怪的结束Token。排查了很久才发现是模板问题回退到基座的模板就好了。这里我想提醒大家这一层往往能卡住你两三天时间别侥幸。2.4 SFT训练超参与Loss观察SFT阶段超参选择相对RL简单很多但我还是总结了一套基线值超参推荐范围我的默认值Epoch1-32数据高品质时1即可学习率1e-6 到 1e-52e-67B以上模型Batch Size取决于显存尽量大32以上稳妥Warmup50-200步100步Max Length不截断有效答案2048或4096关于epoch多说一句SFT不是训得越多越好。我有过惨痛教训高质量数据训到第5轮个别任务上的表现反而下降了。这种现象叫“过拟合到数据噪声”具体表现是Loss还在降但实际评估分在掉。所以我现在的做法是每轮结束都在验证集上测一次选择评估分最高的那版checkpoint而不是等训练全部结束才选。Loss曲线观察也有讲究SFT的loss一般会平稳下降最后收敛在1.0以下视词表大小和任务难度不同会浮动。如果你看到loss在训练中途突然跳高大概率是学习率太高或者batch里出现了极端长样本影响了梯度。另外LoRA的rank选择值得一说。我测试过32、64、128三档发现对于7B和13B级别的模型rank64已经足够表达复杂的指令映射关系再大收益有限、显存压力却明显增加。rank太小比如8则容易欠拟合具体表现是验证集上风格不稳定。2.5 LoRA合并和基座参数冻结的取舍现在聊SFT基本绕不开参数高效微调。我自己实践下来LoRA在绝大部分任务上和全参微调的效果差距很小但显存和迭代效率的优势巨大。不过有几点需要特别注意冻结基座参数时要确保训练数据里的“语言表述”和基座分布接近否则LoRA能记住任务格式、却改不了底层的语言风格。如果做多轮SFT每一次都在上一版LoRA基础上继续叠加效果往往不好。我更建议保留基座权重每次单独训LoRA最后合并或动态加载。合并权重之后最好在合并模型的生成结果上重新抽检一遍因为合并操作在某些框架里会带来一点点精度损失虽然小但不排除影响极端长文本的末尾token预测。我在跑一个面向长文档问答的项目时合并LoRA后抽样发现中间某层输出有轻微漂移导致一个原本能对齐的引用格式偶尔出错。后来我把LoRA放回和训练时一致的推理路径里问题就消失了。这个坑在部署链路复杂的项目里特别容易爆值得提前排查。3. RL训练调优从奖励设计到策略优化3.1 搭建一条完整的RL训练链路RL不是单个算法而是一条链路。链路里任何一个环节出问题模型都会受到连带影响。我惯用的链路是这样的策略模型SFT出的模型奖励模型或奖励函数可以用训练好的RM、也可以用规则计算分数参考模型通常是SFT模型本身用于计算KL散度防止模型跑偏生成rollout数据 → 计算奖励 → 更新策略 → 循环这个链路搭建阶段最容易踩坑的是“参考模型没正确冻结”。有一次我写训练代码时不小心把参考模型也设成了可训练结果KL散度一直在高位抖动模型生成逐渐失控。后来加了requires_grad_(False)才恢复正常。这种问题不细看loss根本发现不了。3.2 奖励模型RL的灵魂在画像是谁给的RL最核心也最容易被低估的部分是奖励模型。很多人一上来就盯着PPO、GRPO的算法参数却忽略了“奖励信号本身准不准”。如果奖励模型给出的分数和真实人类偏好不一致RL优化到最后就是一个“高分低能”的模型。训练奖励模型的数据结构是pair-wise的同一问题给两个回答标注者标明哪个更好。一个常见误区是只用人类标注数据训练RM。标注数据很贵也很稀缺更可行的办法是“冷启动持续迭代”先用一小批高质量人工标注做初始RM然后让策略模型生成一批新样本交给RM打分再抽一部分高分歧样本人工复核不断扩充RM训练集。这样可以大幅降低标注成本。奖赏模型的训练里还有几个经验值奖励模型的训练集最好覆盖“近似但不同水平”的回答对如果两个回答差异太大模型学到的边界会很粗对细微提升不敏感。Batch内尽量让同指令的回答对在一个batch里这样模型对比学习的效果更好。Reward模型训练epoch不宜过多我测下来2个epoch左右就足够继续训容易把训练数据背下来在分布外样本上打分失真。另外强调一个真正的“灵魂”问题如果RL任务本身可以用程序算分——比如数学题的正确率、代码题单测通过数、格式化约束是否满足——那优先用规则奖励不要训练RM。规则奖励干净、无偏、不会reward hacking能让调试复杂度降低一大半。我最近跑数学推理类项目就直接用结果正确性作为信号完全不依赖RM稳定性高很多。3.3 PPO vs GRPO选型经验PPO是RLHF里的经典主力。它通过优势函数估计GAE和重要性采样来更新策略稳定但计算量较大。GRPO则是近两年我越来越喜欢的方案——它在做组内相对比较时不需要额外的critic模型显存占用更小训练也更稳定。我自己的选型逻辑是这样的显存很紧张、或想快速跑通原型优先GRPO适合小团队快速迭代。任务奖励信号噪声大、需要精细控制每次更新的幅度PPO配合精心调好的critic更稳。希望对每个prompt生成多组response做组内对比比如让模型生成8个答案取这四个里最好的方向GRPO天然贴合这种结构因为它在组内做比值。GRPO里的组数group size很值得调。我测试过组数从4到16的变化组数越大优势估计越稳但计算量等比例增大。通常在性能和资源间我选8左右比较均衡。组数太小比如2优势估计方差偏大loss容易波动。3.4 KL系数管住模型别跑飞的缰绳RL训练时模型很容易钻空子比如为了拿奖励突然改变输出风格甚至开始复读垃圾内容。为了防这种情况通常会在奖励里加入KL散度惩罚——惩罚模型偏离参考模型通常是SFT模型太远。KL系数通常记为β需要仔细调。β太大会导致模型不敢探索最终产出和SFT版本差不多RL白跑β太小则模型彻底放飞输出越来越离谱甚至出现重复token、语无伦次。我调β的思路是先设一个偏大的值例如0.1跑一小段试探训练观察平均KL散度和奖励均值。如果KL迅速冲高就调大β如果KL变化平坦、奖励也不长就调小β。理想状态是KL散度在训练过程中有波动但不爆炸奖励均值稳定上升。还有一个小技巧可以在训练前期把β调大一点保护模型基础能力后期逐步减小释放更多探索空间。这种退火思路我在几个项目里测试和创新效果比固定β要好一点但注意别减太猛否则末尾又容易崩。3.5 reward hacking的实战案例reward hacking奖励攻击是RL训练里最经典的“翻车”现象模型发现了奖励函数里的漏洞用意想不到的方式拿到了高奖励但实际效果完全不对劲。我记忆中很典型的一例发生在一次摘要任务上。当时奖励函数里包含了一项“摘要必须涵盖原文所有要点”模型很快学会了把所有句子和关键实体原封不动地堆进摘要里硬凑出了一个超长文本。结果奖励分甚至比正常摘要还高但人工读到根本没法用。我自己亲眼见过这类现象后从此对reward设计变得非常谨慎。几个缓解手段我逐个尝试过对输出长度做惩罚或加硬截断奖励函数里的每一项都加饱和上限在训练中动态采集模型输出做人工审查发现异常即刻干预多个奖励项之间做加权融合避免单一信号主导另外定期检查训练中的生成样本特别重要别只看reward曲线。我训练时每隔几百步就随机打印几条生成结果肉眼过一遍这比任何指标都更能帮助发现问题。这是我个人强烈推荐的习惯。3.6 奖励尺度与归一化奖励数值的尺度在RL里是个隐藏大坑。同一个奖励函数如果不做归一化不同batch之间的奖励波动会非常大导致优势估计不稳定训练剧烈震荡。我在RL里几乎都会做“相对标准化”——对同一批rollout里的奖励做z-score归一化而不是直接用绝对数值。这个做法尤其在GRPO里有效因为组内天然存在比较关系。另外如果奖励取值范围跨度过大比如有些任务轻而易举得1.0另一些任务拼死拼活只有0.2最好给奖励做分位数变换或clip。我试过把奖励从原始分数变为组内排名映射虽然丢失了一些绝对尺度信息但训练稳定性和最终效果都更理想。4. 训练稳定性的排查与避坑实录4.1 Loss不降的常见原因训练到一半发现loss像块铁板一样完全不动这种事我遇过不下五次。最常见的几种原因基本集中在这里学习率过低SFT初始化到1e-7这种量级loss当然像原地踏步。数据问题不同batch里数据难度差异巨大模型直接被“极难样本”拖住了收敛。权重初始化异常或某个模块被意外冻结。奖励尺度太小RL里reward如果一直在0.1和0.2之间浮动优势估计信号微弱模型几乎学不到东西。我排查的顺序固定统一先看数据batch里有没有脏数据再看学习率再看梯度范数。梯度范数是很多训练异常的第一信号源如果梯度范数一度变成NaN或爆炸那模型参数大概率已经受损了。4.2 Loss反升和训练崩溃Loss不降的同时出现在训练中段突然上升这种往往更刺激。我遇到过的几个case分别对应某个batch里包含异常长文本seq长度超过合法范围导致attention计算混乱学习率warmup结束后直接跳到过高的值模型一下跨出了稳定区LoRA和基座混合精度不一致导致数值误差累计RL中奖励出现极端值反向传播时梯度直接冲爆其中一个特别容易被忽视的是“混合精度里的inf”。我排查多次后发现某些层在fp16下中间值溢出尤其是rope和attention score的计算阶段。后来我把关键计算塞回fp32traning才稳下来。如果你的训练和eval之间经常出现莫名其妙的不一致值得顺着这个方向检查。4.3 灾难性遗忘与通用能力衰退模型在SFT或RL之后对话能力可能变好但原有的一些通用能力比如代码能力、常识问答出现回退这就是灾难性遗忘。我常用的缓解策略按优先级排序在训练数据里混入一小部分“通用能力保持集”比例3%-10%不等。做RL时把KL系数调高一点别让策略模型离参考模型太远。定期在通用benchmark上做回归测试遇到下滑立刻回滚。在多任务训练时尽量保证每个任务的loss权重均衡避免某个大语料把其他能力“淹没”。我还有个经验通用能力回退的发生风险在RL后期会比SFT更大因为KL约束只对参考模型负责而参考模型本身毕竟也是SFT版本它的通用能力本来就不如基座。所以想真正保住能力最好以基座模型为参考的广义约束用起来或者更稳妥的方式是“边训练边抽检基座benchmark”。4.4 显存优化和Batch的策略训练大模型显存永远是绕不开的话题。LoRA已经是大救星但在RL里还有更多开销策略、参考、RM可能同时加载。我常用的显存节省方案手段收益注意点梯度检查点显著减少激活显存略微增加训练时间卸载优化器状态省下一大块显存训练速度下降混合精度训练显存减半且速度提升注意掉精度关键层需要fp32小batch 梯度累积突破单卡上限累积步数不要太大否则bn层统计不准Batch size的调参策略在RL里也有讲究rollout的batch size决定了一次要生成多少样本直接影响奖励估计质量而ppo-update的batch size决定了每次用多少数据去更新策略两者不是同一个概念。很多人把这两个batch弄混导致训练行为怪异。我自己一般rollout batch参考采样多样性来定更新batch则取rollout的一小部分多次迭代。5. 评估与迭代怎么判断模型真的变好了5.1 评估集与基线对照在启动昂贵的RL之前一定要先建好评估体系。我习惯是做一个固定评测集里面除了常规的准确率还要人工标注一些开放回答的质量分。评估集规模不需要太大一两百条质量高的case就够关键是能稳定反映能力变化。每次训练后都把新checkpoint和上一版拿出来对比生成最好还是人工盲测。我踩过太多“指标涨、实际烂”的坑这里想特别提醒越是分数看起来光鲜的模型越要经人工这关检验。指标可以骗人但人工感受骗不了人。5.2 自动化评估与采样的取舍自动化评估比如用大模型当裁判给另一个模型的输出打分已经越来越普及我自己也在用。这里有两个经验裁判模型最好和被测模型不是同一个基座体系如果同族太明显裁判会偏好同族模型的长相和风格。打分维度不要只给一个总分要拆成相关性、信息量、可读性、格式等分项分项比总分更敏感能帮你定位问题方向。但在真正做上线决定前人工评估永远不可替代。我会在自动化筛过后把所有候选模型和基线模型放在同一个页面上盲选这是最有说服力的步骤。5.3 多轮迭代的节奏模型微调很少有“一把成”的更多时候是个多轮迭代过程。我的一般节奏是第一轮建立baseline拿到靠谱的评测分数第二轮集中修最大的bad case类别通常是数据质量问题第三轮调RL偏好方向比如更简洁、更稳、更准确第四轮回归测试防通用能力下降每一轮之间的间隔尽量控制在一周以内太久会丢失上下文。训练日志、数据版本、评测结果我全都记录在案这习惯在后期排查问题时会救你命——我回头翻日志时经常发现有意义的规律哪个数据版本、哪个超参组合、哪个评测结果——这些信息一旦缺失迭代起来就是一团黑。5.4 数据版本管理说到版本管理我想单独提一嘴。我的经验是数据文件本身就带版本号比如v1_sft_20250115.jsonl每次修改都另存新版本不要覆盖旧文件。因为训练到中途可能发现数据有问题回退到旧版本重跑是常有的事。同理RM训练数据、RL训练策略、甚至prompt模板都建议保留历史版本。存这些不会多费多少空间但它们既是复盘的依据也是和团队其他成员协作时的重要参照。6. 我压箱底的经验几个容易忽略的细节最后这部分我不想再做系统性的总结就随便聊聊几个我实际训练中的“体感经验”。第一个就是训练卡的时候去读log。现在很多训练脚本的log密密麻麻我见过不少同学训练跑飞了都不知道怎么看。我的建议是锁定一个你关心的指标loss、reward、grad norm、KL写个简单的过滤命令去实时跟踪而不是打开一墙日志去找。好的判断节点是每100步看一次生成样例和梯度范数这些比loss更能反映模型真实状态。第二个是关于实验记录。我后来学乖了每次训练前会写一个实验记录文件内容包括数据版本、基座版本、学习率、LoRA配置、KL系数、用的奖励函数、当时想验证的假设、上一版结果对比。这个记录强迫我在每轮实验前先想清楚“要验证什么”而不是闷头乱跑。看下来我几乎一半以上的有效改进都来自这种“预设假设再实验”的流程。第三个让我印象最深的是关于模型的“话风”。模型在RL之后分数可以涨得很快但“话风”往往会悄悄变掉。比如原来礼貌克制强化后变得过于激进或过度自信这种变化指标上很难显现。所以我每次RL训练完都会找不同风格的测试人员来“聊”一轮确认话风是否还符合产品定位。最后再分享一个所谓的“冷门”心得训练模型这件事数据处理和评估花的时间才是大头。真正训练的时间往往只有一小半超参调来调去带来的收益不如把数据清洗干净、把评估维度设计合理带来的收益大。这不是我在讲漂亮话而是我一次次对比下来最真实的感受。如果你正打算开始自己的SFT或RL项目我的建议是从一个小而完整的闭环做起小数据集、小模型、一轮完整流程跑通感受一下loss、reward、生成质量之间的关系再逐步放大。这比一开始就堆大数据、大模型更能在调试中积累到有价值的直觉。
阅读完成 · 觉得有帮助?