Skip to main content
This guide documents every customization surface available to users who install rLLM as a package (pip install rllm) and want to control training behavior from their own project, without forking the codebase.

Customization layers

rLLM offers three tiers of customization, from least to most effort:

Tier 1: Config-level customization

The simplest path. Pass a YAML file via --config on the CLI, or set keys programmatically with OmegaConf before passing to AgentTrainer.

Selecting an advantage estimator

Set algorithm.adv_estimator in your config to one of the built-in estimators:
my_config.yaml
From the CLI:

Advantage normalization

GRPO normalizes advantages by group standard deviation by default. Disable this if your reward distribution is already well-scaled:

Using precomputed advantages

If your workflow computes per-step advantages internally (e.g., for distillation or supervised fine-tuning), skip the advantage estimator entirely:
When enabled, the trainer reads step.advantage from each step in your trajectories and uses those values directly. Steps with missing advantages default to 0.

Loss function (tinker backend)

The tinker backend supports multiple loss functions. Set via config:

Rejection sampling

Control whether low-quality batches are discarded or accumulated:

Compact filtering

Mask out trajectories that hit error conditions, so they don’t contribute to the gradient:

Programmatic config

From Python, build the config the same way the CLI does:
Or use build_train_config() from the CLI module and merge your overrides on top:

Tier 2: Python API hooks

These require using AgentTrainer or UnifiedTrainer directly from Python, not the CLI.

Custom trajectory grouping

By default, trajectories are grouped by {task_id}:{trajectory_name} — all rollouts for the same task and trajectory role end up in one group, and advantages are computed within that group. Override this with traj_grouping_hook to control how trajectories are grouped:
Pass it to the trainer:
Your hook must return TrajectoryGroup objects with valid group_id and trajectories fields. Each trajectory must have a non-None reward when using broadcast mode (the default). The trainer validates rewards after your hook runs.

Per-group advantage estimator map

In multi-agent workflows (e.g., solver-judge), different trajectory groups play different roles. You may want a different advantage estimator for each role:
The map keys are group roles, derived from the group_id of each TrajectoryGroup. The default grouping produces IDs like {task_id}:{trajectory_name}, and the role is the trajectory_name portion.

Workflow arguments

Pass arbitrary arguments to your Workflow.__init__() via workflow_args:

Tier 3: Registering custom advantage estimators

The advantage estimator registry (RLLM_ADV_ESTIMATOR_REGISTRY) uses a decorator pattern. You can register your own estimator at import time, and then reference it by name in your config.

Defining a custom estimator

Using it

After importing the module that contains your registration, set the estimator name in config:

Estimator function signature

Your function must accept and return these types:
Each element in rewards is a 1-D array of trajectory rewards for one group. Return advantages and returns in the same list-of-arrays structure. **kwargs carries traj_groups: list[TrajectoryGroup], aligned with rewards, so estimators that need per-trajectory metadata (response lengths, step counts) can read it via kwargs.get("traj_groups"). See Advantage estimator for a worked example.

What you cannot customize today

The following aspects of the training loop are fixed and require source modifications to change:

Summary: customization decision tree

Next steps

Unified trainer

Architecture of the 8-stage training pipeline

RL algorithms

Mathematical details of GRPO, REINFORCE, and RLOO

Multi-agent training

Solver-judge and other multi-trajectory workflows

Training backends

Compare verl and tinker backends