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. 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 (or environments, which is mutually exclusive with reward sources). sft_text, dpo, sft_video_gen, and custom_script jobs must omit it: the dataset is their training signal.
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.
Sandbox + limits
Reward functions run inside the training runner. They have:- No network egress — calls to external APIs will silently fail or hang
- Standard library + the runner image’s pre-installed packages only — no
pip installat runtime - A timeout per rollout batch — exceeding it fails the job with
error.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.

