经验分享!这半年来,用 RL 做 LLM 后训练时踩过的那些坑与心得

  • 发布于 2025-12-25
  • 7 次阅读

作者:天晴

https://zhuanlan.zhihu.com/p/1986921621240447760

用 RL 做后训练 LLM 时,探索效率和训练稳定性是两个最核心的问题。这半年,我积累了不少心得感悟,也踩了很多坑。由于打算金盆洗手不再做这方面的工作了,索性把这些经验分享给大家。

当然,这些经验不一定都正确,存在我个人认知的局限。

探索效率

先说探索效率这块。普通研究者会觉得 RL 太重了,需要预先加载一堆模型:当前模型算 logprob,reference model 算 reference logprob,还要记录 old logprob,PPO 还需要 critic model,额外可能还有 reward model。

四份模型加一份 logprob 记录,光看着就头大。训练效率就更不用说了,涉及的模型越多,瓶颈点和 pipeline 气泡就越大

一个典型的问题是 rollout 和训练之间的同步间隔。如果 Sync=1,就是探索一个 step 采样数据,再用这批数据训练一个 step,这种情况下机器利用率能有 50% 就不错了。

那如果提升同步频率呢?也就是允许数据是 off-policy 的,探索多步再训练,这样就可能造成训练不稳定。GRPO 的重要性采样就是为此而生的,但它并不能保证训练不崩溃。

Agent 环境的探索延迟也是个大问题。拿 Webshop 来说,32 个 runner 同时创建 32 个环境探索,大约需要 1.7T 内存,Retrieve 步骤还需要很多 CPU,延迟也很高。

数学任务和 Alfworld 这种还好做一些。Mobile Agent、GUI Agent 的探索成本就高得离谱了,不是我能玩得转的。

自然而然会想到,做 Mobile Agent 时不要用真实手机采样,而是 Mock 一个环境,界面和手机相同,截图就行。这样可以开多个 Runner 而采样成本低。缺点是仿真环境不够真,而且难以更新和覆盖 Corner Case。

但 Corner Case 的覆盖恰恰是 RL 最大的魅力,相较于 SFT,RL 只需要准备好环境和 Questions,剩下的就无脑交给 GRPO 和 LLM 梭哈,它可以自动处理 OOD 和 Corner Cases。

另一个角度说,RL肯定是希望正样本越多越好,多样性越高越好。这里有个坑要注意:以前数据合成的思路不一定能直接搬到 RL 里用

比如通过环境反馈加自然语言反思来合成数据,反思得到的轨迹的 logprob 是在有额外上下文的情况下获得的,和直接用 Question 推理的 logprob 是不一致的,所以重要性采样理论上不能直接用。

这里可以采取的一个技巧叫上下文蒸馏。当然实践中不用重要性采样有时候也能 work。总之通过各种数据合成策略提升正样本数量,总体上是有益的。

训练稳定性

再说训练稳定性。很多人会发现 RL 不像预训练和 SFT 那样可以 scaling,可能训几千步就崩了,熵、KL、reward、PPO loss、输出长度这些指标突然不正常,即使手里有再多数据和机器也没用。

DeepSeek 3.2 还是 Qwen3 来着,他们技术报告里说训推理能力的 RL 阶段只依赖 4k 条数据,多个 Epoch 训练。这么少的数据就能训出推理能力,一方面感慨 RL 对数据利用够充分,另一方面也说明 RL 的 Scaling 确实难

另一个稳定性问题是训 GRPO 时的崩溃。这里细节和坑特别多,我总结一些自己遇到过的。

首先是基建层面。大家探索用 vLLM 或 SGLang,但由于推理浮点精度和某些 Bug,它们预测的序列 logprob 和 Huggingface 推理出的不完全等价(应该有 Issue 在讨论和解决这个)。

最典型的现象是,Sync=1 时所有数据理论上都是最新的,但实际上很多会被重要性采样 clip 掉,而且随着训练时间增加 clip 比例还会增加。一个潜在思路是不完全相信 vLLM 的 logprob,用 HF 重算一遍 Prefill 阶段,用这里获得的Logprob。

loss的选择方面,Seq-level loss 还是 Token-level loss,两个典型工作是 GSPO 和 DAPO。我实测下来,GSPO 对 Dense 模型收敛偏慢但更稳定,而且 GSPO 对 MOE 有优化,所以 MOE 模型无脑用 GSPO。

其他情况下 GRPO、DAPO、Reinforce++ 差别不大。DAPO 因为对长序列有限制,在多轮对话非数学场景下可能训不起来。

输出 Token 长度设置不当也会导致崩溃。比如任务只需要每轮输出 200 token,你却设了 8192,就比较危险。

因为 RL 中如果 rollout 出超长的崩溃循环输出,这部分轨迹会在 Token-level Loss 中影响很大。能设小就设小;如果非要很大的输出长度,就要非常小心超长轨迹和离群值,该过滤就过滤。

对于小 LLM 做多轮 Agent RL,因为能力有限很容易丢失焦点。最好在每轮对话时把原始 Target 和前几轮 Action 都在 Prompt 里重复告诉模型。

关于 Sync 值,其实 Sync 越大不一定越坏,我见过 Sync=10 比 Sync=1 效果更好的场景。但全异步训练还是要谨慎,最好配合 Priority Buffer,把比较新的数据放在靠前位置来保证稳定性。

如果模型对某类任务成功率不高,不能直接用 GRPO,要想办法提高正样本在 loss 中的比例,无论是 Token 级别过滤、Sample 级别过滤,还是提升正样本的 Advantage 权重都可以试。否则负样本占主导容易崩溃。

这是因为传统 RL 的动作空间小,抑制错误 Action 后概率会自然偏移到正确 Action 上;但 LLM RL 的动作空间是词表大小乘以序列长度,抑制了某个序列输出的概率,这些概率被分配到哪里是未知且混沌的,所以必须强调正样本的作用

关于 PPO,如果有 Verifiable Reward 就最好不用 PPO。一般主观题才用 PPO,客观题用 GRPO。因为 Critic Model 预测其实不准,尤其是有争议或数据有冲突的时候。

基座模型选择

做 Paper 最好选 Qwen2.5 或 Mistral 的 Instruct 或 Base 模型,用 SFT 做冷启动再上 RL。Qwen 的 <think> 标签在词表里不是一个独立的Token,模型不一定能稳定按这个格式输出,其实完全没必要非用 <think>,可以用词表更亲和的 Token来代表Think Tag。

不要用 Llama 系列。它在基座训练时 COT 能力不够强,用 RL 训出来结论会很奇怪。Qwen 系列在 Post-Training 早就训得很像 Thinking 模型了,更容易训出来。

Thinking 模型的后训练

Thinking/Reasoning 模型的后训练需要单独说,里面隐式的坑更多。相较于 Instruct 模型到 Thinking 模型的路径,直接对 Thinking 模型做 RL 是更难的。

因为它们的多轮对话并非通用多轮对话,而是拼接多轮对话,也就是多组修改上下文的单轮对话。

拿 Qwen3 举例,它在 Turn 2 的时候会把 Turn 1 的 thinking 部分删掉,目的是降低上下文长度。这样一来标准的多轮 GRPO 就没法用了。标准 GRPO 是对一个很长的多轮对话轨迹 Mask 掉 Input 部分,然后梯度从尾向头传递。

但 Qwen3 因为修改了 Turn 2中Turn 1部分的上下文,训练就变成 Turn 1 训一下、Turn 2 在不同上下文训一下,以此类推。所以所有面向 GRPO 做的 paper 和工作,在这种范式下要重新思考。强行按通用多轮去训 Qwen3,是有可能水土不服的

多次 tool call 的场景就更复杂了。比如 Kimi 模型,Turn 1 里有三次工具调用,每次调用前的 Thinking 会被保留,但到 Turn 2 时,Turn 1 每个工具调用前的 Thinking 会被删除。现代模型的 Template 真是越来越复杂了

如果我们预先不知道 Thinking 模型是用什么 RL 算法和上下文修改规则训的,直接做后训练风险很高

另一个被忽视的问题是 Thinking 模型的 Temperature。主流开源模型都会说要在指定温度、TopP 下运行,那训练时有必要遵循吗?我推荐训练时按温度 1 或官方推荐温度采样,推理评估按官方的来。

希望这些经验能帮到在这条路上探索的朋友。