SkipManager: Skip everything in the RL pipeline.
Last updated: 2026-05-23
1. Overview
SkipManager (verl.utils.skip.SkipManager) is a general-purpose framework for skipping
selected steps in verl training flows. By bypassing expensive stages on configured steps, it helps
save time, memory, or other resources and improves developer iteration speed during
debugging and experimentation.
Skip behavior is centralized under the top-level Hydra key skip. Modules register by role
(for example "rollout" or "async_rollout") and are attached with
@SkipManager.annotate(role=...). Each role declares which integer steps in config are
eligible for skip logic. Today only rollout-related roles are implemented; the same mechanism
can be extended to other pipeline stages (see section 5).
Typical use cases
SkipManager is intended for development workflows where repeating full training is costly:
Faster iteration: skip heavy stages on chosen steps (e.g. generation) while exercising the rest of the pipeline.
Deterministic replay: cache and reload intermediate results to reproduce a prior run on specific steps.
Resource savings: avoid recomputing or holding large tensors when bisecting bugs or tuning downstream logic.
The built-in rollout / async_rollout modules apply this to sequence generation; other
roles can follow the same pattern as they are added.
Supported entry points today
Training entry |
Skip role / config |
Status |
|---|---|---|
|
|
Supported |
|
|
Not supported (see section 3) |
|
|
Supported |
3. Rollout quick start (rollout role)
Use skip.rollout when training with main_ppo.py / RayPPOTrainer and the standard
AgentLoopManager.generate_sequences path. Configuration fields and cache / repeat
semantics are in section 2.
``main_ppo.py`` (supported)
RayPPOTrainer.fit()callsSkipManager.init(self.config)andSkipManager.set_step(self.global_steps)each training step.AgentLoopManager.generate_sequencesis decorated with@SkipManager.annotate(role="rollout").
``main_ppo_sync.py`` (not supported yet)
main_ppo_sync replaces the Agent Loop integration with AgentLoopManagerTQ. The main reason
rollout skip is not supported today is logic coupling in
AgentLoopManagerTQ.generate_sequences: it not only drives sequence generation, but also marks
samples in the ReplayBuffer and writes generated data into TransferQueue (TQ). Skipping
generate_sequences would therefore skip both generation and the TQ handoff, which breaks the
downstream training loop that consumes data from TQ.
Decoupling “generate” from “enqueue to TQ” is non-trivial under the current design, so SkipManager
adaptation for main_ppo_sync is deferred until the TransferQueue-based training path is
further stabilized.
4. Fully async quick start (async_rollout role)
In advance/fully_async, Trainer and Rollouter run in separate processes. Rollout generation
happens on the Rollouter via streaming single-sample dispatch. Use skip.async_rollout (not
skip.rollout) when launching fully_async_main. Shared Hydra fields and on-disk layout are
in section 2.
Important
In async_rollout, a step is not the trainer timeline. It is only the prompt request /
feed order on the Rollouter: the monotonic index in sample_{epoch}_{index} when
FullyAsyncRollouter enqueues the next prompt. Under concurrent rollout, completion order can
differ from feed order; do not treat these indices as trainer global_steps or parameter-sync
boundaries when configuring skip.async_rollout.steps.
Step key from sample_id
Each fed sample carries an id of the form sample_{epoch}_{index} (for example
sample_0_42). The integer matched against skip.async_rollout.steps and used for on-disk
directories is the last segment — Rollouter feed-order index at enqueue time.
Wiring
FullyAsyncRolloutercallsSkipManager.init(self.config)in the Rollouter process.FullyAsyncAgentLoopManager.generate_sequences_singleis decorated with@SkipManager.annotate(role="async_rollout")and receivessample_idfor online step resolution.
5. Design and implementation
SkipManager API
SkipManager (verl.utils.skip.skip_manager) is a class-level registry:
``init(config)``: Parse
config.skipintoSkipManagerConfig, instantiate one skip module per registered role, and store them inSkipManager.skip_instances.``set_step(step: int)``: Set
SkipManager.stepfor roles withsupport_online_step = False(trainerglobal_stepsinmain_ppo).``annotate(role, **kwargs)``: Decorator factory for sync or async functions.
Decorator flow
call decorated function
│
▼
skip disabled or role missing? ──yes──► run original function
│no
▼
resolve step (set_step vs extract_step)
│
▼
step ∉ config.steps? ──yes──► run original function
│no
▼
meet_precondition (cache/repeat)? ──yes──► warp_function (load cache)
│no
▼
run original function → prepare_data (dump)
BaseSkip interface
Each skip module subclasses BaseSkip (verl.utils.skip.base_skip) and registers via
@register_skip("role_name").
``support_actions``: Allowed
SkipActionvalues for this module.``support_online_step``: When
True, useextract_stepper call instead ofSkipManager.step.
Instance methods: is_enabled, meet_precondition, warp_function, prepare_data, and
extract_step (required when support_online_step is True).
RolloutSkip / AsyncRolloutSkip (verl.utils.skip.rollout_skip) implement generation
caching for the rollout and async_rollout roles.
Intercepted functions
Role |
Decorated function |
Defined in |
Step source |
|---|---|---|---|
|
|
|
|
|
|
|
|
``rollout`` wraps the full batch Agent Loop RPC (chunk dispatch, concat, timing) as one skip unit.
``async_rollout`` wraps one streaming sample’s generate_sequences_single(self, prompts,
sample_id) so concurrent samples resolve step independently.
Step resolution: set_step vs support_online_step
See section 2 for steps semantics per role.
Shared ``SkipManager.step``: One class-level slot per process. Fits sequential trainer loops (
main_ppo):set_step(global_steps)before rollout.Online step:
AsyncRolloutSkipsetssupport_online_step = Trueand parsessample_idon each call so in-flight async samples do not share a single counter. Forrepeat,RolloutSkiprecomputes_find_latest_stepon everymeet_preconditionandwarp_functioncall (no shared mutable step field on the skip instance).
Extending with custom skip modules
Subclass
BaseSkipfromverl.utils.skip.base_skip.Decorate the class with
@register_skip("your_role_name").Add a matching field under
SkipManagerConfig.Attach
@SkipManager.annotate(role="your_role_name"). For concurrent pipelines, prefersupport_online_step = Trueand pass step identity through call arguments.