一键导入
model-support
Use when adding, debugging, validating, or productionizing new model support in modal-training-gym, especially Slime recipes and model configs.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when adding, debugging, validating, or productionizing new model support in modal-training-gym, especially Slime recipes and model configs.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
This skill should be used when the user asks to "check the progress of a run", "what step is run X on", "is my training run stuck", "what is run <id> doing", "grab the app logs for a run", "how far along is the rollout", or otherwise wants to know the live status, current step, current phase, or blocker of a modal-training-gym training run given a run id (or partial id / wandb id / Modal app id).
Runbook for launching, monitoring, and debugging training jobs on Modal: entrypoint discovery, detached app workflow, log filtering, container inspection, volume state, image build behavior, and debugging strategy. Use when running modal run, checking app status, reading logs, or troubleshooting a Modal training job.
One-stop reference for the modal-training-gym repo: package layout, core abstractions (ModelConfig, DatasetConfig, framework two-class split, build_app, cloudpickle caller resolution), the tutorial generator system, model catalog, tools/ directory, and common gotchas. Use when working with tutorials, models, frameworks, or any code in this repository.
Tiered validation pipeline for checking whether tutorials and examples still run as documented: Tier 0 (local compile), Tier 1 (cheap drift checks), Tier 2 (scheduled smoke on Modal), Tier 3 (full multi-node validation). Covers discovery, pass criteria, and failure recording. Use when validating, testing, or checking tutorials and examples for drift.
| name | model-support |
| description | Use when adding, debugging, validating, or productionizing new model support in modal-training-gym, especially Slime recipes and model configs. |
When asked to add a new model example to SlimeRecipe, you should output artifacts in a temporary directory in .gym/new_models/[model_name]/ folder. Once you are finished, add the finished config to the recipes folder.
Always read the common gotchas.
First try looking for the existing model running on slime. You can find examples in slime model scripts or slime examples. If you cannot find an existing model, find the model with the most similar architecture. Reference huggingface for model architecture.
Check image/version compatibility FIRST — it is the most common blocker. The gym pins the slime image by digest (SLIME_IMAGE in modal_training_gym/frameworks/slime/launcher.py). A model added to slime after that image was built will not run on it. Verify:
curl -s "https://api.github.com/repos/THUDM/slime/commits?path=scripts/models/<model>.sh&per_page=5" (also check slime_plugins/models/... and any slime_plugins/mbridge/...).SLIME_IMAGE digest to its nightly tag/date on Docker Hub:
curl -s "https://hub.docker.com/v2/repositories/slimerl/slime/tags?page_size=30&ordering=last_updated".slimerl/sglang:<tag>; new attention backends (e.g. NSA/DSA) require a matching sglang bump, so check the Dockerfile at both the pinned commit and the model's support commit.SLIME_IMAGE is a shared-infra change (re-bases every slime recipe) → flag it for the user and smoke-test an existing small recipe (Qwen3-0.6B) after the bump. A per-recipe base image override is NOT cleanly possible: the sglang binary lives in the base image, and image_overlay / image_run_commands / image_env / local_slime only layer on top of the fixed SLIME_IMAGE.Then, output your first artifact, which is a file called model_setup.md, containing:
SLIME_IMAGE? If so, note the required image bump + sglang version.Scale/cost gate. Very large models (700B+ needing dozens of nodes) make the Phase-2/3 runs expensive, cluster-reserving operations. Do not launch them without explicit user sign-off on GPU budget and cluster availability; write the recipe + config first (Phases 1 & 4) and leave the live run to the operator if unconfirmed.
Output a slime config you believe will work, and kick off a run with 1 single step. Check this step works e2e. Output the config in configs folder directly, and keep track of progress in progress_log_[attempt_count].md.
While tracking the progress, also make sure the timing lines up with your expectations in the model_setup.md artifact.
If this step does not work, go back to phase 1: what assumptions did you make in phase 1 that were incorrect and caused this? Output an artifact if it fails with failure_analysis_[attempt_count].md.
Record how long the step took, and how long each substep took. Make sure the model parser works and it is not generating gibberish.
Run it for more than 1 step, and kick off a run for 10 steps. Make sure the training does not fail. If it fails, create a minimal repro of the problem and work to address.
Record how long the step took, and how long each substep took. Make sure the model parser works and it is not generating gibberish.
Create a doc describing the slime config changes, and justify any patches you have made. If it's possible to not patch, do not patch.
Naming convention: For the model name in artifacts, it should be _ separated by model family identifiers and replacing . for versioning (e.g. Qwen3_4b, Qwen3_6_35b, Kimi_K2_6).
Slime by default use mbridge (megatron_to_hf_mode="") instead of bridge (megatron_to_hf_mode="bridge"), which requires it to preconvert the weights. To determine if we should use bridge mode or mbridge, look upstream at the slime codebase at what was used for similar models.
--max-tokens-per-gpu is a flag for training, whereas --rollout-max-response-len is a flag for rollouts.
If it is a large MoE, you may need --optimizer-cpu-offload, --use-precision-aware-optimizer, and --overlap-cpu-optimizer-d2h-h2d
SlimeRecipe.cli_args emits --<field-name-with-dashes> <value> for every dataclass field not listed in _SLIME_SKIP (recipe.py). So the way to add an arbitrary slime/sglang flag is simply to declare it as a field on your recipe subclass — no edits to recipe.py or the launcher. glm_4_7.py and qwen3_6_35b_long_context.py do exactly this for their sglang_* and perf flags. Rules cli_args follows:
True → bare flag (--foo); False / None / "" → omitted entirely. So default an unwanted flag to None/False/"".list → --foo a b c.YAML_CONFIG_FIELDS (eval_config, extra_config, sglang_config) may be passed as a dict — prepare_slime_config materializes it to a YAML file at runtime and rewrites the value to the path (this is how SGLang PD-disaggregation server_groups are supplied). JSON_CONFIG_FIELDS (train_env_vars, apply_chat_template_kwargs, multimodal_keys) are passed as JSON._SLIME_SKIP (e.g. slime_model_script, megatron_conversion_hf_checkpoint, environment) are launcher instructions, not CLI flags — they won't appear in cli_args output. That is expected, not a bug.slime_model_script vs. ModelArchitectureWhen a model's args aren't representable in ModelArchitecture (DSA, MLA q/kv-lora, --spec ..., --allgather-cp, --enable-experimental, exotic MoE routing), set slime_model_script = "scripts/models/<model>.sh". The launcher then sources that script and passes ${MODEL_ARGS[@]}, and recipe._model_to_fields is skipped — the upstream args are used verbatim. This mirrors GLM_4_7_Recipe. The ModelArchitecture on the model class becomes informational (still useful for the num_experts ÷ expert_model_parallel_size validator).
get_checkpoint_conversion_policy (modal_helpers/utils.py) decides the HF→torch_dist conversion layout. Gotchas:
decoder-first/last-pipeline-num-layers, mtp-num-layers, make-vocab-size-divisible-by) — never EP/ETP. torch_dist is reshardable, so training EP can differ from conversion; the model reloads fine. (This is why GLM_4_7/GLM_5_2 convert without an explicit expert-parallel size.)decoder_first/last_pipeline_num_layers pair shared between conversion and training. For models with pipeline-stage-placement assertions (e.g. DSA cross-layer index sharing requires each PP stage to start on a computing layer), keep conversion PP == training PP so the same split is valid for both. Overriding only conversion PP (conversion_tensor_model_parallel_size / conversion_pipeline_model_parallel_size) will pass a first/last split that no longer sums to the layer count.tp==1 and pp==1 and mtp_num_layers, conversion runs single-rank (world=1) to avoid corrupting the sharded state dict with the MTP head's duplicated embedding.Some models train in BF16 but roll out in FP8 (separate HF repos). The launcher's download step only calls model.download(), yet both megatron_conversion_hf_checkpoint (BF16) and hf_checkpoint (FP8) are later resolved with local_files_only=True. So override the model's download() to fetch every repo the recipe references (see GLM_5_2.download()), or a later step fails with a cache miss.
Do NOT blindly copy GLM_4_7's _disable_mtp_in_config (it zeroes num_nextn_predict_layers). That is a workaround for a PP>1 embedding collision in a model that does not use EAGLE. If the model uses its MTP layer for EAGLE spec decoding (--sglang-speculative-algorithm EAGLE), you must keep MTP — zeroing it breaks the draft model.
Wiring a new <Model> + <Model>_Recipe requires edits in all of:
modal_training_gym/common/models/<model>.py + export in common/models/__init__.py (import + __all__).modal_training_gym/train_recipes/slime_recipe/<model>.py + export in slime_recipe/__init__.py (import + __all__).modal_training_gym/__init__.py: add to _EXPORTS (lazy map) and __all__.SlimeRecipe.get_base_recipe (recipe.py): add the model_name → Recipe() branch.Verify with: uv run python -m compileall, uv run ruff check <files>, and a quick python -c "from modal_training_gym import <Model>, <Model>_Recipe; r=<Model>_Recipe(); print(r.gpu_allocation.summary())" — instantiating the recipe runs the GPU-allocation and parallelism validators, catching bad TP/PP/EP/node math before any Modal run.