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
Setalgorithm.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: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:build_train_config() from the CLI module and merge your overrides on top:
Tier 2: Python API hooks
These require usingAgentTrainer 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:
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: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 yourWorkflow.__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: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

