Getting started
Modal provides many ways to get started with training.
The easiest way is to use Modal Dojo, an open-source library that gives you the building blocks, tuned defaults, and observability you need for easy, production-grade LLM training.
For a Tinker-compatible API, you can deploy a Spindle server. And when you need maximum control over your stack, you can bring your existing training code and infrastructure to a Clustered Function.
Here, we walk through how to start training with Modal Dojo. See here for a more fully-fledged example.
Run your first example
Install the package:
uv add 'modal-dojo @ git+https://github.com/modal-projects/modal-dojo.git'Set up the dashboard:
modal-dojo setupAnd empower your agents with the skill bundle:
modal-dojo skills installThen, it’s as easy as:
import re
from modal_dojo import (
HuggingFaceDataset,
Qwen3_5_4B,
Qwen3_5_4B_Recipe,
TrainConfig,
)
model = Qwen3_5_4B()
async def gsm8k_rm(args, sample, **kwargs) -> float:
text = model.parse_response(sample.response or "").content
boxed = re.findall(r"\\boxed\{([^}]+)\}", text)
pred = boxed[-1] if boxed else (re.findall(r"-?[\d,]+(?:\.\d+)?", text) or [""])[-1]
try:
return float(float(pred.replace(",", "")) == float(sample.label))
except ValueError:
return 0.0
config = TrainConfig(
model=model,
dataset=HuggingFaceDataset(
hf_repo="skrishna/gsm8k_only_answer",
hf_split="train[:120]",
input_column="text",
output_column="label",
input_format="text",
),
recipe=Qwen3_5_4B_Recipe(
custom_rm_function=gsm8k_rm,
),
)
if __name__ == "__main__":
run = config.launch()
print(run.training_run_id)See the documentation for more information.