load_environment() function returns the
dataset, prompt builder, and reward logic that Flash uses for SFT, GRPO, and OPD, and
local validation.
Task records
Author dataset rows withinput and output:
The algorithm decides which column the model learns from. SFT trains
directly on
output, the gold answer. GRPO and OPD use only input: the
model generates its own answers from the prompt, and learns from your reward
(GRPO) or a teacher’s token-level grading (OPD). output is optional for both.
GRPO reads it only if your score_response uses it as a reference; OPD ignores
it entirely, since the teacher, not your reward, is the training signal.
load_task_examples(...) accepts a local file path or an iterable of records.
- File formats:
.jsonl,.json,.csv,.txt, or.bson. - Field mapping:
input->example.input,output->example.output,metadata->example.metadata. - Original row: the untouched record stays available as
example.record.
dataset/train.jsonl
input plus an optional output; alternate prompt or target
key names are not accepted. Records are canonicalized to exactly
input/output/metadata.
Message-shaped SFT targets
For SFT,output is the gold completion appended after the environment’s
prompt messages. A scalar output becomes one assistant message. To teach a
multi-turn trajectory or native tool calling, set output to
{"messages": [...]} or a bare list of chat messages. Flash preserves those
assistant, tool-call, tool-result, and reply messages when it builds the SFT
example.
dataset/train.jsonl
output is validated rather than coerced, so a malformed
trajectory fails instead of collapsing into one bare turn:
{"messages": ...}must hold a list, and every entry in it must be an object.{"messages": [...]}may not carry sibling keys - that shape is exactly one key.- A list mixing message objects with non-objects is rejected.
output is still rendered into a single assistant message, so the
strictness applies to targets that look like chat messages, not to plain answers.
Use Environment.sft_completion(example) when your environment must
synthesize or transform the gold completion before SFT.
Multi-turn SFT masks observations
For message-shaped multi-turn targets, Flash supervises authored assistant bodies and masks interleaved user, tool, and environment observations out of the loss. The model learns its replies without being trained to reproduce what the environment or tool returned. The run logs how many rows used role-aware assistant-body masking. If a rendered transcript is not parseable as ChatML, Flash keeps the row with completion-only fallback and prints a warning: the completion remains supervised, but masking of interleaved observations is not proven. Treat that warning as a dataset or template issue to inspect rather than assuming the non-assistant turns were excluded.Validate thinking-model SFT targets
SFT on a thinking model (thinking = true) expects each gold completion to
literally contain a <think>...</think> block. Catch missing blocks locally
before submitting a run:
UserWarning naming the
first few. Unlabeled records (no output) are skipped.
Image inputs
Every catalog model is multimodal, so a prompt can include images and Flash trains and serves on them. Images belong in the prompt, not in the gold completion: an image inside an SFToutput message is rejected.
Build a multimodal prompt the OpenAI way: a user message whose content is a
list of parts, mixing text with one or more image parts. Flash accepts image,
image_url, and input_image parts, and each image source can be a data:
URI, raw bytes, a PIL image, or a package-root-relative path under dataset/
(e.g. dataset/photo.jpg). Remote http(s) URLs are not accepted; see
below:
environment.py
image (single) or images (a list).
These are the one exception to the field whitelist above: the multimodal loader
reads them from the original row (example.record) and appends them to the
first user message, so they survive even though they are not part of the
canonical input/output/metadata mapping.
Training image limits
The limits apply per training example, across prompt content blocks and top-levelimage or images fields together:
These are training limits. Serving has a separate limit of four images per
request; see Send images.
Remote URLs
Remotehttp(s) image URLs are not supported, and there is no flag to
enable them: Flash never fetches a user-supplied URL at training time, so the
training input stays fixed at submit. Include the image in the environment
package as a relative path, or embed it as a data URI. A relative path is
resolved from the package root and must stay inside dataset/
(e.g. dataset/photo.jpg).
Algorithm boundaries:
- SFT: Images may appear only in the prompt. An image in a gold
outputmessage is rejected; the target remains text or tool messages. - GRPO: Images from the initial prompt persist as conditioning media for every
turn of a multi-turn rollout. A later image returned by
step_episode()is rejected because dynamic per-turn media is not supported. - OPD: Image prompts require a vision-capable
teacher_model, and image-bearing OPD is single-turn only. A text-only teacher or a multi-turn image environment is rejected rather than distilling without the intended pixels. See image-bearing OPD.
dataset/ so they upload with the environment (see
What gets uploaded).
Load sidecars
Read packaged files relative to__file__ so paths work locally and in a managed
run.
environment.py
build_prompt_messages, score_response) is covered
in Environments.
Then select the split from your Flash config:
[environment.params] values are passed to your load_environment(**kwargs).
split is also honored by Flash itself: for an environment packaged with
dataset files, split = "eval" selects dataset/eval.jsonl (or .json) as
the dataset Flash trains on: SFT targets and GRPO problem selection alike. If
the environment packages a default train split but the requested split file
does not exist, the run fails at load time instead of silently falling back to
train.jsonl. An explicit dataset_path param takes precedence over split.load_environment() builds self.dataset in code, those rows are what
Flash trains on - the packaged file is only the fallback for an environment that
exposes no dataset of its own. Filtering, subsampling, augmentation, and
deduplication done in Python are honored rather than overwritten by a re-read of
the file. That holds even when your filter matches nothing: an empty in-code
dataset fails rather than quietly falling back to the unfiltered file and
training on the rows you meant to exclude. An explicitly selected dataset_path,
records, or side split still wins over an in-code dataset.
What gets uploaded
For a local environment directory,flash env push includes:
environment.py, always at the artifact root.- Sibling Python helper files.
- Sidecar directory named
dataset. - Common sibling data files such as
.jsonl,.json,.csv,.txt,.md,.parquet,.tsv,.yaml, and.yml.
.env files and files
matching *.key, *.pem, *.pfx, *.p12, credentials*, or SSH key names
(id_rsa*, id_ed25519*, and similar) are excluded. Keep the artifact small:
environment uploads are capped at 64 MB compressed, 256 MB uncompressed, and
5000 files. For large corpora, keep the data in an external store and pass the
identifier or URL through [environment.params].
When you push a single .py file (or a folder with just one top-level .py),
only that entrypoint, a sibling README.md/TRAINING.md, and any dataset/
tree are packaged, and sibling helper modules are not. An evaluations.py is
not packaged in single-file mode either; push the folder if you want
flash env eval suites to travel with the
environment.
Next steps
Single-turn environments
Load these records inside an environment class.
Training
Train SFT, GRPO, or OPD on your dataset.