Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
08ce80b
temp save rfc
SamitHuang Mar 2, 2026
3af806e
add plan
SamitHuang Mar 3, 2026
48fbde3
update
SamitHuang Mar 3, 2026
f8ceed6
qwen2.5 0.5b non-colocate (first attempt ok, but nccl error later)
SamitHuang Mar 4, 2026
2caa4a0
add convert script
SamitHuang Mar 4, 2026
8caa8ba
add setup doc
SamitHuang Mar 4, 2026
25ee005
fix nccl error by NcclBridge subprocess
SamitHuang Mar 5, 2026
09f534a
Add rollout backend client and test qwen2.5-0.5b non-colocate training
SamitHuang Mar 5, 2026
ab7eb0b
eliminate gpu to cpu weight transfer
SamitHuang Mar 5, 2026
411e2d2
Eliminate intermediate CPU tensors for faster weight transfer
SamitHuang Mar 5, 2026
546d2ad
Revise weight synchronization strategy in goal plan
SamitHuang Mar 5, 2026
d480da0
Router for vllm (#5)
knlnguyen1802 Mar 23, 2026
c154078
Plan refactor vllm/sglang
knlnguyen1802 Mar 30, 2026
1a2dcf5
Code implemented
knlnguyen1802 Mar 31, 2026
8addb37
Fix bug
knlnguyen1802 Mar 31, 2026
9689a97
Fix bug
knlnguyen1802 Mar 31, 2026
3753432
Fix bug
knlnguyen1802 Mar 31, 2026
f1e7554
Fix port
knlnguyen1802 Mar 31, 2026
91cc780
Fix config
knlnguyen1802 Mar 31, 2026
be1ecd4
Fix bug MOE weight sync
knlnguyen1802 Apr 1, 2026
e7216d8
Fix bug vllm transfer weight
knlnguyen1802 Apr 1, 2026
2343647
Fix weight sync
knlnguyen1802 Apr 1, 2026
8498b7b
Fix
knlnguyen1802 Apr 1, 2026
8a41184
Fix config
knlnguyen1802 Apr 2, 2026
acc9690
Change name config
knlnguyen1802 Apr 2, 2026
90934e6
Resolve review
knlnguyen1802 Apr 13, 2026
6b4c373
Try colocated vllm weight
knlnguyen1802 Apr 15, 2026
49d760f
[Draft] Local runable dev
knlnguyen1802 Apr 17, 2026
ee2702b
Fix offload train
knlnguyen1802 Apr 21, 2026
cb77fc5
Fix offload train
knlnguyen1802 Apr 22, 2026
ba06919
Fix offload_rollout
knlnguyen1802 Apr 22, 2026
3491aae
Fix vllm offload
knlnguyen1802 Apr 24, 2026
af2bfb4
Fix offload traing
knlnguyen1802 Apr 24, 2026
14aa09a
Fix offload weight
knlnguyen1802 Apr 24, 2026
d82d1d0
Fix offload weight
knlnguyen1802 Apr 24, 2026
c8aaf01
Fix CI: update rollout_data_postprocess plugin contract for new call …
jingshenghang May 11, 2026
5b326e6
Patch Megatron TP grad coalesce to chunked all-reduce (#1899)
jingshenghang May 11, 2026
41dc3b6
fix: harden retool rollout against multi-turn / retry desync (#1861)
leofan-lab May 11, 2026
a7a3ee1
Fix log file
knlnguyen1802 May 14, 2026
e7dbc8d
Rebase
knlnguyen1802 May 15, 2026
b015d72
Fix import engine group
knlnguyen1802 May 15, 2026
26f979d
Fix rebase code
knlnguyen1802 May 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions convert_qwen2.5_ckpt.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
source scripts/models/qwen2.5-0.5B.sh
PYTHONPATH=/root/Megatron-LM python tools/convert_hf_to_torch_dist.py \
${MODEL_ARGS[@]} \
--hf-checkpoint /root/Qwen2.5-0.5B-Instruct \
--save /root/Qwen2.5-0.5B-Instruct_torch_dist/
Comment on lines +2 to +5

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This script contains hardcoded paths (e.g., /root/Megatron-LM, /root/Qwen2.5-0.5B-Instruct). This reduces portability and makes it difficult for other users to run the script in different environments. Consider using environment variables or command-line arguments to specify these paths to improve reusability.

360 changes: 360 additions & 0 deletions docs/en/advanced/rfc-vllm-rollout-backend.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/en/examples/deepseek-r1.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ OPTIMIZER_ARGS=(

These are the parameters required by sglang. Here, `--rollout-num-gpus-per-engine` basically corresponds to sglang's `tp_size`. Other sglang parameters are passed to slime by adding a `--sglang-` prefix. To fully leverage sglang's large EP inference capabilities, we have added configurations like ep64, dp\_attention dp8, and deepep mode auto.

The final `--sglang-server-concurrency` is a parameter specific to slime. It is used to prevent the sglang server's concurrent requests from becoming too large and crashing the HTTP server. The default is 512. However, since we now have one server for 8 nodes, we have adjusted it to 1024 to ensure that each dp rank can have a concurrency of 128.
The final `--rollout-server-concurrency` is a parameter specific to slime. It is used to prevent the sglang server's concurrent requests from becoming too large and crashing the HTTP server. The default is 512. However, since we now have one server for 8 nodes, we have adjusted it to 1024 to ensure that each dp rank can have a concurrency of 128.

```bash
SGLANG_ARGS=(
Expand All @@ -190,7 +190,7 @@ SGLANG_ARGS=(
--sglang-deepep-mode auto

# make every dp rank have 128 concurrency
--sglang-server-concurrency 1024
--rollout-server-concurrency 1024
)
```

Expand Down
4 changes: 2 additions & 2 deletions docs/en/examples/qwen3-4B.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,10 @@ In this case, 2 GPUs will be allocated for training, and 6 GPUs will be allocate

⚠️ If the concurrency on each sglang server is too high, it may exceed sglang's default CUDA graph concurrency limit (the default maximum is 160), which will affect inference speed. You can adjust this in the following two ways:

1. Use `--sglang-server-concurrency` to limit the maximum number of concurrent requests sent to a single sglang server. For example:
1. Use `--rollout-server-concurrency` to limit the maximum number of concurrent requests sent to a single sglang server. For example:

```bash
--sglang-server-concurrency 160
--rollout-server-concurrency 160
```

2. Use `--sglang-cuda-graph-bs` (which corresponds to sglang's native `--cuda-graph-bs` argument) to increase the number of CUDA graphs initialized by sglang. For example:
Expand Down
462 changes: 462 additions & 0 deletions docs/en/vllm/ROUTER_DESIGN.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/zh/examples/deepseek-r1.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ OPTIMIZER_ARGS=(

sglang 所需的参数,这里 `--rollout-num-gpus-per-engine` 基本对应 sglang 的 `tp_size`,除此之外的 sglang 参数均通过添加 `--sglang-` 的前缀来传给 slime。为了充分利用 sglang 的大 EP 推理能力,我们加上了 ep64、dp_attention dp8、deepep mode auto 等配置。

最后的 `--sglang-server-concurrency` 是 slime 的特有参数,是为了方式同时发给 sglang server 的并发太大打爆 http server,默认为 512。但是我们现在是 8 机一个 server,为了保证每个 dp rank 能有 128 的并发,我们调整为 1024。
最后的 `--rollout-server-concurrency` 是 slime 的特有参数,是为了方式同时发给 sglang server 的并发太大打爆 http server,默认为 512。但是我们现在是 8 机一个 server,为了保证每个 dp rank 能有 128 的并发,我们调整为 1024。

```bash
SGLANG_ARGS=(
Expand All @@ -190,7 +190,7 @@ SGLANG_ARGS=(
--sglang-deepep-mode auto

# make every dp rank has 128 concurrency
--sglang-server-concurrency 1024
--rollout-server-concurrency 1024
)
```

Expand Down
4 changes: 2 additions & 2 deletions docs/zh/examples/qwen3-4B.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,10 @@ ray job submit ... \

⚠️ 在进行训推分离的时候,每个 sglang server 上的并发度太大,超过了 sglang 默认的 cuda graph 的并发度(默认最大 160),影响推理速度。可以用以下 2 种方式进行调整:

1. 通过 `--sglang-server-concurrency` 限制发给一个 sglang server 的最大并发量,例如:
1. 通过 `--rollout-server-concurrency` 限制发给一个 sglang server 的最大并发量,例如:

```bash
--sglang-server-concurrency 160
--rollout-server-concurrency 160
```

2. 使用 `--sglang-cuda-graph-bs`,即 sglang 原生的 `--cuda-graph-bs`, 增大 sglang 初始化的 cuda graph 数量,例如:
Expand Down
2 changes: 1 addition & 1 deletion examples/fully_async/fully_async_rollout.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def get_global_worker(args, data_buffer):
with _worker_lock:
if _global_worker is None or not _global_worker.worker_thread.is_alive():
print("Creating new global async worker...")
_global_worker = AsyncRolloutWorker(args, data_buffer, concurrency=args.sglang_server_concurrency)
_global_worker = AsyncRolloutWorker(args, data_buffer, concurrency=args.rollout_server_concurrency)
_global_worker.start()
return _global_worker

Expand Down
65 changes: 57 additions & 8 deletions examples/retool/generate_with_retool.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,15 @@ async def generate(args, sample: Sample, sampling_params) -> Sample:
"""Custom generation function supporting tool calls"""
assert not args.partial_rollout, "Partial rollout is not supported for " "this function at the moment."

# Retried samples (previously aborted / partial) arrive here with stale
# rollout state from the first attempt. Clear it so this generation starts
# clean; otherwise the concatenation below appends new tokens to old ones
# and downstream `slice_log_prob_with_cp` sees a length mismatch.
sample.rollout_log_probs = None
sample.response = ""
sample.response_length = 0
sample.loss_mask = None

state = GenerateState(args)
url = f"http://{args.sglang_router_ip}:{args.sglang_router_port}/generate"

Expand All @@ -229,22 +238,37 @@ async def generate(args, sample: Sample, sampling_params) -> Sample:
loss_masks = []
tool_call_count = 0 # Track actual tool call rounds

if args.rollout_max_context_len is not None:
max_context_length = args.rollout_max_context_len
else:
max_context_length = args.context_parallel_size * args.max_tokens_per_gpu

for turn in range(TOOL_CONFIGS["max_turns"]):
# Check if total length exceeds max context length
total_length = len(prompt_tokens_ids) + len(response_token_ids)
if args.rollout_max_context_len is not None:
max_context_length = args.rollout_max_context_len
else:
max_context_length = args.context_parallel_size * args.max_tokens_per_gpu
if total_length >= max_context_length:
sample.status = Sample.Status.TRUNCATED
break

# Clamp per-turn max_new_tokens to the remaining context budget so a
# single turn cannot push total_length past max_context_length. Without
# this, a turn can append up to rollout_max_response_len tokens on top
# of a total that was just barely under the cap, producing samples
# that exceed the training-side max_tokens_per_gpu * cp_size budget
# and crash the partition/batch code (asserts or OOMs on an oversized
# partition).
remaining_budget = max_context_length - total_length
per_turn_sampling_params = dict(sampling_params)
per_turn_sampling_params["max_new_tokens"] = min(
sampling_params.get("max_new_tokens", remaining_budget),
remaining_budget,
)

# Use token IDs instead of text
current_token_ids = prompt_tokens_ids + response_token_ids
payload = {
"input_ids": current_token_ids,
"sampling_params": sampling_params,
"sampling_params": per_turn_sampling_params,
"return_logprob": True, # Request log probabilities for training
}

Expand Down Expand Up @@ -285,9 +309,14 @@ async def generate(args, sample: Sample, sampling_params) -> Sample:
sample.rollout_log_probs += cur_log_probs

else:
cur_response = output["text"]
cur_response = postprocess_responses(cur_response)
cur_response_token_ids = state.tokenizer(cur_response, add_special_tokens=False)["input_ids"]
# sglang returned text but no output_token_logprobs — we cannot
# recover per-token logprobs for this turn, which would desync
# rollout_log_probs from response_token_ids and blow up
# `slice_log_prob_with_cp` downstream. Abort the sample so the
# fully_async rollout manager returns the whole group to the
# buffer for retry instead of poisoning the trainer.
sample.status = Sample.Status.ABORTED
return sample

response += cur_response
response_token_ids += cur_response_token_ids
Expand Down Expand Up @@ -321,6 +350,26 @@ async def generate(args, sample: Sample, sampling_params) -> Sample:
sample.rollout_log_probs
), f"Token/logp length mismatch at turn {turn}: {len(response_token_ids)} tokens vs {len(sample.rollout_log_probs)} logps"

# Tool output is appended verbatim and can push total_length past
# max_context_length (the per-turn generation was clamped to the
# remaining budget, but tool output is unconstrained). Trim tail
# tokens so the final sample fits the training budget exactly.
overflow = len(prompt_tokens_ids) + len(response_token_ids) - max_context_length
if overflow > 0:
response_token_ids = response_token_ids[:-overflow]
loss_masks = loss_masks[:-overflow]
if sample.rollout_log_probs is not None:
sample.rollout_log_probs = sample.rollout_log_probs[:-overflow]
# Resync the text field from the trimmed token list so
# reward_func's `sample.prompt + sample.response` matches what
# the model was actually trained on. decode(tokenize(text)) can
# be lossy on some tokenizers (whitespace / special-token
# collapse), but reward_func's regex is whitespace-robust and
# the trainer sees tokens, not text — so the drift is safe.
response = state.tokenizer.decode(response_token_ids)
sample.status = Sample.Status.TRUNCATED
break

if tool_call_count >= TOOL_CONFIGS["max_tool_calls"]:
break

Expand Down
2 changes: 1 addition & 1 deletion examples/tau-bench/run_qwen3_4B.sh
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ SGLANG_ARGS=(
--rollout-num-gpus-per-engine 1
--sglang-mem-fraction-static 0.7
# If gemini API reports concurrency limit error, set this parameter to reduce the concurrency
# --sglang-server-concurrency 32
# --rollout-server-concurrency 32
)

MISC_ARGS=(
Expand Down
33 changes: 33 additions & 0 deletions goal_plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
### 阶段一:打通Qwen2.5-0.5B GRPO 8卡同步/异步训练(train.py和train_async.py),GSM8K 数据集,loss/reward 收敛与 SGLang backend 基本一致,且满足确定性计算,多次重复运行Loss曲线完全一致。

First Design and RFC by 03/06

#### 初步方案:
- 对标SGLang,Slime 在 Ray 内管理 vLLM 的完整生命周期,包括进程拉起、权重同步、推理暂停/恢复
- 暂不使用Router,SGLang Model Gateway仅只支持SGLang Worker,SlimeRouter仅在 R3 / radix-tree caching 时需要,Qwen2.5-0.5B 非 MoE 且用 token-in/token-out
- 单vLLM实例,无router,通过vLLMClient 直连本地 vLLM 进程端口
- 先支持训推不共卡(non-colocate),权重同步采用NCCL broadcast,对标SGLang update_weights_from_distributed (默认)
- 再支持和验证colocate,权重同步采用GPU IPC(vLLM update_weights_from_ipc, update_weights_from_tensor),对标SGLang update_weights_from_tensor,以验证Reproductivity。**IPC 依赖vllm 0.17**

#### 风险:
- slime, sglang版本依赖,和vllm 0.16的版本依赖冲突(numpy, torch, transformers, etc)
- slime代码较挫,可靠性差,强依赖preset docker
- 算力


#### Reference

https://thudm.github.io/slime/advanced/reproducibility.html


### 阶段二:接入vllm-project/router,支持多实例vLLM

- vllm router forked from SGLang Model Gateway

### 阶段三:多节点大规模验证,MoE模型,optional:验证MTP Speculative Decoding,FP8 rollout 等高级特性

- Model: Qwen/Qwen3-30B-A3B or GLM4.7
- Parallel: 16卡 or 128卡, Train mixed EP+FSDP, Rollout EP+DP
- Verify more features:
- Bf16 train, FP8 rollout
- MTP Speculative Decoding
Loading
Loading