GRPO 与 RLVR 训练实战:基于 TRL 的可验证奖励强化学习配方、奖励门禁与变体选型(agents24 llm-finetuning 插件)
发布时间:2026/9/10 13:47:17 作者:尧图编辑部 阅读量:1,286
)
GRPO 与 RLVR 训练实战基于 TRL 的可验证奖励强化学习配方、奖励门禁与变体选型agents24 llm-finetuning 插件【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents导读本文围绕 agents24 仓库中plugins/llm-finetuning插件的grpo-rlvr-training技能系统讲解如何在目标任务具备算法可验证的通过/失败信号数学答案、代码执行、工具调用、结构化输出时用 GRPOGroup Relative Policy Optimization与 RLVRReinforcement Learning from Verifiable Rewards训练推理模型。你将掌握什么时候该用 RL 而不是 SFT 或 DPO、一份可直接落地的 TRLGRPOTrainer vLLM 参考配方、训练前强制执行的奖励函数人工检查门禁、五种可直接运行的奖励函数实现、失败模式驱动的 GRPO 变体选型DAPO / Dr.GRPO / GSPO以及不同参数量级下的显存规划与 DGX Spark 带宽约束。文章所有配置与代码均来自该仓库技能文档及其 references可复制、可运行、可继续深入源码验证。适用范围判定什么情况下 RL 才是对的工具grpo-rlvr-training技能在设计上承接finetuning-method-selection的决策路由。它只处理一类信号可验证的 pass/fail 信号——单元测试通过、解析器接受输出、工具调用匹配预期 schema、数学答案匹配 ground truth。如果你手里的是人类示范走lora-qlora-recipes或偏好对走preference-optimization则不该进入本技能。该技能的输入是路由决策RLVR via GRPO 一个验证器代码执行器、测试套件、schema 检查器或评分器输出不是自由形式的建议而是一份经过校验的 GRPO 配置kwarg 值来自 references/grpo-memory.md奖励函数来自 references/reward-functions.md由llm-finetuning-training-engineer直接消费。先决条件一评分必须算法可验证如果对输出打分需要人类主观判断或主观评分标准那首先是 eval-harness 与 judge 校准问题见eval-harness-first技能而不是跳过校准直接上 RL 的理由。GRPORLVR 只有在成功是否发生可以被机器判定时才值得投入。先决条件二模型必须已经偶尔能成功RL 只能锐化已有能力不能从零安装能力。打开一次 GRPO 运行之前必须确认目标模型在目标任务上有时已经能成功——RL 通过向已成功的样本重新加权来打磨策略。由此产生两条路由模型在低温度、大量采样下从未成功缺口在格式理解或任务理解而非策略精化。应回退到 SFTlora-qlora-recipes等基础成功率非零后再回到本技能。模型有时成功、但不稳定这正是 GRPO 的最佳适用区间sweet spot直接进入下面的参考配方。插件级通则DPO 管品味GRPO 管推理插件内有一条贯穿始终的准则DPO for taste, GRPO for reasoning。如果信号是两个可接受输出之间的偏好那是 preference-optimization 的领地而不是本技能。参考配方TRL GRPOTrainer vLLM 生成参考配方使用 TRL 的GRPOTrainer配合 vLLM 加速生成from trl import GRPOConfig, GRPOTrainer grpo_args GRPOConfig( output_dir./outputs-grpo, use_vllmTrue, vllm_modecolocate, # single GPU; server for multi-GPU num_generations8, # floor — fewer starves the group-relative baseline learning_rate5e-7, # settled range for GRPO beta0.01, # KL coefficient vs the reference policy per_device_train_batch_size8, gradient_accumulation_steps4, bf16True, logging_steps10, seed3407, ) trainer GRPOTrainer( modelSFT_CHECKPOINT, argsgrpo_args, reward_funcs[format_reward, correctness_reward], # references/reward-functions.md train_datasetprompts, # prompt-only — GRPO generates its own completions processing_classtokenizer, ) trainer.train()每个关键参数的含义与为什么参数取值语义与设计约束use_vllmTrue布尔用 vLLM 引擎做 rollout 采样生成速度远快于原生 HF 采样vllm_modecolocatecolocate/servercolocate将生成与训练放在同一 GPU单卡默认server指向独立 vLLM server 进程是多 GPU 路径生成与训练不争抢同一设备num_generations8≥ 8下限而非建议GRPO 的优势估计相对组均值计算每个 prompt 少于 8 个样本会产生噪声基线learning_rate5e-7浮点GRPO 已收敛的起始学习率区间只有基础运行稳定且通过奖励检查后才能偏离beta0.01浮点相对参考策略的 KL 惩罚系数控制策略偏离参考模型的程度per_device_train_batch_size8整数每设备训练批次gradient_accumulation_steps4整数梯度累积步数等效扩大批次bf16True布尔BF16 混合精度在训练工程师的 Failure Triage 中fp16 在无良好 BF16 支持的硬件上是已知的静默发散源logging_steps10/seed3407整数日志间隔与随机种子关键设计要点奖励是复合的格式奖励输出是否解析 / 匹配所需结构加上正确性奖励答案是否通过验证。格式正确但答案错误与格式畸形不应得同分——如果只用正确性奖励会丢失这一区分信号。数据集只含 promptGRPO 自己生成补全completions训练数据集不需要预生成答案对。内存按目标规模分档见 references/grpo-memory.md后文详述。与训练工程师执行链的衔接该配方由 llm-finetuning-training-engineer 在/finetune生命周期 Phase 4 消费生成train/config.yaml与train/train.py提交后才允许启动以{step: 340, loss: 0.812, lr: 1.8e-4, mem_gb: 71, temp_c: 68}形式输出结构化进度。发散时按顺序排查bf16 vs fp16 → 学习率与方法的匹配GRPO 与 SFT/DPO 的收敛学习率区间差异很大→ packing 损坏。这也解释了为什么本配方把bf16True与learning_rate5e-7写死为基准值。奖励检查门禁训练前必须人工阅读 50–100 个样本在启动正式训练前把奖励函数跑在 50–100 个采样输出上并逐条人工阅读结果。这是一道门禁gate不是一次性 sanity check。如果奖励函数的判断与人类对该样本的阅读不一致先修奖励函数再谈训练。对着一个未经检查的奖励训练或通过调超参去补偿一个正在静默打分错误的奖励函数——这正是 reward-hacking 的产生机制模型朝着错误目标干净地优化而这种问题不会以训练循环 bug 的形式浮现出来。从工作流视角看这道检查是/finetune命令的Phase 1 gate 输入llm-finetuning-architect在走决策树时会确认在 GRPO 路由上奖励函数的 Inspection Rule 已执行见 finetune.md 的 Phase 1 第 4 步。同一个 50–100 样本的人工阅读正是/finetune在允许 GRPO brief 继续之前检查的东西。可对照检查的完整奖励函数实现精确匹配、schema 校验、单元测试执行、长度惩罚包装器、rubric 判官模式见 references/reward-functions.md。奖励函数库五种可直接运行的实现references/reward-functions.md 提供符合当前 TRL 奖励函数签名的完整实现接收completions以及任意额外数据集列作为关键字参数返回与completions等长的list[float]。文中SFT_CHECKPOINT/JUDGE_MODEL是占位符实际 checkpoint 见finetuning-method-selection的 references/model-catalog.md。格式说明以下示例假定标准字符串补全格式completions: list[str]直接调用.strip()、json.loads()、.split()。若使用 TRL 的对话式数据集格式每个 completion 是[{role: assistant, content: ...}]需先提取completion[0][content]再做字符串操作。1. 格式奖励Format Reward检查结构合规性——补全是否遵循要求的响应形状——作为评判正确性的前置条件import re def format_reward(completions, **kwargs) - list[float]: 1.0 if the completion has a reasoning.../reasoning block followed by an answer.../answer block, else 0.0. This is a gate, not the correctness signal — a well-formed wrong answer still scores 0 on correctness_reward below. pattern re.compile( r^reasoning.*?/reasoning\s*answer.*?/answer$, re.DOTALL, ) return [1.0 if pattern.match(c.strip()) else 0.0 for c in completions]2. 正确性奖励——精确匹配Exact Match基线版可验证答案奖励适用于单一 ground-truth 字符串的任务数学最终答案、闭式查询def correctness_reward(completions, answer, **kwargs) - list[float]: answer is the ground-truth column from the training dataset, aligned index-for-index with completions. Extracts the answer block from format_rewards expected shape and compares. rewards [] for completion, gold in zip(completions, answer): match re.search(ranswer(.*?)/answer, completion, re.DOTALL) predicted match.group(1).strip() if match else None rewards.append(2.0 if predicted gold.strip() else 0.0) return rewards注意正确命中给 2.0 而非 1.0——与格式奖励叠加时格式正确但答案错误得 0格式门 1.0 × 0只有格式与答案都对才得满分从而保留了格式-正确性的区分度。3. 正确性奖励——Schema 校验用于结构化输出与工具调用任务此时正确意味着符合要求的 JSON Schema而非字符串相等import json from jsonschema import validate, ValidationError def schema_reward(completions, output_schema, **kwargs) - list[float]: output_schema is a JSON Schema dict, either a single constant schema for the whole batch or a per-example list the same length as completions. Rewards valid, schema-conformant JSON; 0.0 for anything that doesnt parse or doesnt validate. if isinstance(output_schema, dict): # Constant case: one schema dict for every completion — # zip()-ing a bare dict would iterate its keys instead, # not the schema itself, so normalize first. schemas [output_schema] * len(completions) else: schemas list(output_schema) if len(schemas) ! len(completions): raise ValueError( fschema_reward: {len(schemas)} schemas for f{len(completions)} completions ) rewards [] for completion, schema in zip(completions, schemas): try: parsed json.loads(completion) validate(instanceparsed, schemaschema) rewards.append(1.0) except (json.JSONDecodeError, ValidationError): rewards.append(0.0) return rewards实现细节值得注意当output_schema是单个 dict 时先归一化为等长列表因为直接对 dict 做zip()会迭代其键而非 schema 本身当传入列表但长度与 completions 不一致时显式抛ValueError避免静默错位。4. 正确性奖励——单元测试执行含安全边界用于代码生成任务正确意味着生成的函数通过留出测试套件。必须在子进程中以硬超时执行——绝不在进程内exec()不可信的补全。安全警告此函数执行模型生成的代码强制要求隔离环境无网络的容器、gVisor/firejail 或专用 CI 沙箱且环境中不得有任何 secrets 或凭据无 HF token、实验跟踪器密钥、云凭据、SSH 密钥。GRPO 在策略探索时会按设计把对抗性补全推过这条路径切勿在持有凭据的训练主机上直接运行。超时只保护训练循环的活性不是安全边界TemporaryDirectory只约束 harness 写文件的落点不约束被执行的代码能读什么、能触达什么。import logging import subprocess import tempfile from pathlib import Path logger logging.getLogger(__name__) def test_execution_reward( completions, test_code, sandbox_cmd, timeout_s10, **kwargs ) - list[float]: test_code is a per-example pytest snippet that imports the candidate under a fixed module name and asserts expected behavior. Runs each candidate in its own subprocess with a wall-clock timeout; an infinite loop or crash scores 0.0 instead of hanging the training loop. SECURITY: executes model-generated code. This function REQUIRES an isolation boundary — it does not run anything on the host by itself. sandbox_cmd (list[str], required) is a command prefix that wraps pytest in that boundary, e.g. a network-disabled, resource-capped Docker container: # sandbox_cmd [ # docker, run, --rm, --networknone, # --memory1g, --cpus1, # -v, f{workdir}:/work:ro, -w, /work, # python:3.12-slim, # ] If sandbox_cmd is falsy, this function refuses to execute anything and returns 0.0 for every completion — it never falls back to running pytest on the host. The subprocess environment is scrubbed to a minimal PATH (no HF tokens, experiment-tracker keys, cloud credentials, or SSH keys). The timeout is a liveness guard for the training loop, NOT a security boundary — isolation comes entirely from sandbox_cmd; the temporary directory only confines harness writes, not what executed code can read or reach. if not sandbox_cmd: logger.warning( test_execution_reward: no sandbox boundary provided — refusing to execute model-generated code ) return [0.0 for _ in completions] scrubbed_env {PATH: /usr/bin:/bin} rewards [] for completion, tests in zip(completions, test_code): with tempfile.TemporaryDirectory() as tmp: candidate_path Path(tmp) / candidate.py test_path Path(tmp) / test_candidate.py candidate_path.write_text(completion) test_path.write_text(tests) try: result subprocess.run( [*sandbox_cmd, python, -m, pytest, str(test_path), -q], cwdtmp, capture_outputTrue, timeouttimeout_s, envscrubbed_env, ) rewards.append(1.0 if result.returncode 0 else 0.0) except subprocess.TimeoutExpired: rewards.append(0.0) return rewards这段实现的安全姿态是三层防御sandbox_cmd缺省时拒绝执行并全员返回 0.0绝不回退到主机跑 pytest、子进程环境被清洗为最小 PATH、超时只保训练循环活性。这直接呼应训练工程师 agent 的失败分类——把执行路径上的资源/环境问题与训练配置问题分开处理。5. 长度惩罚包装器包装上述任一奖励函数在不替换底层正确性信号的前提下抑制补全长度失控——适用于纯正确性奖励开始向更长、填充式输出漂移的场景def with_length_penalty(reward_fn, target_len512, penalty_per_token0.001): Returns a new reward function that subtracts a small per-token penalty for every token past target_len, applied on top of reward_fns output. Penalty is capped so it cant drive an otherwise-correct reward negative — it discourages padding without overriding correctness. def wrapped(completions, **kwargs) - list[float]: base_rewards reward_fn(completions, **kwargs) adjusted [] for reward, completion in zip(base_rewards, completions): overflow max(0, len(completion.split()) - target_len) penalty min(reward, overflow * penalty_per_token) adjusted.append(reward - penalty) return adjusted return wrapped注意事项len(completion.split())用词数作为 token 数的廉价代理调target_len时应改用模型自己的 tokenizer 做真实 token 计数。更重要的是定位——这是针对已观测到的长度蠕变的定点修复不是 Dr.GRPO 的替代品如果长度偏置是系统性的而非偶发溢出应路由到技能变体选型中的 Dr.GRPO而不是堆叠惩罚包装器。6. 边界情况Rubric-as-Reward 判官模式针对正确性不可用代码检查、但 pass/fail 边界足够清晰可供判官一致应用的场景例如响应是否遵循了要求的格式并保持切题而非这是不是一篇好文章。二元 pass/fail不用 Likert 分def make_rubric_judge_reward(judge_client, rubric): judge_client calls JUDGE_MODEL — a model from a *different* model family than the model under training, never the model being trained or a same-family relative of it. rubric is a fixed pass/fail criterion string, not a free-form quality prompt, so both are bound here rather than read from TRL-supplied per-example kwargs. Returns a reward function matching TRLs actual signature. def rubric_judge_reward(completions, prompts, **kwargs) - list[float]: Returns 1.0/0.0 per completion, never an intermediate score. rewards [] for prompt, completion in zip(prompts, completions): verdict judge_client.judge( rubricrubric, promptprompt, responsecompletion, output_formatpass_fail, # binary only — no Likert scale ) rewards.append(1.0 if verdict pass else 0.0) return rewards return rubric_judge_reward两个硬性约束判官必须是与被训练模型不同模型家族的模型绝不能用被训练模型或其同族近亲judge_client与固定的rubric通过闭包绑定后再交给GRPOTrainer(reward_funcs[...])——因为 TRL 通过**kwargs只注入 completions 与数据集列不会注入判官客户端这类任意对象。校准是硬性前置条件不是锦上添花未校准的判官只是更吵、更贵的精确匹配奖励。接入 GRPO 前判官必须对照人类标签校准train/dev/sealed-test 划分、报告 TPR/TNR、判官固定到某个快照该工作流在eval-harness-first技能中不能因为 rubric看起来显然正确就跳过。变体选型失败模式驱动的 DAPO / Dr.GRPO / GSPO基础配方是默认。只有在特定失败模式出现时才使用变体不要预防性使用失败模式变体原因熵坍缩 / 退化的超长思维链DAPO解耦裁剪界限并放宽过度正则化长推理轨迹探索的 KL 惩罚奖励或输出长度与质量无关地持续上升Dr.GRPO移除 GRPO 的长度归一化偏置让奖励追踪正确性而非补全长度训练 mixture-of-expertsMoE模型GSPO把重要性采样比移到序列级而非逐 token——逐 token 比率在 MoE 路由上不稳定因此 GSPO 在这里是必需的而非可选正确的流程是先跑普通 GRPO观察具体症状——长思维链上的熵坍缩、长度-奖励相关性、或 MoE 不稳定——然后才换上对应的变体。不要在基础配方真正表现出失败模式之前就预先选型。VLM RL仅作参考v1 不执行视觉-语言模型的 RL 在插件 v1 中不被执行——在此记录仅为提供上下文不是可运行路径。原因有二工具链在 ms-swift 和 EasyR1 衍生 fork 之间碎片化尚无一行式的 TRL 命令且把朴素的纯文本 GRPO 直接套到 VLM 上模型容易通过优化文本推理轨迹而忽略图像来 reward-hack——听起来对但没看输入。VLM RL 运行是超出本技能支持配方的研究 spike而不是上述参考配方的一个变体。内存与硬件规划GRPO 在同等参数量下的内存足迹比 SFT 或 DPO 更重训练运行 共驻或服务端的 vLLM 生成引擎按num_generations采样每个 prompt 的补全叠加常规优化器状态与激活成本。完整的按规模分档、vLLM 睡眠模式与优化器状态策略、Unsloth 长上下文 RL 分块、以及 DGX Spark 解码密集型 rollout 的带宽告诫都在 references/grpo-memory.md。按规模类的显存锚点规模类可行性锚点小≤~3B24GB 级 GPU——需 vLLM sleep mode 8-bit AdamW 梯度检查点三管齐下~32B 级H200 级 GPU~70B 级B200 级 GPU24GB 级对小模型可行但必须三个杠杆同时启用缺一不可vLLM sleep mode在 rollout 阶段与训练步阶段之间释放生成引擎的 KV-cache 与权重内存而不是让两者同时驻留。8-bit AdamWoptimadamw_8bit削减优化器状态内存机制与 SFT/DPO 相同见 lora-qlora-recipes。梯度检查点以重计算换激活内存。H200 级是 ~32B 级模型的锚点策略模型、参考模型用于 KL 项与共驻 vLLM 生成引擎三者在该级以下无法同时放下。B200 级是 ~70B 级模型的锚点同样基于三方驻留原因只是规模更大。这些是起始锚点而非硬下限vllm_modeserver独立的生成进程可能在独立 GPU 上会改变驻留计算假设某规模类在特定机器上不可行之前应重新推导。Unsloth 长上下文 RL 分块Unsloth 的分块损失chunked-lossRL 路径可在相同显存预算下将可用 RL 上下文延长至未分块 GRPO 的约7 倍——该数量级来自 Unsloth 自己发布的基准本插件未重新测量精确预算规划前应核对当前 Unsloth 版本发布说明。这对 RL 特别重要因为 rollout尤其是长思维链补全正是 GRPO 在基础训练成本之上新增的显存压力点分块是不改变num_generations或 batch size就能买到余量的杠杆。DGX Spark带宽受限的 rolloutGRPO 的 rollout 阶段是解码密集型——每个 prompt 采样num_generations≥ 8 个补全且常带长思维链——而解码受内存带宽约束而非计算。在 DGX Spark 上共享内存带宽上限是 GRPO 特有、先于裸 VRAM 咬人的约束实测持续带宽远低于 273 GB/s 的规格值。这正是dgx-spark-ops插件spark-training-gotchas技能SKILL.md的 G5 陷阱规划 rollout 吞吐应依据该技能的带宽预算持续 180–192 GB/s而非宣传规格上限。实际结论在 Spark 上做 GRPO 优先选小模型。一个在单台 Spark 上能舒适跑 SFT 或 DPO 的规模类一旦 rollout 解码饱和共享带宽在 GRPO 下可能严重瓶颈——上面的显存锚点表回答能否装下本节回答能否快得值得跑。当 Spark rollout 吞吐成为绑定约束时降到更小的规模类通常比继续调 GRPO 超参更有效。与整个 llm-finetuning 生命周期的集成本技能不是孤立配方而是插件 eval-gated 微调生命周期中 GRPO 路线的实现层。/finetune命令finetune.md将流程划分为七个 artifact 门禁阶段Phase 0 构建 eval harness 与基线 → Phase 1 由 architect 做离场判定与选型GRPO 路由在此确认奖励函数 Inspection Rule 已执行→ Phase 2 数据集 → Phase 3 环境预检 →Phase 4 训练本技能配置在此落地为train/config.yaml与train/train.py提交后才启动→ Phase 5 checkpoint 门禁 → Phase 6 导出。相关技能边界也很清晰finetuning-method-selection在存在可验证 pass/fail 信号时路由到这里preference-optimization 是处理偏好对的姊妹技能eval-harness-first覆盖任何非纯代码可检查奖励的判官校准。在 DGX Spark 上本技能内存表未覆盖的记忆/热力修复阶梯应服从已安装的dgx-spark-ops插件的技能。参考资料主技能SKILL.md — 路由判据、参考配方、检查门禁、变体选型、VLM 边界奖励函数库references/reward-functions.md — 五种可直接运行的奖励函数精确匹配、schema 校验、单元测试执行、长度惩罚包装器、rubric 判官模式供 Inspection Rule 对照检查显存规划references/grpo-memory.md — 按规模类显存锚点、vLLM sleep mode、8-bit AdamW、Unsloth 分块、DGX Spark 带宽告诫消费方llm-finetuning-training-engineer — 负责将本配方生成配置、提交、启动、监控与失败分类编排入口finetune.md — 七阶段 artifact 门禁生命周期Phase 1 确认奖励函数检查已执行姊妹技能finetuning-method-selection、preference-optimization、eval-harness-first、lora-qlora-recipes【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考