Adapting an Embodied Model in SGLang Server#
This document describes how to integrate an embodied model already adapted to SGLang Server into RLinf’s evaluation rollout and evaluate the model using the various simulators supported by RLinf.
The document is divided into two parts:
The first part describes the steps and interface conventions required when adapting any new model;
The second part uses DreamZero as an example and explains, item by item, the code and YAML configuration that need to be modified.
Note
This document only covers the eval rollout / sglang-serve path. This path is responsible for converting environment observations into actions during evaluation and does not include training-side model registration, FSDP Policy, or SFT adaptation. For training-side adaptation, refer to Adding a New Model with FSDP and Adding a New SFT Model.
Part One: Adapting a New Model#
Overall Architecture#
The SGLang embodied evaluation path separates general logic from model-specific logic:
The driver script (e.g.
eval_embodied_agent.py) starts one or more sglang server processes vialaunch_sglang_router_and_server()and pushes each server’s URL to the rollout workers; server startup,/healthpolling, and port allocation are handled bySGLangServerWorker(driver side) — the rollout worker itself no longer owns a server subprocess;SGLangEmbodiedWorkerpicks the driver-assigned server URL for its own rank, uses it to create anInferenceHTTPClient, loads the model’s sglang adapter, and exchanges observations and actions with the environment Worker through channels. The HTTP request to the server (msgpack encoding + retries) is performed by the worker itself;The sglang adapter (a plain standalone class, e.g.
DreamZeroSGLangAdapter) only holds model-specific pure logic:build_requestturns an env observation into the request payload,parse_responseturns the server response into actions, andaction_pathdeclares the action endpoint. It does not hold an HTTP client and does not send requests itself.
Therefore, integrating a new model usually does not require modifying
rlinf/workers/rollout/sglang/sglang_embodied_worker.py, and you do not need to
care how the server is started — server parameters come entirely from the YAML
rollout.sglang.server block passed straight to the sglang server process. The
model is selected by rollout.model.model_type, and the call flow is as follows:
rollout.model.model_type: "<your_model>"
│
â–Ľ
driver: launch_sglang_router_and_server()
│ (rollout.sglang.server_type == "embodied" → SGLangServerWorker)
â–Ľ
each SGLangServerWorker.init_server()
│ (rollout.sglang.server → ServerArgs.from_kwargs → dispatch_launch)
â–Ľ
SGLangEmbodiedWorker.init_worker()
│
├── get_sglang_adapter_cls("<your_model>")
├── pick this rank's server URL, create InferenceHTTPClient
└── create YourSglangAdapter(cfg, rank)
SGLangEmbodiedWorker.predict(env_obs) # driven by EmbodiedEvalRunner
│
├── adapter.build_request(env_obs) → (payload, state)
├── http_client.post(adapter.action_path, payload, msgpack=True, ...)
└── adapter.parse_response(resp, state) → [N, H, D] actions
To enter this call flow, the following conditions must all be satisfied in the configuration:
runner:
task_type: embodied_eval
only_eval: true
rollout:
rollout_backend: sglang
sglang:
serving_mode: embodied # rollout worker = SGLangEmbodiedWorker
server_type: embodied # server dispatch = embodied (via dispatch_launch)
launch_server: true # driver launches the server group
model:
model_type: "<your_model>"
Note that rollout.sglang.server_type and rollout.model.model_type are two
orthogonal fields with different names and different responsibilities:
rollout.sglang.server_typedecides which sglang dispatch branch the server subprocess runs (within the sameSGLangServerWorkerclass:srt= language model viasglang.srt.entrypoints.http_server.launch_server;embodied= VLA / diffusion viasglang.multimodal_gen.runtime.launch_server.dispatch_launch, serving the/v1/actions/generationsendpoint);rollout.model.model_typedecides which sglang adapter the rollout worker loads (the adapter registry lookup key).
serving_mode: embodied also cannot be omitted — otherwise RLinf creates a
regular SGLangWorker instead of SGLangEmbodiedWorker.
Adaptation Steps#
The following describes, in the recommended order, the work required for a new model.
Step 1: Confirm the SGLang Server Action Interface#
RLinf’s sglang adapter builds requests for and parses responses from SGLang Server (the actual HTTP round-trip is performed by the worker). Before writing RLinf code, first confirm that the SGLang side already has the following capabilities:
sglang servecan load the target model or target Pipeline;SGLang Server provides a VLA interface for this model that accepts batched observations and returns batched actions;
The request and response formats are fixed and can represent the images, text, states, and cache information required by the model.
Warning
The sglang adapter in the RLinf repository is only responsible for building action requests and parsing responses. The model Pipeline, action route, and
related sglang serve parameters still need to be implemented in the SGLang version being used.
Step 2: Register model_type#
Register the model in rlinf/config.py so that configuration validation recognizes the name:
SupportedModel.YOUR_MODEL = SupportedModel.register("your_model", force=True)
If the model needs to pass embodied configuration validation, it must also be added to EMBODIED_MODEL:
EMBODIED_MODEL = {
# ...
SupportedModel.YOUR_MODEL,
}
"your_model", the name used in register_sglang_adapter, and
rollout.model.model_type in the YAML must be identical. The adapter registry
lookup is case-insensitive, but using lowercase everywhere is still recommended.
Step 3: Implement the sglang adapter#
Create the adapter file under the model’s own directory (in the model layer, next to the training-side model code):
rlinf/models/embodiment/<your_model>/sglang_adapter.py
The adapter is a plain standalone class (it does not need to inherit any base
class) with the constructor signature (cfg, rank). It must implement
build_request / parse_response and declare action_path:
import numpy as np
import torch
class YourSglangAdapter:
action_path = "/v1/actions/generations"
def __init__(self, cfg, rank):
self.cfg_rollout = cfg.rollout
self.model_cfg = cfg.rollout.model
self.rank = rank
# Create lightweight transforms here (do not load large model weights).
def build_request(self, env_obs, mode="eval"):
# 1. Convert RLinf env_obs to model input and normalize it;
# 2. Assemble the server request payload (a dict);
# 3. Return (payload, state); state is passed back to parse_response as-is.
payload = {...}
state = ... # e.g. the intermediate observation used for denormalization
return payload, state
def parse_response(self, resp, state):
# 1. Read the normalized action from the server response;
# 2. Denormalize it to environment-scale actions.
actions = ...
info = {
"prev_logprobs": ...,
"prev_values": ...,
"forward_inputs": ...,
}
return torch.as_tensor(actions, dtype=torch.float32), info
Interface contract:
HTTP is handled by the worker — the adapter does not hold an HTTP client and does not send requests. The worker calls
build_requestto get the payload, sends it viahttp_client.post(adapter.action_path, payload, msgpack=True, ...), then hands the response toparse_response;The
env_obspassed tobuild_requestis a dictionary of environment observations organized by batch; general fields includemain_imagesandtask_descriptions, and the model can also usewrist_images,statesor other views. It returns(payload, state):payloadis the request body sent to the server, andstateis any intermediate value to be reused inparse_response;parse_responsereturns(actions, info):actionsmust be a Tensor with shape[N, num_action_chunks, action_dim];infois an additional information dictionary reserved for future training extensions — currently it can returnprev_logprobs,prev_valuesandforward_inputsas DreamZero does;The current SGLang embodied Worker is used only for evaluation. If the adapter does not support training mode, it should explicitly raise
NotImplementedErrorwhenmode != "eval". Support for using SGLang as a rollout worker for embodied model training is planned.
Important
Do not load the model in the adapter. The model should exist only in the
sglang serve subprocess. Keep only data transformations and a small amount
of request context in the adapter; otherwise weights will be loaded repeatedly
and additional GPU memory will be consumed.
Step 4: Register the adapter#
The adapter is registered with a lazy builder in
_register_builtin_sglang_adapters() inside
rlinf/models/embodiment/sglang_adapter.py (mirroring the model-registration
style of rlinf.models): put the heavy imports inside the builder so your
adapter module is imported only when that model_type is actually looked up:
# rlinf/models/embodiment/sglang_adapter.py
def _register_builtin_sglang_adapters():
def _build_your_model():
from rlinf.models.embodiment.your_model.sglang_adapter import (
YourSglangAdapter,
)
return YourSglangAdapter
register_sglang_adapter(
SupportedModel.YOUR_MODEL.value,
_build_your_model,
force=True,
)
The worker looks it up via get_sglang_adapter_cls(model_type) in
init_worker. If registration is missing, Worker initialization reports that
no sglang adapter is registered for the corresponding model_type.
Step 5: Add the Model YAML and Evaluation YAML#
It is recommended to maintain the model configuration and SGLang evaluation configuration separately:
examples/embodiment/config/model/<your_model>.yaml
evaluations/<benchmark>/<your_model>_eval_sglang.yaml
The model configuration describes the model’s fixed structure, such as action dimensions, action horizon, and input image size; the evaluation YAML describes the checkpoint, environment, resources, Server startup parameters, and HTTP parameters. This allows the same model configuration to be reused by multiple YAML configuration files.
Step 6: Test and Debug#
For the first run, it is recommended to reduce env.eval.total_num_envs and confirm the following in order:
The rollout Worker type in the logs is
SGLangEmbodiedWorkerand the server Worker type isSGLangServerWorker(server_type=embodied);The
multimodal_gen sglang serve: launching in-process ...line printed in the logs carries the correctpipeline,backend,tp_sizeand GPU;/healthresponds before the timeout (server first-time compilation + weight loading is slow, so allow enough time);The request sent by the Policy can be parsed correctly by the action endpoint;
The action dimensions and dtype output by the Server meet the convention;
The denormalized action shape matches the simulator’s requirements;
Increase the number of parallel environments and the degree of model parallelism only after a small-scale run succeeds.
Part Two: DreamZero as an Example#
DreamZero’s SGLang evaluation path consists of the following files:
File |
Purpose |
|---|---|
|
Register |
|
|
|
adapter registry ( |
|
DreamZero 5B model configuration |
|
SGLang evaluation YAML for LIBERO-Spatial |
Code Adaptation#
Register the Model#
DreamZero is registered in rlinf/config.py as follows:
SupportedModel.DREAMZERO = SupportedModel.register("dreamzero", force=True)
At the same time, SupportedModel.DREAMZERO is added to EMBODIED_MODEL. Therefore, the evaluation YAML
can use:
rollout:
model:
model_type: dreamzero
Adapter Adaptation#
sglang_adapter.py uses a single class DreamZeroSGLangAdapter to hold
all of the DreamZero adaptation logic (observation/action transforms + request
assembly + response parsing):
__init__(cfg, rank)reuses the training data transforms (build_dreamzero_composed_transform) to prepare observation conversion and action inverse-transform; it does not load the large model nor build an HTTP client;build_request(env_obs, mode)turns an env observation into the server request payload and returns astate(the converted observation) forparse_responseto reuse;parse_response(resp, state)reads the normalized action from the response and denormalizes it to environment-scale actions;action_pathdeclares the action endpoint/v1/actions/generations.
The HTTP request is performed by ``SGLangEmbodiedWorker`` — the adapter only
builds the payload and parses the response, it does not send requests; server
parameters also come entirely from the YAML rollout.sglang.server block.
The adapter is registered via a lazy builder (see
rlinf/models/embodiment/sglang_adapter.py):
register_sglang_adapter(
SupportedModel.DREAMZERO.value,
_build_dreamzero_sglang_adapter, # lazily imports DreamZeroSGLangAdapter inside
force=True,
)
The complete data flow for one inference is:
RLinf env_obs
│
├── build_request()
│ ├── _observation_convert()
│ │ main_images → video.image
│ │ wrist_images → video.wrist_image
│ │ states → state.state
│ │ task_descriptions → annotation.task
│ ├── _normalize_obs() dataset transform + metadata normalization
│ │ (text is NOT tokenized on the client; the SGLang server does it)
│ └── assemble payload (raw prompt text + normalized observation)
│
├── worker: POST /v1/actions/generations (msgpack)
│
└── parse_response()
├── _unapply() [B, H, max_action_dim] → environment-scale actions
└── actions [B, H, action_dim]
Using embodiment_tag: libero_sim as an example, main_images and
wrist_images are converted into two video modalities, an external camera and a wrist camera; states is converted into
robot state, and task_descriptions is converted into language instructions. The inverse transformation slices out the action dimensions required by LIBERO according to
the metadata and binarizes gripper actions to -1 or 1.
To make DreamZero support a new simulator, it is usually also necessary to add, under
rlinf/data/datasets/dreamzero/data_transforms/, the corresponding
embodiment_tag, RolloutObsLayout, modality definitions, training prompt format, and
embodiment id.
HTTP Requests#
The adapter’s build_request assembles the payload for
POST /v1/actions/generations, which the worker sends via
http_client.post(..., msgpack=True). The logical structure of the payload is
as follows (transported with msgpack, so Tensors and ndarrays do not need to be
expanded into large lists first):
{
"model": "/path/to/RLinf-DreamZero-WAN2.2-5B-LIBERO-SFT-repacked",
"input": {
"prompt": [
"<training-format prompt>"
],
"observation": {}
},
"parameters": {
"session_ids": [
"rlinf-eval-r0-stage0-slot0"
],
"reset_mask": [
false
],
"negative_prompts": [
"<negative prompt>"
],
"seed": 1140
},
"runtime": {
"response_format": "envelope",
"output_format": "numpy"
}
}
Where:
input.promptis the raw instruction text for each environment (it is not tokenized on the client; the SGLang server tokenizes it);input.observationis the normalized model input (the output of_normalize_obswith the prompt/token-related keys removed);parameters.session_idsidentifies each logical environment slot and is used by the Server to reuse video or text caches;parameters.reset_maskis used to clear the cache for the corresponding session before the next request (allfalseby default in evaluation);parameters.negative_promptsare the negative prompts;parameters.seedcomes fromrollout.sglang.seed.
The worker reads the normalized actions returned by the Server from the following
location and hands them to parse_response:
response["data"][0]["action"]["values"]
These actions are still in DreamZero’s normalized and padded action space and cannot be sent directly to the environment; they must pass through
DreamZeroSGLangAdapter._unapply (called inside parse_response).
Server Parameters and Pipeline Configuration#
The server’s startup parameters come entirely from the YAML
rollout.sglang.server block. That block is forwarded verbatim to
sglang.multimodal_gen’s ServerArgs.from_kwargs(**): top-level keys are
ServerArgs fields, and the pipeline_config sub-block is dispatched by
from_kwargs into DreamZeroPipelineConfig (matched by
pipeline_class_name), which also converts backend / disagg_role
strings to enums. A typical block looks like:
rollout:
sglang:
server:
model_path: ${rollout.model.model_path}
backend: sglang
pipeline_class_name: DreamZeroPipeline
tp_size: ${..tensor_parallel_size}
num_gpus: 1
attention_backend: TORCH_SDPA
dit_cpu_offload: false
cfg_parallel_degree: 1
sp_degree: 1
pipeline_config: # → DreamZeroPipelineConfig
cfg_scale: 5.0
default_num_inference_steps: 16
action_horizon: 16
num_frames: 33
synthetic_height: 160
synthetic_width: 320
dreamzero_compile_components: true
dreamzero_max_sessions: 128
Key points:
host/port/master_portare filled at runtime bySGLangServerWorker(free ports allocated serially under a PortLock); do not set them in YAML;the top-level
ServerArgsfields map directly tosglang servearguments (backend,attention_backend,tp_size,num_gpus,dit_cpu_offload,cfg_parallel_degree,sp_degree, …);the
pipeline_configsub-block maps toDreamZeroPipelineConfigfields, named identically to the sglang side (cfg_scale,default_num_inference_steps,dreamzero_compile_components,dreamzero_max_sessions, …);all model paths point to
rollout.model.model_path; the Server loads the different model components per the checkpoint layout.
Model shape-related fields (num_frames, tile parameters, synthetic_*,
action_horizon, …) must remain consistent with the checkpoint training
configuration and cannot be changed arbitrarily based only on GPU memory
availability.
Model YAML#
The DreamZero model configuration is located at
examples/embodiment/config/model/dreamzero_5b.yaml. Fields directly related to SGLang evaluation
can be summarized as:
model_type: "dreamzero"
model_path: null
metadata_json_path: null
action_dim: 32
state_horizon: 1
action_horizon: 24
num_action_per_block: 24
max_action_dim: 32
max_state_dim: 64
target_video_height: 176
target_video_width: 320
action_head_cfg:
config:
num_frames: 33
tile_size_height: 34
tile_size_width: 34
tile_stride_height: 18
tile_stride_width: 16
tiled: false
The meanings of the main fields are as follows:
Field |
Meaning |
|---|---|
|
Lookup key for the adapter registry; must be |
|
Full checkpoint path; must be overridden in the evaluation YAML |
|
Dataset statistics used for state and action normalization and denormalization |
|
Model action width; |
|
Action horizon predicted by the Server in one request |
|
Number of actions used by each action block in the DreamZero DiT |
|
Video resolution used by the data transformations and Pipeline |
|
DreamZero network structure and video and tile parameters; these should usually remain consistent with the training checkpoint |
The values in the model configuration are defaults. The evaluation YAML can override these values, but
action_horizon, num_action_per_block, video dimensions, and model structure-related fields must match
the current checkpoint. For example, the LIBERO SGLang configuration in this section overrides the horizon from the default
24 to 16; this is a requirement of that evaluation checkpoint, not a general recommendation.
Detailed Evaluation YAML#
The complete example is located at
evaluations/libero/libero_spatial_dreamzero_eval_sglang.yaml. The configuration blocks are explained below.
Hydra defaults#
defaults:
- env/libero_spatial@env.eval
- model/dreamzero_5b@rollout.model
- override hydra/job_logging: stdout
hydra:
searchpath:
- file://${oc.env:EMBODIED_PATH}/config/
This composes the libero_spatial simulator configuration into env.eval and the
dreamzero_5b model configuration into rollout.model. run_eval.sh sets
EMBODIED_PATH.
Cluster and Runner Configuration#
cluster:
num_nodes: 1
component_placement:
env,rollout: all
runner:
task_type: embodied_eval
max_epochs: 1
only_eval: True
ckpt_path: null
Field descriptions:
component_placementspecifies how env and rollout are placed;task_type: embodied_evalselectsEmbodiedEvalRunner;only_eval: Trueis required, andSGLangEmbodiedWorkerasserts it;ckpt_pathcan benullin this path, and the Server loads weights fromrollout.model.model_path;The current script supports evaluation only, not training.
Environment Parallelism and Evaluation Steps#
env:
eval:
rollout_epoch: 1
total_num_envs: 128
auto_reset: True
ignore_terminations: True
max_episode_steps: 480
max_steps_per_rollout_epoch: 1920
group_size: 1
use_fixed_reset_state_ids: True
use_ordered_reset_state_ids: True
is_eval: True
total_num_envs is the total number of parallel environments and must be divisible by the actual number of environment Workers,
pipeline_stage_num, and group_size.
max_steps_per_rollout_epoch must be divisible by
rollout.model.num_action_chunks. The Worker calculates how many action requests are needed per epoch using the following
formula:
n_eval_chunk_steps = (
env.eval.max_steps_per_rollout_epoch
// rollout.model.num_action_chunks
)
In the example, 1920 // 16 = 120. num_action_chunks must be consistent with the action chunk length returned by one inference and
actually executed by the environment.
SGLang Worker Dispatch#
rollout:
rollout_backend: "sglang"
pipeline_stage_num: 1
return_logprobs: false
sglang:
serving_mode: "embodied" # rollout worker = SGLangEmbodiedWorker
server_type: "embodied" # server dispatch = embodied (via dispatch_launch)
launch_server: true # driver launches the server group
launch_router: false # no router (action endpoint not forwarded by router)
group_name: SGLangServerGroup
router_group_name: SGLangRouterGroup
rollout_backend: sglangselects the SGLang backend;serving_mode: embodiedselects the rollout worker =SGLangEmbodiedWorker;server_type: embodiedselects the server dispatch branch =embodied(VLA / diffusion, viasglang.multimodal_gen’sdispatch_launch).serving_modeandserver_typeare orthogonal: the former controls how the worker connects, the latter which sglang dispatch the server subprocess runs; both take effect within the sameSGLangServerWorkerclass — there is no longer a separate server class;launch_router: falseis required: the sglang router only forwards fixed LLM endpoints (/generate,/v1/chat/completions), not the dreamzero/v1/actions/generations, so the embodied path disables the router and rollout workers hit their rank-assigned server URL directly.
pipeline_stage_num participates in calculating the eval batch size for each rollout rank;
return_logprobs: false indicates that policy probabilities are not needed for evaluation.
Server Startup and Parallel Configuration#
rollout.sglang top level holds RLinf-private keys (HTTP client, parallelism,
launch toggles); the server sub-block holds the ServerArgs fields
forwarded to sglang:
rollout:
sglang:
tensor_parallel_size: 1
pipeline_parallel_size: 1
launch_server: true
launch_router: false
server_type: embodied
seed: 1140
server: # → ServerArgs.from_kwargs
backend: sglang
pipeline_class_name: DreamZeroPipeline
tp_size: ${..tensor_parallel_size}
num_gpus: 1
attention_backend: TORCH_SDPA
dit_cpu_offload: false
cfg_parallel_degree: 1
sp_degree: 1
pipeline_config: # → DreamZeroPipelineConfig
cfg_scale: 5.0
default_num_inference_steps: 16
dreamzero_compile_components: true
Top-level private-key fields:
Field |
Meaning |
|---|---|
|
TP size per server engine; the launcher packs hardware ranks into engines
of |
|
PP size per server engine |
|
Whether the driver launches the server group / router |
|
server dispatch branch: |
|
Random seed used for each action request |
The server sub-block fields are ServerArgs fields (backend,
attention_backend, tp_size, num_gpus, dit_cpu_offload,
cfg_parallel_degree, sp_degree, …); the pipeline_config sub-block
holds DreamZeroPipelineConfig fields (cfg_scale,
default_num_inference_steps, dreamzero_*, …). Refer to the
ServerArgs / DreamZeroPipelineConfig of the SGLang version in use for
the exact field meanings.
With multiple rollout ranks, launch_sglang_router_and_server packs the
hardware ranks into multiple server engines of
tensor_parallel_size Ă— pipeline_parallel_size and launches them in parallel.
The HTTP port and master_port are allocated by the worker’s PortLock as free
ports serially — do not set host / port / port_base /
master_port_base in YAML; this avoids concurrent ranks grabbing the same
port (an EADDRINUSE on master_port=30005 was seen before).
HTTP Client Configuration#
rollout:
sglang:
http_timeout_s: 600
http_max_retries: 5
http_retry_backoff_s: 1.0
These fields are read by SGLangEmbodiedWorker to create the
InferenceHTTPClient that sends requests to the server. Field
descriptions:
http_timeout_sis the timeout for a single action request;http_max_retriesis the number of retries for connection errors or retryable 5xx responses;http_retry_backoff_sis the base wait time for linear backoff.
Note
Embodied action requests always use msgpack (so ndarrays are not expanded
into enormous JSON lists for images / large batches); the worker calls
http_client.post(..., msgpack=True), and there is no longer an
http_payload_format config option.
DreamZero Model and Data Configuration#
rollout:
model:
model_type: "dreamzero"
precision: bf16
model_path: /path/to/RLinf-DreamZero-WAN2.2-5B-LIBERO-SFT-repacked
metadata_json_path: /path/to/metadata.json
embodiment_tag: "libero_sim"
action_horizon: 16
num_action_chunks: 16
num_action_per_block: 16
target_video_height: 160
target_video_width: 320
Among these fields:
model_pathis the checkpoint loaded by SGLang Server;metadata_json_pathprovides normalization statistics from the training data. If it is not explicitly specified, the code only attemptsmodel_path/experiment_cfg/metadata.json;embodiment_tagselects the observation layout, modality transformations, action postprocessing, and embodiment id;action_horizonis the action length generated by the model at one time;num_action_chunksis the action length RLinf sends to and executes in the environment each time;num_action_per_blockis a DreamZero network structure parameter;target_video_heightandtarget_video_widthmust be consistent with the checkpoint and Server Pipeline.
All three action lengths in the current example are 16. If a new checkpoint’s generation horizon differs from the chunk that is actually
executed, the Server output, Policy slicing, and environment execution strategy must all be confirmed together; changing only
one of these fields is insufficient.
Generating Metadata#
DreamZero’s observation normalization and action denormalization depend on dataset metadata. The LIBERO example can use:
python toolkits/lerobot/generate_dreamzero_metadata.py \
--preset libero_sim \
--dataset-root /path/to/libero \
--output-metadata /path/to/metadata.json
After generation, write the path to rollout.model.metadata_json_path. The metadata must come from data and an embodiment matching the training
checkpoint; using incorrect statistics may not cause an immediate error, but it results in incorrect action
scales.
Running Evaluation#
After preparing the DreamZero dependencies, an SGLang environment that supports DreamZeroPipeline, the checkpoint, and
metadata, run the following from the repository root:
export DREAMZERO_PATH=/path/to/DreamZero
bash evaluations/run_eval.sh \
libero \
libero_spatial_dreamzero_eval_sglang \
rollout.model.model_path=/path/to/RLinf-DreamZero-WAN2.2-5B-LIBERO-SFT-Diffusers \
rollout.model.metadata_json_path=/path/to/metadata.json
For the detailed DreamZero SGLang evaluation workflow, see DreamZero SGLang Evaluation.
For initial joint debugging, the number of environments can be overridden:
bash evaluations/run_eval.sh \
libero \
libero_spatial_dreamzero_eval_sglang \
rollout.model.model_path=/path/to/RLinf-DreamZero-WAN2.2-5B-LIBERO-SFT-Diffusers \
rollout.model.metadata_json_path=/path/to/metadata.json \
env.eval.total_num_envs=4
run_eval.sh sets EMBODIED_PATH and adds DREAMZERO_PATH to
PYTHONPATH. Make sure DREAMZERO_PATH points to the DreamZero
code directory containing the groot package.
Common Issues#
Worker Is Not SGLangEmbodiedWorker#
Check whether both of the following are set:
rollout:
rollout_backend: sglang
sglang:
serving_mode: embodied
sglang adapter Not Registered#
Confirm that the following three names are identical and that the adapter is
registered in _register_builtin_sglang_adapters() inside
rlinf/models/embodiment/sglang_adapter.py:
SupportedModel.register("dreamzero")
register_sglang_adapter("dreamzero", _build_dreamzero_sglang_adapter, force=True)
rollout.model.model_type: dreamzero
Server Fails to Start#
The logs print a multimodal_gen sglang serve: launching in-process ... line
and the server subprocess output (streamed straight to the Ray actor’s
stdout/stderr). Check the following first:
Whether the current SGLang installation contains
DreamZeroPipelineand the action endpoint;Whether the checkpoint path and component layout are correct;
Whether
num_gpus,tp_size, andsp_degreematch the available GPUs;Whether the port is occupied (HTTP/master_port are auto-allocated by PortLock but may still clash with external processes);
Whether enough startup wait time is given for first-time compilation and weight loading.
Request to Local Server Times Out#
NO_PROXY must include 127.0.0.1,localhost; otherwise, /health and action requests may
be sent to an upstream proxy. The Worker sets it automatically when starting a local Server; when starting one manually or testing the Client separately,
you need to check the proxy environment variables yourself.
Incorrect Action Shape or Scale#
Check the following in order:
Whether the Server output is
[B, H, max_action_dim];Whether
action_horizon,num_action_chunks, andnum_action_per_blockare consistent with the checkpoint;Whether
embodiment_tagselects the correct data transformation;Whether
metadata_json_pathcomes from matching training data;Whether the action dimensions after
unapplymeet the environment’s requirements;Whether the image resolution and view order are consistent with training.
Abnormal GPU Memory Usage#
Confirm that the sglang adapter does not import and create a local large DreamZero model. The model can only be loaded by
sglang serve. Also check max_sessions, eval batch size, compilation options, and
parallel configuration; DreamZero sets max_sessions to the current Worker’s eval batch size by default, and
increasing the number of parallel environments also increases the Server-side cache requirements.