> ## Documentation Index
> Fetch the complete documentation index at: https://docs.freesolo.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Training

> Write a config, submit a managed run, and follow it to completion.

A training run is one TOML config, submitted with `flash train`. Flash runs the
job on managed infrastructure, supervises it, and streams checkpoints and logs
back to you. The config and run lifecycle follow; the
[configuration reference](/reference/configuration) lists every field.

## Pick a base model

Flash trains a [LoRA adapter](/how-flash-works) on top of a supported base
model. List base model ids and their parameter sizes
([Supported models](/reference/models) covers algorithms, reasoning, and
pricing):

```bash theme={null}
flash models
```

Set your choice at the top of the config:

```toml theme={null}
model = "Qwen/Qwen3.5-4B"
# model_revision = "main"  # optional hugging face branch, tag, or commit
seed = 42
```

`model_revision` pins all student-model loads to one Hugging Face revision. An
empty or omitted value uses the model's default revision. `seed` controls the
run's deterministic training order and defaults to `42`.

## Choose a training algorithm

<CodeGroup>
  ```toml SFT theme={null}
  algorithm = "sft"
  ```

  ```toml GRPO (RL) theme={null}
  algorithm = "grpo"
  ```

  ```toml OPD (distillation) theme={null}
  algorithm = "opd"
  ```
</CodeGroup>

* **`sft`**: supervised fine-tuning, when you already have the answers. The
  model imitates the prompt/answer pairs in your environment's [dataset](/guides/datasets).
* **`grpo`**: reinforcement learning, when there's no fixed answer to copy.
  Your environment's reward scores each completion.
* **`opd`**: on-policy distillation, when a stronger model already does the task.
  A managed teacher, **GLM 5.2 by default** or another selected with
  `teacher_model`, grades your model's own completions token by token. Training
  pulls your model toward that teacher without using answers or a reward as the
  training signal.
  **Warm-start from an SFT adapter** (`init_from_adapter`) for best results; a cold
  OPD run tends to underperform SFT. OPD supports single- and multi-turn
  environments, but not tool-calling ones. Teacher access is managed and teacher
  tokens are not billed to you.

All three are driven by the same [environment](/guides/environments/overview), and
`algorithm` defaults to `sft` when omitted. See
[how Flash works](/how-flash-works) for the difference.

## Check the teacher before OPD

OPD pulls your model toward the teacher, so the teacher's competence on your task
roughly sets the ceiling. Treat a teacher evaluation as a precondition for the
run. Flash does not automate this comparison. Use your evaluation harness, or have
the coding agent follow the scaffolded
[`TRAINING.md`](/directory-structure#trainingmd), to call the teacher on held-out
prompts and score its transcripts with the same scorer you use for your model.

1. Keep a held-out split outside training, then run both the selected teacher and
   your current model on it.
2. Compare their scores, then read several trajectories from both. A score alone
   can hide a teacher that reaches the right answer for the wrong reason.
3. Confirm that the teacher clearly wins and that your environment rewards the
   behavior you want to transfer.

| What you find                                                                 | Next step                                                |
| ----------------------------------------------------------------------------- | -------------------------------------------------------- |
| The teacher clearly outperforms your model, and the scores match what you see | Use OPD                                                  |
| The teacher is no better than your model                                      | Use GRPO or train on curated answers with SFT            |
| The teacher looks better, but the environment does not reward the improvement | Fix the environment, then repeat the held-out evaluation |

The environment score does not drive OPD's token-level updates. It tells you
whether the behavior you care about improved, so a broken evaluation leaves you
unable to judge the run.

### Bound reasoning before long rollouts

If the teacher over-reasons in the held-out evaluation or OPD rollouts hit the
length limit, put a hard, specific budget in the environment's system prompt:

```text theme={null}
Reason in at most two or three sentences, then act.
Once you have started, do not reconsider.
```

Avoid a vague instruction such as "be brief." It can shorten the typical response
while making the longest responses even longer. Re-run the held-out evaluation
after changing the prompt. See [Troubleshooting](/reference/troubleshooting) if
rollouts still fail to terminate.

## Anatomy of a config

```toml theme={null}
model = "Qwen/Qwen3.5-4B"
# model_revision = "main"            # optional hugging face branch, tag, or commit
algorithm = "sft"
seed = 42
# thinking = true                     # opt into reasoning mode

[environment]
id = "your-org/your-env"

[train]
epochs = 3                            # passes over retained rows or prompts
max_examples = 1000                   # sft keeps the first n rows before seeded shuffle
max_steps = 100                       # exact update horizon when positive
save_at_steps = [25, 50, 100]         # mandatory saves; requires positive max_steps
lora_rank = 32
lora_alpha = 64
# learning_rate = 1e-4
# batch_size = 8
# group_size = 8                      # grpo: completions sampled per prompt
# max_completion_tokens = 512         # grpo/opd: generated tokens per rollout turn
# max_context_tokens = 4096           # total context cap, including sft
# init_from_adapter = "<sft-run-id>"  # grpo/opd: omit lora rank and alpha
# teacher_model = "glm-5.2"           # opd: managed teacher
# structured_outputs = '{"type":"object","properties":{"answer":{"type":"string"}},"required":["answer"]}'

[wandb]
# project = "my-project"              # optional weights & biases logging
```

To force every GRPO or OPD rollout into valid JSON, a regex, or a fixed choice
set, so your reward scores content instead of formatting, set
`structured_outputs`. See the [Structured outputs](/guides/structured-outputs)
guide.

## Control the update horizon and checkpoints

For SFT, GRPO, and OPD, a positive `train.max_steps` is the exact number of
optimizer updates. If it is absent or non-positive, Flash derives the update
count from epochs, retained examples, batch size, and the recipe.

Use `train.save_at_steps` when specific checkpoint boundaries matter:

```toml theme={null}
[train]
max_steps = 100
save_at_steps = [25, 50, 100]
```

The list must be strictly increasing and positive, requires positive
`max_steps`, and cannot contain a step beyond it. It suppresses `save_every`,
and every requested save is mandatory. Without `save_at_steps`, periodic
`save_every` uploads block training while attempted but remain best-effort after
bounded retries. Use `save_at_steps` for required durable boundaries.

For SFT, `max_examples = N` retains the first N rows in file order before the
seeded shuffle. SFT also honors `max_context_tokens` for the rendered sequence.

## Warm-start safely

`init_from_adapter` continues a source adapter in a new GRPO or OPD run. The
source can be a finished SFT run or a saved checkpoint. Its LoRA rank and alpha
are authoritative, so omit both `lora_rank` and
`lora_alpha`. The server resolves them during `--dry-run` and real submit; local
`--cost` may warn and estimate with defaults.

If you set `model_revision`, the source and target revisions must match exactly.
Use server-side `--dry-run` to resolve and validate the source.

## Infrastructure is managed

You choose the model, algorithm, environment, and training settings. Flash
selects suitable infrastructure by default. For controlled runs, `[gpu]` can pin
a provider and an active validated GPU class from `flash gpus`; those constraints
also apply to retries and cost estimates. Artifact storage remains managed.

## Validate before you submit

`--dry-run` is authenticated and server-side. It runs submit-time preflights,
including warm-start resolution, creates a run with `state=dry_run`, and reports
client/server `[train]` schema differences. It allocates no GPU and charges
nothing:

```bash theme={null}
flash train config.toml --dry-run
```

Use `--cost` separately for the local estimate.

## Submit the run

```bash theme={null}
flash train config.toml
```

By default `flash train` follows the logs until the run finishes. Useful flags:

| Flag                  | Effect                                                         |
| --------------------- | -------------------------------------------------------------- |
| `--background`        | Submit and return immediately instead of following logs        |
| `--dry-run`           | Run authenticated server submit preflights; no GPU or charge   |
| `--cost`              | Print the local pre-flight USD cost and exit (no submit)       |
| `--set key=value`     | Override a config value (repeatable)                           |
| `--config other.toml` | Deep-merge additional TOML for config composition (repeatable) |

```bash theme={null}
# override values at submit time
flash train config.toml --set train.epochs=3 --set train.lora_rank=16
```

## Cost and billing

Before submitting, Flash checks your org's prepaid balance against the pre-flight
estimate. A successful run bills at the quoted Flash cost. A run cancelled after
training starts is repriced to the steps it reached. Setup time is reported but
not billed. Preview the estimate before you submit:

```bash theme={null}
flash train config.toml --cost
```

See [Cost and billing](/reference/cost-model) for what affects cost, how to read
the preview output, and how cancellations are repriced.

## Monitor a run

`Ctrl-C` during `flash train` detaches you. The run keeps going on Freesolo.

```bash theme={null}
flash runs                # all your runs: state, cost, model
flash status <run-id>     # status JSON, including the cost record
flash status <run-id> --follow  # poll status until completion, without replaying logs
flash log <run-id>              # print the full log snapshot
flash log <run-id> --follow     # stream logs until completion
flash cancel <run-id>     # cancel a run
```

## After training

When a run reaches `done`, serve it with
[`flash deploy`](/guides/deploy-and-chat) and talk to it with `flash chat`.

<Note>
  Deploy or
  [export](/guides/deploy-and-chat#export-to-your-own-huggingface-repo) a run
  you want to keep. Freesolo's managed storage garbage-collects a run's
  checkpoints and final adapter about **7 days** after its last activity when
  the run was never deployed. A deployed run, or one that another run
  warm-started from, is kept. Exporting copies the adapter into a HuggingFace
  repo you own.
</Note>

## Next steps

<CardGroup cols={2}>
  <Card title="Deploy & chat" icon="comments" href="/guides/deploy-and-chat">
    Serve a finished run and talk to it.
  </Card>

  <Card title="Configuration reference" icon="gear" href="/reference/configuration">
    Every field you can set in a training config.
  </Card>
</CardGroup>
