ReOPD distills a teacher agent into a student without environment interaction during student training: the student acts on prefixes replayed from pre-collected teacher trajectories, while the teacher supplies dense per-step supervision. It matches or improves online OPD accuracy with zero tool calls and 4β9Γ faster rollouts.
- [07/2026] ReOPD reproduction code is released!
Fully online OPD (top) re-rolls the student through a live environment every update and queries the teacher at each visited history. ReOPD (bottom) replays a teacher-forced prefix from an offline pool β collected for free during the teacher's RL β and lets the student act only at the supervised step. Multi-turn OPD suffers a two-sided distribution shift (student occupancy vs. teacher reliability), so ReOPD samples positions with p_t β ΞΊ^t (ΞΊ = 0.6) at data-processing time, favoring early, low-shift prefixes and leaving the loss unchanged.
The offline pool also decouples environments from training: trajectories from heterogeneous environments are collected separately by domain-specific teachers and merged into one pool, so a single student is distilled jointly without keeping all environments online.
ReOPD/
data/ # Prefix-pool construction, prompt mixing
train/ # Training code (src/) + env-var reference (README.md)
eval/ # math/ (AIME24/25, AMC23, Minerva, Olympiad, MATH500), search/ (7 QA sets)
scripts/
models/ # Megatron model-arg configs
train/ # convert, cold start, GRPO, distillation
eval/ # math.sh, search.sh
tools/ # HF <-> Megatron torch_dist converters
docs/ # search.md, multi_env.md
third_party/slime # Training framework (submodule)
This README covers math (ReTool). See docs/search.md and docs/multi_env.md for the other environments.
Set up the base environment following slime's quick-start guide (PyTorch/CUDA, Ray, SGLang, Megatron-LM, Docker image), then:
git clone https://github.com/BaohaoLiao/ReOPD.git && cd ReOPD
git submodule update --init --recursive
pip install -r requirements.txt
pip install -e third_party/slime --no-deps- A100 (SM80): slime's default images target H100/H800. Use the A100 patch set in THUDM/slime#1832.
- Megatron elsewhere than
/root/Megatron-LM:export MEGATRON_ROOT=/path/to/Megatron-LM. - Math (ReTool): no extra install β the Python sandbox deps are in
requirements.txt. - Search (Search-R1): extra deps + a retriever conda env β see
docs/search.md.
Evaluate a released model:
hf download baohao/ReOPD_Math_Qwen3-8B_SFT-RL_to_Math_Qwen3-4B-Instruct-2507_SFT --local-dir /ckpt/model
DP_SIZE=8 bash scripts/eval/math.sh /ckpt/modelRun one ReOPD distillation from released artifacts, skipping stages 1, 2 and 3a (8 GPUs: teacher 4β7, student 0β3):
hf download baohao/Math_Qwen3-4B-Instruct-2507_SFT --local-dir /ckpt/student_hf
hf download baohao/Math_Qwen3-8B_SFT-RL --local-dir /ckpt/teacher_hf
hf download baohao/Math_Qwen3-8B_SFT-RL_Prefix --repo-type dataset --local-dir /data/pool
# slime trains from torch_dist; the teacher is served by SGLang and stays HF
HF_CHECKPOINT=/ckpt/student_hf SAVE=/ckpt/student_torch_dist \
bash scripts/train/convert_hf_to_torch_dist.sh
TEACHER=qwen3-8b STUDENT=qwen3-4b \
TEACHER_MODEL_PATH=/ckpt/teacher_hf \
HF_CHECKPOINT=/ckpt/student_hf \
REF_LOAD=/ckpt/student_torch_dist \
PROMPT_DATA=/data/pool/train.jsonl \
SAVE_DIR=/runs/reopd_8b_to_4b \
bash scripts/train/reopd_math.sh
RUN_DIR=/runs/reopd_8b_to_4b ORIGIN_HF_DIR=/ckpt/student_hf \
bash scripts/eval/math.sh iter_0000199Any released checkpoint used as a student needs that one-time torch_dist conversion for
REF_LOAD(addMODEL_CONFIG=scripts/models/<model>.shfor 8B/30B). Teachers stay in HF format.
Four stages per environment. Every script validates its inputs on startup and names what's missing.
| Stage | Script | Purpose |
|---|---|---|
| 1 | cold_start.sh |
SFT the base model on tool-use traces |
| 2 | teacher_grpo_math.sh |
RL the teacher; its rollouts become the prefix pool for free |
| 3 | reopd_math.sh |
ReOPD (ours) β replay prefixes, one turn, zero tool calls |
| 4 | opd_math.sh |
OPD baseline β student rolls out live, queries the teacher every step |
Start from any stage. All
_SFT(cold start) and_SFT-RL(teacher) checkpoints are released β see Trained Models and the Quickstart conversion note.
Download a base model and convert it to torch_dist (written to <hf_dir>/torch_dist):
hf download Qwen/Qwen3-4B-Instruct-2507 --local-dir /path/to/Qwen3-4B-Instruct-2507
# also available: Qwen/Qwen3-8B-Base , Qwen/Qwen3-30B-A3B-Instruct-2507
QWEN3_4B_HF=/path/to/Qwen3-4B-Instruct-2507 \
bash scripts/train/convert_all_to_torch_dist.shSet QWEN3_8B_HF and/or QWEN3_30B_HF in the same call to convert those too. Then SFT:
hf download baohao/math-cold-start --repo-type dataset --local-dir /path/to/data
MODEL=qwen3-4b \
HF_CHECKPOINT=/path/to/Qwen3-4B-Instruct-2507 \
REF_LOAD=/path/to/Qwen3-4B-Instruct-2507/torch_dist \
PROMPT_DATA=/path/to/data/train.parquet \
SAVE_DIR=/path/to/output \
bash scripts/train/cold_start.shMODEL sets config, parallelism and optimizer offload; 3 epochs, LR 5e-5 cosine:
MODEL |
Config | TP | EP | Offload |
|---|---|---|---|---|
qwen3-4b (default) |
qwen3-4B-Instruct-2507.sh | 2 | 1 | off |
qwen3-8b |
qwen3-8B.sh (Qwen3-8B-Base) | 2 | 1 | off |
qwen3-30b |
qwen3-30B-A3B-Instruct-2507.sh | 4 | 8 | on |
Qwen3-8B-Base ships without a chat template.
convert_all_to_torch_dist.shcopiestokenizer_config.jsonfrom Qwen3-4B-Instruct-2507 whenever bothQWEN3_8B_HFandQWEN3_4B_HFare set, keeping everything in non-thinking mode (COPY_NONTHINKING_TOKENIZER=0disables).
slime saves cold start as a training checkpoint (optimizer state included), so re-materialize clean weights first β torch_dist β HF β torch_dist:
COLD_START_RUN=/path/to/output # SAVE_DIR from stage 1
ITER=$(cat $COLD_START_RUN/latest_checkpointed_iteration.txt)
INPUT_DIR=$COLD_START_RUN/iter_$(printf '%07d' $ITER) \
OUTPUT_DIR=/path/to/sft_hf \
ORIGIN_HF_DIR=/path/to/Qwen3-4B-Instruct-2507 \
bash scripts/train/convert_torch_dist_to_hf.sh
HF_CHECKPOINT=/path/to/sft_hf SAVE=/path/to/sft_torch_dist \
bash scripts/train/convert_hf_to_torch_dist.shThen RL the teacher:
hf download baohao/math-train --repo-type dataset --local-dir /path/to/rl_data
MODEL=qwen3-4b \
HF_CHECKPOINT=/path/to/sft_hf \
REF_LOAD=/path/to/sft_torch_dist \
PROMPT_DATA=/path/to/rl_data/train.jsonl \
SAVE_DIR=/path/to/teacher_run \
bash scripts/train/teacher_grpo_math.shMODEL also sets the RL rollout-engine and memory settings. Rollouts land in SAVE_DIR/rollout_debug/ β that is the prefix pool for stage 3. No in-training eval; measure with scripts/eval/math.sh.
a. Build the prefix pool (Ο(t; ΞΊ) = ΞΊ^t, ΞΊ = 0.6):
python data/build_prefix_pool_math.py \
--rollout-dir /path/to/teacher_run/rollout_debug \
--prompt-data /path/to/rl_data/train.jsonl \
--output /path/to/math_prefix_pool.jsonlFiltering rules and flags: data/README.md.
Or download it. One pool per teacher:
Teacher Pool Rows Qwen3-4B-Instruct-2507 Math_Qwen3-4B-Instruct-2507_SFT-RL_Prefix81,936 Qwen3-8B Math_Qwen3-8B_SFT-RL_Prefix53,762 Qwen3-30B-A3B-Instruct-2507 Math_Qwen3-30B-A3B-Instruct-2507_SFT-RL_Prefix54,706
b. Distill:
TEACHER=qwen3-30b STUDENT=qwen3-4b \
TEACHER_MODEL_PATH=/path/to/teacher_sft_rl_hf \
HF_CHECKPOINT=/path/to/student_sft_hf \
REF_LOAD=/path/to/student_sft_torch_dist \
PROMPT_DATA=/path/to/math_prefix_pool.jsonl \
SAVE_DIR=/path/to/student_run \
bash scripts/train/reopd_math.shSame presets as stage 4; what differs:
| ReOPD (3) | OPD (4) | |
|---|---|---|
| Student turns / sample | 1 | up to 16 |
| Tool calls | 0 | up to 16 |
| Response / context cap | 4096 / 8192 | 8192 / β |
| Teacher serving | mem 0.8, 256 in-flight, 32k KV | mem 0.85, 128 in-flight, uncapped |
One turn and zero tool calls is what makes rollouts 4β9Γ faster.
Same command with opd_math.sh and the RL prompts instead of the pool:
TEACHER=qwen3-30b STUDENT=qwen3-4b \
TEACHER_MODEL_PATH=/path/to/teacher_sft_rl_hf \
HF_CHECKPOINT=/path/to/student_sft_hf \
REF_LOAD=/path/to/student_sft_torch_dist \
PROMPT_DATA=/path/to/rl_data/train.jsonl \
SAVE_DIR=/path/to/student_run \
bash scripts/train/opd_math.shTEACHER and STUDENT are independent. The paper's pairs:
| Pair | TEACHER |
STUDENT |
Teacher served | Student offload |
|---|---|---|---|---|
| 4B β 4B | qwen3-4b |
qwen3-4b |
TP1 Γ DP4 | off |
| 8B β 4B | qwen3-8b |
qwen3-4b |
TP1 Γ DP4 | off |
| 30B β 4B | qwen3-30b |
qwen3-4b |
TP2 Γ DP2 | off |
| 30B β 8B | qwen3-30b |
qwen3-8b |
TP2 Γ DP2 | on |
Teacher on TEACHER_GPUS (default 4β7), student on STUDENT_GPUS (0β3). Every variable: train/README.md.
# HF checkpoint:
DP_SIZE=8 bash scripts/eval/math.sh /path/to/hf_model
# torch_dist checkpoints from a run (converted automatically):
RUN_DIR=/path/to/run ORIGIN_HF_DIR=/path/to/base_hf \
bash scripts/eval/math.sh iter_0000199 iter_0000219One pipeline: convert if needed β serve β evaluate β tear down. Key settings are grouped at the top of the script and env-overridable, e.g. DATASETS="aime24" NUM_SAMPLES_HARD=16 TP_SIZE=2. Search eval: docs/search.md.
All in the Hugging Face collection. Names encode role, environment (Math / Search / Both), and base model. Multi-env runs reuse the single-env teachers β only the student is trained on both.
| Role | Pattern |
|---|---|
| Cold start (stage 1) | <Env>_<Base>_SFT |
| Teacher (stage 2) | <Env>_<Base>_SFT-RL |
| ReOPD student (ours) | ReOPD_<Teacher>_to_<Student> |
| OPD student (baseline) | OPD_<Teacher>_to_<Student> |
| SFT student (off-policy baseline) | SFT_<Student>_on_<Teacher>_trace |
| Multi-env cold start | Both_<Base>_SFT |
| Multi-env student | <Method>_Math-Search_<Teacher>_to_Both_<Student> |
| Prefix pools (stage-3 data) | <Env>_<Teacher>_SFT-RL_Prefix |
Example: baohao/ReOPD_Math_Qwen3-30B-A3B-Instruct-2507_SFT-RL_to_Math_Qwen3-8B_SFT.
@misc{liao2026reopd,
title={Multi-Turn On-Policy Distillation with Prefix Replay},
author={Baohao Liao and Hanze Dong and Christof Monz and Xinxing Xu and Li Dong and Furu Wei},
year={2026},
eprint={2607.04763},
archivePrefix={arXiv},
primaryClass={cs.LG},
url={https://arxiv.org/abs/2607.04763},
}Built on slime for training and SGLang for rollout and teacher serving. The math and search environments are adapted from ReTool and Search-R1. We really appreciate their contributions to the community.


