Chapter 13

源码导读:Trainer / Strategy / Engine 三层抽象

📌 commit 6c6056daa522 10 个文件读懂整套架构

本章给你一张"哪个文件做什么"的源码地图,把 OpenRLHF 的整套架构剥开。 目标是让你在给 OpenRLHF 提 PR 时知道改哪里

13.1顶层目录地图

OpenRLHF/
├── openrlhf/                       ★ 主代码
│   ├── cli/                        命令行入口(5 个)
│   │   ├── train_sft.py            SFT 训练
│   │   ├── train_rm.py             Reward Model 训练
│   │   ├── train_dpo.py            DPO / IPO / SimPO 等
│   │   ├── train_ppo_ray.py        ★ PPO / GRPO / RLOO 等 RL 训练
│   │   ├── serve_rm.py             把 RM 起成 HTTP service
│   │   └── lora_combiner.py        merge LoRA 权重
│   ├── trainer/                    训练逻辑
│   │   ├── sft_trainer.py          SFT loop
│   │   ├── rm_trainer.py           RM loop
│   │   ├── dpo_trainer.py          DPO loop
│   │   ├── ppo_trainer.py          ★ PPO loop(单进程版,被 RayActor 调用)
│   │   ├── ppo_trainer_async.py    异步版本(multi-turn agent 用)
│   │   ├── ppo_utils/              experience / KL / replay buffer 等
│   │   └── ray/                    ★ Ray actor 封装
│   │       ├── launcher.py         RayActorGroup / BaseDistributedActor
│   │       ├── ppo_actor.py        actor 端 Ray actor 实现
│   │       ├── ppo_critic.py       critic 端 Ray actor 实现
│   │       ├── vllm_engine.py      ★ vLLM rollout 的 Ray actor
│   │       └── vllm_worker_wrap.py vLLM worker 内部 patch
│   ├── models/                      模型实现
│   │   ├── actor.py                Actor 类(包 HF 模型)
│   │   ├── model.py                get_llm_for_sequence_regression(RM / Critic 用)
│   │   ├── loss.py                  ★ PolicyLoss / ValueLoss / DPOLoss
│   │   ├── ring_attn_utils.py       Ring Attention 实现
│   │   └── utils.py
│   ├── datasets/                    数据加载
│   │   ├── prompts_dataset.py       PPO 用的 prompt dataset
│   │   ├── reward_dataset.py        RM 训练用的 preference dataset
│   │   ├── sft_dataset.py           SFT 用
│   │   └── utils.py
│   └── utils/                       工具
│       ├── deepspeed/               DeepspeedStrategy + offload
│       ├── distributed_util.py      stateless NCCL group
│       ├── logging_utils.py
│       └── ...
├── examples/
│   ├── scripts/                     20+ 个生产级启动脚本
│   └── python/                      自定义 reward / agent 范例
├── tests/                            单元测试
├── docs/
├── dockerfile
├── requirements.txt
├── pyproject.toml
└── setup.py

13.2五条主线代码

主线核心文件
入口 + 参数解析 cli/train_ppo_ray.py
Ray 编排 trainer/ray/launcher.py
主循环 trainer/ppo_utils/experience_maker.py
PPO 训练 step trainer/ray/ppo_actor.py + trainer/ppo_trainer.py
vLLM 集成 trainer/ray/vllm_engine.py

13.3从命令行到训练循环的调用栈

flowchart TB CLI["bash train_ppo_ray_hybrid_engine.sh"] CLI --> Py["python -m openrlhf.cli.train_ppo_ray <一长串 --args>"] Py --> Main["train_ppo_ray.py · train(args)"] Main --> Init["ray.init()
初始化 Ray 集群"] Main --> Groups["创建 4 个 RayActorGroup
(actor / ref / critic / reward)
+ 若干 vLLMEngine"] Groups --> EM["新建 RemoteExperienceMaker
(experience_maker.py)"] Main --> Loop["for episode / for step:"] Loop --> ME["experience = EM.make_experience(prompts)"] ME --> R1["actor → vllm 同步权重"] ME --> R2["vllm.generate() → responses"] ME --> R3["ref/reward/critic 并行 forward"] ME --> R4["KL / advantage 计算 (kl_controller.py)"] Loop --> Train["actor_group.training_step(experience)
critic_group.training_step(experience)"] Train --> PA["ppo_actor.py · DeepspeedPPOActor.training_step()"] PA --> PT["ppo_trainer.py · PolicyLoss + backward"]

13.4cli/train_ppo_ray.py:入口

这是所有 RL 训练命令的真正入口。它做几件事:

  1. 解析数百个 --xxx flag;
  2. 初始化 Ray;
  3. 按用户配置创建 RayActorGroup(一个 group 对应一个角色);
  4. 创建 vLLM engines;
  5. trainer.fit() 开始主循环。
# 简化版
def train(args):
    ray.init()

    # 按 args 起 4 个角色(按 colocate 配置决定是否合并 PG)
    actor_group  = RayActorGroup(args.actor.num_nodes, args.actor.num_gpus_per_node, PPOActor)
    ref_group    = RayActorGroup(args.ref.num_nodes, args.ref.num_gpus_per_node, ReferenceActor)
    critic_group = RayActorGroup(args.critic.num_nodes, args.critic.num_gpus_per_node, CriticActor)
    reward_group = RayActorGroup(args.reward.num_nodes, args.reward.num_gpus_per_node, RewardActor)

    # 起 vLLM
    vllm_engines = [LLMRayActor.remote(...) for _ in range(args.vllm.num_engines)]

    # 初始化模型(每个 group 各自加载)
    refs = []
    refs.extend(actor_group.async_init_model_from_pretrained(args))
    refs.extend(ref_group.async_init_model_from_pretrained(args))
    refs.extend(critic_group.async_init_model_from_pretrained(args))
    refs.extend(reward_group.async_init_model_from_pretrained(args))
    ray.get(refs)

    # 建 actor ↔ vllm 的 NCCL group
    setup_weight_sync(actor_group, vllm_engines)

    # 跑主循环
    experience_maker = RemoteExperienceMaker(actor_group, critic_group, reward_group, ref_group, ...)
    for episode in range(args.train.num_episodes):
        for step in range(args.train.steps_per_episode):
            experience = experience_maker.make_experience(prompts)
            actor_group.async_run_method("training_step", experience)
            critic_group.async_run_method("training_step", experience)
            if step % args.ckpt.save_steps == 0:
                save_checkpoint(...)

13.5trainer/ray/launcher.py:RayActorGroup 实现

角色
BaseDistributedActor 所有 Ray actor 的基类,把 PyTorch distributed 信息塞进环境变量
RayActorGroup N 个 actor 的包装,create placement group + 起 N 个 Ray actor

读这个文件能理解"角色 → placement_group → N 个 Ray actor"是怎么落地的。

13.6trainer/ray/ppo_actor.py:训练 actor 主逻辑

这是 OpenRLHF 中最重要的一个文件。每个 RayActorGroup 里的 actor 都是这个类的实例。它的关键方法:

方法做什么
init_model_from_pretrained() 加载 HF 模型 + DeepSpeed engine 初始化
training_step(experience) PPO 一步训练(forward + loss + backward + step)
forward(sequences) 算 log_prob(ref / actor 都用这个)
broadcast_to_vllm() 把当前权重 broadcast 到 vLLM
save_checkpoint() 分布式 save
offload_states() / reload_states() colocate 时的 sleep 接口

13.7trainer/ppo_utils/experience_maker.py:主循环

这里是"actor / ref / reward / critic 协同"真正发生的地方。RemoteExperienceMaker.make_experience() 大致:

def make_experience(self, prompts):
    # 1. actor 权重同步到 vllm
    self.actor_model_group.async_run_method("broadcast_to_vllm")

    # 2. vllm rollout
    sequences = []
    for engine in self.vllm_engines:
        result = engine.generate.remote(prompts)
        sequences.append(ray.get(result))
    sequences = concat(sequences)

    # 3. 并行调 ref / reward / critic
    ref_logp_ref = self.initial_model_group.async_run_method("forward", sequences)
    reward_ref   = self.reward_model_group.async_run_method("forward", sequences)
    value_ref    = self.critic_model_group.async_run_method("forward", sequences)
    actor_logp_ref = self.actor_model_group.async_run_method("forward", sequences)

    # 4. 等所有结果
    ref_logp, reward, value, actor_logp = ray.get([ref_logp_ref, reward_ref, value_ref, actor_logp_ref])

    # 5. 算 advantage + KL
    advantages, returns = compute_advantages(
        rewards, values, ref_logp, actor_logp,
        gamma=self.gamma, lam=self.lam,
        adv_estimator=self.adv_estimator,
    )

    return Experience(sequences, ref_logp, actor_logp, reward, value, advantages, returns)

13.8trainer/ray/vllm_engine.py:vLLM 集成

类 / 方法作用
LLMRayActor vLLM engine 的 Ray Actor 包装
LLMRayActor.generate() 调 vllm.LLM.generate
LLMRayActor.init_weight_update_group()建 actor ↔ vllm 的 NCCL group
LLMRayActor.update_weight() 接收 actor 广播过来的权重
LLMRayActor.sleep() / wake_up() sleep mode

vllm_worker_wrap.py 是注入到 vLLM 内部 worker 的 patch,让它能接收 NCCL broadcast 的权重。

13.9models/loss.py:所有 loss 函数

用途
PolicyLoss PPO clipped objective
ValueLoss critic value regression loss
DPOLoss DPO + IPO + SimPO 系
SwitchBalancingLossMoE 负载均衡(MoE 训练用)

新增算法(比如 GSPO / ORPO)从这里开始,加一个新的 loss class + 在 dispatch 处加 case。

13.10models/actor.py:模型抽象

OpenRLHF 的 Actor 类是 HuggingFace 模型的一层封装:

Reference 和 Actor 用同一个类,区别只是 reference 全程 requires_grad=False

13.11utils/deepspeed/:训练后端

文件角色
DeepspeedStrategy 统一的训练策略入口
deepspeed_utils.py offload / reload states 等工具
deepspeed_config.py 动态生成 ds_config(从 --ds.* flag)

13.12阅读路线总结

  1. 跑通 ch03 单机 demo:建立感觉;
  2. cli/train_ppo_ray.py:理解入口;
  3. trainer/ray/launcher.py:理解 RayActorGroup;
  4. trainer/ppo_utils/experience_maker.py · make_experience():理解主循环;
  5. trainer/ray/ppo_actor.py · training_step():理解训练实现;
  6. trainer/ray/vllm_engine.py:理解 vLLM 集成;
  7. models/loss.py:理解 PPO loss 实现;
  8. trainer/ppo_utils/kl_controller.py:理解自适应 KL;
  9. 动手提一个 PR(哪怕修文档)。

13.132025–2026 新增子模块速查

13.1 给的目录树偏简化。下面是基线 commit 上有但容易忽略的新增子模块:

文件 / 目录关键符号 (file:line)对应章节
openrlhf/trainer/ppo_trainer_async.py 异步 PPO 主循环(与 ppo_trainer.py 镜像但 generate / train 并行)ch08.5 / ch11.9
openrlhf/utils/agent.py AgentExecutorBase:31 / AgentInstanceBase / MultiTurnAgentExecutorch10.13
openrlhf/utils/vlm_utils.py VLM 图像加载、processor、像素张量ch10.14
openrlhf/utils/distributed_util.py stateless_init_process_group() 给 vLLM weight sync 用ch06.11
openrlhf/utils/seqlen_balancing.py 序列长度均衡(动态 batch 配套)ch11.11
openrlhf/utils/loss_utils.py get_loss_batch_info() 动态 batch 时 token 数统计ch11.11
openrlhf/models/ring_attn_utils.py patch_transformers_for_ring_flash_attn:9 + reset_ring_attn_position_ids:32ch07.13 / ch11.12

13.147 个 loss 类的完整对照

ch13.9 提了 4 个核心 loss。openrlhf/models/loss.py 实际共有 7 个 loss 类:

用途核心公式 / 特征
GPTLMLoss 预训练 / SFT 因果 LM CrossEntropyLoss(logits, labels),含 Ring Attention 兼容
SFTLoss SFT 微调(支持 packing) -per_token_logps,token / sequence 级聚合
PolicyLoss PPO actor loss min(ratio·adv, clamp(ratio)·adv),支持 PPO / GSPO / DualClip + vLLM IS 矫正
ValueLoss PPO critic loss 0.5·(values - returns)²,可选 value clip
PairWiseLoss Reward Model -logsigmoid(chosen - rejected - margin),Bradley-Terry
LogExpLoss RM 变种 log(1 + exp(rejected - chosen))(arXiv:2204.05862)
DPOLoss DPO / IPO beta · (pi_logratios - ref_logratios),label_smoothing + IPO 变体

13.15建议阅读升级版(7 天路线)

目标主要文件
D1跑通 ch03 最小 PPO demo train_ppo_ray_hybrid_engine.sh
D2读 controller 入口 cli/train_ppo_ray.py + 9 大 args group 拆解
D3读 Ray 抽象 trainer/ray/launcher.py:202 RayActorGroup + duplicate_actors
D4读主循环 trainer/ppo_utils/experience_maker.py:make_experience()
D5读训练 step trainer/ray/ppo_actor.py:training_step() + trainer/ppo_trainer.py
D6读 vLLM 集成 trainer/ray/vllm_engine.py + vllm_worker_wrap.py 注入
D7读算法 + agent models/loss.py + utils/agent.py + ring_attn_utils

13.16想给 OpenRLHF 提 PR?从这里入手

改动类型对应文件
新 advantage estimator trainer/ppo_utils/experience_maker.py 加 case
新 loss 函数 models/loss.py
新 reward 来源类型 trainer/ppo_utils/experience_maker.py + cli/train_ppo_ray.py
新模型架构 models/actor.py + models/model.py
新数据格式 datasets/prompts_dataset.py
新采样后端(SGLang / TRT-LLM) 仿照 trainer/ray/vllm_engine.py 写一个
新训练后端 utils/deepspeed/ 替换或并行加
新部署模式 trainer/ray/launcher.py placement group 策略
新 CLI flag cli/train_ppo_ray.py args 注册

13.14延伸阅读

资源用途
GitHub OpenRLHF/OpenRLHF 主仓库
openrlhf.readthedocs.io官方文档
DeepWikiAI 生成的代码 wiki
Tech Report系统论文
verl 那本书 对比另一种 RLHF 框架设计(HybridFlow)
TRL 那本书 对比单机风格 RLHF
DeepSpeed 那本书OpenRLHF 训练后端的本体
恭喜 到这里你已经读完了 OpenRLHF 中文 tutorial 的全部 13 章。 这本书在 commit 6c6056daa522 上是精确的,对应 OpenRLHF v0.10.3。 这套框架仍在快速演进,关注新增的 VLM RLHF / Multi-Turn Agent / REINFORCE++-baseline 等方向。