feat: integrate Arctic RL backend (opt-in via [arctic]) - #2
Open
sfc-gh-kganesan wants to merge 1 commit into
Open
feat: integrate Arctic RL backend (opt-in via [arctic])#2sfc-gh-kganesan wants to merge 1 commit into
sfc-gh-kganesan wants to merge 1 commit into
Conversation
sfc-gh-kganesan
marked this pull request as ready for review
May 25, 2026 20:57
sfc-gh-kganesan
force-pushed
the
feat/arctic-integration
branch
from
May 27, 2026 07:53
5b26b03 to
a018632
Compare
Adds an opt-in alternative training backend for prime-rl. All integration
code lives under integrations/arctic-rl/; core prime-rl gains a small
generic dispatch hook (~66 LOC, no integration name).
Enabling: any existing recipe flips to Arctic via a one-line overlay,
no edits to the base recipe:
uv run rl @ configs/gsm8k/rl.toml @ integrations/arctic-rl/examples/arctic_overlay.toml
The launcher peeks at trainer.backend before strict config parse and
dispatches via importlib.import_module(f"{backend}.entrypoint").main().
Default is "native"; when unset the integration package is never imported.
Core changes (5 files, +66/-2):
- packages/prime-rl-configs: backend field on TrainerConfig;
client_type + class_path fields on ClientConfig
- src/prime_rl/entrypoints/rl.py: _peek_backend dispatch
- src/prime_rl/orchestrator/orchestrator.py: honor client_type;
no-op update_weights for custom clients (they own their own
weight sync)
- src/prime_rl/utils/client.py: forward class_path to vf.ClientConfig
Integration (~2.35k LOC, all under integrations/arctic-rl/):
- ArcticClient: a verifiers.Client subclass that batches and proxies
rollouts to the Arctic RL coordinator. No subprocess, no monkey-patch.
- arctic-trainer: single-process HTTP client to the Arctic RL coordinator
(/fwd-bwd, /step, /sync-weights). Reuses prime-rl's DataLoader and
scheduler, writes the STABLE marker after each weight sync so the
orchestrator's polling loop is unchanged.
Validation (4xH200, wandb offline):
- Native dispatch regression check on reverse_text, alphabet_sort,
gsm8k: convergence preserved.
- Arctic-mode E2E convergence on reverse_text: 0.105 -> 0.833 peak
over 30 steps (7.1x), monotonic ramp, plateau by step ~18.
- Arctic-mode E2E on gsm8k via overlay (native recipe untouched):
0.561 -> 0.792 peak over 30 steps. Aggregate: 480+ HTTP 200,
0 5xx, ~7700 rollouts with 0 failures.
Companion: sfc-gh-kganesan/verifiers#1 (~30 LOC)
adds client_type="custom" + class_path field on the verifiers ClientConfig.
Out of scope: multi-node, LoRA, multi-run, teacher_inference, multimodal.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
sfc-gh-kganesan
force-pushed
the
feat/arctic-integration
branch
from
May 27, 2026 08:05
a018632 to
abb08b4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Opt-in Arctic RL backend for PRIME-RL.
grep -ri "arctic" src/ packages/ pyproject.tomlreturns 2 matches, both in docstrings/comments illustrating the new generic field — no imports, no hardcoded references.Enabling
Any existing recipe flips to Arctic via a one-line overlay — no edits to the base recipe:
The overlay file is 8 lines:
The launcher peeks at
trainer.backendbefore strict config parse and dispatches viaimportlib.import_module(f"{backend}.entrypoint").main(). Default is"native"— when unset thearctic_rlpackage is never imported. The base recipe's[inference]block is silently ignored in Arctic mode (Arctic owns sampling via its own server).Architecture
torchrun+ FSDP2ArcticClientruns in-process inside the orchestrator)ClientTwo PRs
client_type="custom"and aclass_path: str | Nonefield onClientConfig. Generic — works for any externalClientsubclass.integrations/arctic-rl/.ArcticClient(verifiers.OpenAIChatCompletionsTokenClient)overrides three methods:tokenize,get_native_response,from_native_response. No subprocess, no monkey-patch.Validation
Native-dispatch regression check (4×H200, wandb offline)
Verifies that adding the
_peek_backenddispatch + newclient_type/class_pathconfig fields doesn't regress the native path. All three runs usetrainer.backend = "native"(the default).examples/reverse_text/rl.tomlexamples/alphabet_sort/rl.tomlconfigs/gsm8k/rl.tomlArctic-mode E2E convergence (4×H200,
backend = "local", wandb offline)Two recipes, 30 steps each, end-to-end through the Arctic RL backend.
reverse-text (dedicated example
integrations/arctic-rl/examples/arctic_reverse_text/rl.toml)0.128 → 0.786 (6.1×), monotonic, plateau by step ~17.
gsm8k (native
configs/gsm8k/rl.toml+arctic_overlay.toml, no recipe edits)Qwen3-0.6B starts strong on gsm8k; Arctic mode reaches 0.792 peak at step 9, comparable to the native 10-step run (0.781). Late-step variance (~0.55-0.75) is normal RL noise.
Aggregate server-side counters across both runs: 840× HTTP 200, 0× 5xx, ~7,700 rollouts with 0 failures. NCCL weight transfer between training and sampling GPUs averaged 0.9-3.7s (longer for the 2048-token gsm8k responses).
Bugs surfaced + fixed by E2E runs
Six integration bugs uncovered while running real Arctic-mode jobs are folded into the squashed commit:
entrypoint.pyblankedCUDA_VISIBLE_DEVICESfor the trainer subprocess. Correct forbackend="remote"(trainer is just an HTTP client), but withbackend="local"the trainer spawns the Arctic RL coordinator in-process and Ray needs visible GPUs. Now gated on backend.pyvenv.cfgmarkers) and re-launches its raylet workers viauv run python, which lands them in a freshly-created empty venv without ray. Stripped uv-related env vars and setRAY_ENABLE_UV_RUN_RUNTIME_ENV=0.wait_for_readydoes an HTTP probe onclient.base_url. With Arctic mode that URL pointed at the OAI-compat default (localhost:8000), which has nothing listening. Now redirected toarctic.urlandskip_model_check=True(the Arctic RL coordinator doesn't speak the OAI catalog API).StaticInferencePool.update_weightsissues/pauseon its admin clients before pushing weights — fine for vLLM, but the Arctic RL coordinator has no/pauseendpoint (it owns its own NCCL weight-sync). Added a no-op override whenclient_type="custom".ArcticRLConfigvalidator now silently drops[inference]instead of rejecting it, so existing recipes work via overlay without edits.ArcticTrainerAdapterinspectsclient.step()'s signature before passinglearning_rate(olderArcticRLClient.step()revs take no kwargs).Out of scope
Multi-node, LoRA, multi-run,
teacher_inference, multimodal. Recipes using any of those need explicit edits, the overlay alone won't help.