Format
Veri runs reward functions in thetrl shape, the format the production GRPO runner uses.
At submit, the platform checks that each source parses as Python and defines a function; a violation rejects the job with HTTP 400 before anything is billed.
Loading and invocation happen in the open-source runtime: see
load_reward_function in training_runtime.py (and score_episode in harness_rollout.py for how harness trajectories are scored) if you need to check exactly how your function is called.
TRL format
Receives a batch of completions, returns one score per completion.completions— list of strings OR list of message-dict lists (depending on how the runner formats prompts)answer— list of ground-truth strings (from the dataset’sanswercolumn)- Return — list of floats, same length as
completions
Attach it to a job
The reward rides the job submission itself. Pick your surface:veri jobs create configs/train.toml reads [reward].file, or override it inline with --reward ./reward.py (a relative path resolves against the config file’s directory, like [reward].file). The CLI runs an AST lint before submitting (the file parses as Python and defines at least one function), so a broken file fails locally instead of at the API.
A method=grpo or method=grpo_harness job requires a reward. sft_text and dpo jobs must omit it (the dataset is their training signal), and so must custom_script jobs, which own their training loop.
The job response carries reward_count (the number of attached sources; null for reward-free methods).
Limits: up to 8 sources per job, 256 KiB each, and every source must define a function. Violations are HTTP 400 at submit.
Where rewards run
Your reward is imported and called inside the training process on the GPU machine. It can use the Python standard library and the packages already installed on the training image; there is no way to declare extra dependencies. There is no separate sandbox and no per-call timeout: the machine has network access, and a reward that hangs (for example on a slow network call) stalls the whole job. Keep rewards fast and deterministic, and avoid network calls. An exception raised by your reward fails the job witherror.code = "training_error".
Composing rewards
A common pattern is to weight multiple signals:[0, 1] is conventional). GRPO normalizes scores within a group, so the absolute scale matters less than the spread.
Multiple weighted reward functions
Instead of summing signals inside one function, you can attach several reward sources and let GRPO combine them with weights. TRL’s GRPOTrainer scores each completion with every function and sums the results, scaled byreward_weights. This keeps each signal in its own file (independently testable) and lets you retune the mix without editing code.
Each function has the standard trl signature and returns one score per completion. Pass the sources and matching weights:
reward_weights is optional; omit it to weight every function equally. When provided, its length must match reward_sources (the SDK and API reject a mismatch). A single reward_source still works for the one-reward case.
Viewing a job’s reward
Every job keeps the exact source it was submitted with. Click a training job on the dashboard to view the reward source it was submitted with, or fetch it programmatically:Shaped rewards for harness jobs
Harness-in-the-loop jobs score the trajectory’s final assistant message by default, the deploy-aligned choice, since at inference time the final answer is all that matters. When you need more signal (partial credit for fetching the right page, penalties for invalid tool calls), declare atrajectory parameter and the platform passes the full message history of the rollout’s final turn (protocol-shaped dicts, including tool_use / tool_result content), one history per completion:
trajectory are called exactly as before; the parameter is opt-in.
One sharp edge with chatty agent runtimes (the Claude Agent SDK especially): because the default scores only the final message, instruct your harness to put the answer there (“finish with a last line of exactly ANSWER: <url>”) or a correct mid-trajectory answer can score zero.
Where to go next
GRPO algorithm
What the score actually does inside the training loop.
Submit a job
Wire
reward_source into training_jobs.create.Quickstart
End-to-end with the example math reward.

