Chapter 18 · Section 18.3 · 55 min

Verifiable rewards

In late 2024 the Tulu 3 team at the Allen Institute gave a name to something several labs were already doing. Take prompts whose answers can be checked by a program, such as math problems with known answers or instructions with checkable constraints like "use fewer than 50 words". Sample a response, run the checker, and give a reward of 10 if it passes and 0 if it does not. Train with RL. They called it reinforcement learning with verifiable rewards (RLVR), and they found that it improved GSM8K, MATH, and IFEval scores on top of an already strong post-trained model (Lambert et al. 2024). Two months later, DeepSeek-R1 showed what the same idea does at scale (§18.5).

The appeal is that a program cannot be flattered. A learned reward model is a neural network with blind spots, and RL against it finds them (§16.5). DeepSeek gave exactly this reason for using no neural reward model in R1-Zero, writing that "the neural reward model may suffer from reward hacking in the large-scale reinforcement learning process".

But a program can be wrong. RL is an optimizer that will find every input on which your checker says yes and the truth says no, and the checker is the entire specification of what you want. This section builds checkers for math and code, shows how policies learn to fool them, and turns that into a short engineering discipline for graders you can trust.

The objective

Write R(x,y)∈{0,1}R(x, y) \in \{0, 1\} for the verifier's verdict on response yy to prompt xx. RLVR maximizes

J(θ)=Ex∼D Ey∼πθ(⋅∣x)[R(x,y)]−β Ex[DKL(πθ(⋅∣x) ∥ πref(⋅∣x))],J(\theta) = \mathbb{E}_{x\sim\mathcal{D}}\,\mathbb{E}_{y\sim\pi_\theta(\cdot\mid x)}\big[R(x, y)\big] - \beta\, \mathbb{E}_{x}\Big[D_{\mathrm{KL}}\big(\pi_\theta(\cdot\mid x)\,\Vert\,\pi_{\text{ref}}(\cdot\mid x)\big)\Big],

the KL-regularized objective of §15.7 with a program in place of the reward model, where πref\pi_{\text{ref}} is the starting model and β≥0\beta \ge 0 sets how far the policy may drift (several recipes set β=0\beta = 0, as §18.4 discusses). With a 0/1 reward the first term is exactly the average pass@1 over the prompt distribution, the quantity §18.2 called p(x)p(x), averaged over xx. In plain words, RLVR directly maximizes the probability of a correct answer, which is the one number a deployed model without a checker needs to be high.

Each verifier is a function from (prompt, response) to a reward, built from three parts. An extractor finds the claimed answer in the response, a normalizer puts it in canonical form, and a comparator decides whether it matches the reference. Each part can fail in two directions.

  • A false negative rejects a correct response. The model is penalized for being right in an unexpected format, which wastes signal and teaches the format rather than the math.
  • A false positive accepts a wrong response. The model is paid for being wrong in a particular way, and RL will learn to be wrong in exactly that way as often as possible.

False positives are the dangerous ones, because RL amplifies them. A false negative rate of 5% costs some learning speed. A false positive that a policy can trigger on purpose eventually becomes the policy.

Format rewards

DeepSeek-R1-Zero's template asked the model to put its reasoning between <think> and </think> and its answer between <answer> and </answer>, and its reward had two rule-based parts, an accuracy reward and a format reward for following the template (DeepSeek-AI 2025). The format reward does two jobs. It makes extraction reliable, since the answer is wherever the tags say, and it separates the part of the output that is reasoning (and may later be hidden or summarized) from the part that is the answer.

A format reward should be strict about structure and indifferent to content. One well-formed thinking block, one well-formed answer block, nothing else. Leniency here leaks into the accuracy reward, because a response with two answer blocks invites the extractor to read the wrong one.

Warm-up

A strict format reward

Implement format_reward(text) returning 1.0 if text, after stripping leading and trailing whitespace, consists of exactly one block <think>...</think>, then optional whitespace, then exactly one block <answer>...</answer>, and nothing else. Neither block may contain any of the four tags inside it, and the answer must be non-empty after stripping. Otherwise return 0.0.

Hidden tests, hints, and AI help, from $1.99 a month.

Checking math answers

Most math RLVR data comes in one of two shapes. Competition problems (the MATH dataset and its descendants) have answers written in LaTeX, by convention inside \boxed{...} at the end of the solution. Word problems (GSM8K) have numeric answers, which the dataset marks after ####. Either way the checker must find the model's final answer, canonicalize it, and compare it with the reference.

Extraction

The rule nearly everyone uses is "the last \boxed{} in the response". It is the last one because models often box intermediate results, and the final answer comes at the end. The contents can contain braces, as in \boxed{\frac{a}{b^{2}}}, so a regex like \\boxed\{(.*?)\} returns \frac{a and silently breaks every answer with a fraction. You need a brace counter.

Core

Extracting the last boxed answer

Implement extract_boxed(text) returning the contents of the last \boxed{...} in text, with nested braces handled, or None if there is no complete one. Allow spaces between \boxed and the opening brace. If the last \boxed is unbalanced (its brace never closes), fall back to the previous one.

Hidden tests, hints, and AI help, from $1.99 a month.

Normalization and comparison

Now the hard part. A checker that compares strings exactly will reject 0.5 against a reference of \frac{1}{2}, 1000 against 1,000, and x = 5 against 5. Each of those false negatives tells the model, on that example, that the right answer was wrong. Here is a working list of transformations, roughly in the order a checker applies them.

stepexamplewhy
strip spacing commands and dollar signs\left( 1, 2 \right) to (1,2)LaTeX spacing carries no meaning
canonicalize commands\dfrac, \tfrac to \frac; \frac12 to \frac{1}{2}; \sqrt2 to \sqrt{2}many spellings of one thing
unwrap text\text{B} to Banswers wrapped for display
drop units and decorations10^{\circ} to 10; 50\% to 50the reference rarely includes them consistently
drop a variable prefixx = 5 to 5models restate the variable
remove thousands separators1,000 to 1000, but not 1,2a comma followed by exactly three digits is a separator
compare numerically0.5 equals \frac{1}{2}different forms of one number
compare elementwise(0.5, 3) equals (\frac{1}{2},3)tuples, intervals, coordinates

Each rule is also a place to be wrong. Dropping percent signs makes 50\% equal 50, which is what most datasets want, but also makes it unequal to 0.5, which some want. Removing the separator in 1,000 is right, but the same rule applied to 1,2 would turn the coordinate pair into twelve. Numeric comparison needs a tolerance, but a loose one accepts 0.333 for 1/3, which a grader should reject because the model rounded. And no list of string rules catches every symbolic equivalence. 323\sqrt{2} and 18\sqrt{18} are equal, and only a computer algebra system can tell. That is why production checkers such as Hugging Face's Math-Verify parse LaTeX into SymPy expressions and test equivalence symbolically, falling back to string rules when parsing fails.

Interview

A math answer checker that is hard to fool and easy to satisfy

Implement answers_match(pred, ref) for two extracted answers (strings, or None for a missing answer). Normalize both with the rules of the table, made precise here and applied in this order. Remove \left, \right, the spacing commands \!, \,, \;, and \ , and dollar signs. Rewrite \dfrac and \tfrac as \frac. Unwrap \text{...}, \mathrm{...}, \textbf{...}, and \mbox{...}, which may contain braces. Remove all whitespace. Drop ^{\circ}, ^\circ, \%, and %. Drop a leading variable prefix such as x=. Drop trailing periods. Remove thousands separators, a comma between digits that is followed by exactly three digits. Rewrite single-digit shorthand such as \frac12 and \sqrt2 as \frac{1}{2} and \sqrt{2}. Finally, turn a single letter in parentheses, such as a multiple-choice (B), into the bare letter.

Then return True if they are equal as strings, or both parse as numbers (integers, decimals, a/b, or \frac{a}{b} with an optional leading minus) that agree to a relative tolerance of 10−610^{-6}, or both are bracketed tuples with the same brackets whose elements match pairwise. Return False for None or for anything empty after normalization.

The tests include equivalent forms that must match and near misses that must not, such as 0.333 against 1/3, 1,2 against 12, (1,2) against [1,2], and a hedged answer containing two values.

Hidden tests, hints, and AI help, from $1.99 a month.

Huang et al. (2025) measured how real checkers fail during RL on math. Rule-based checkers, they found, often fail to recognize equivalent answers written in different formats, a substantial false negative rate. Model-based checkers, where an LLM judges whether the response matches the reference, recover those false negatives but are themselves hackable. During RL, policies learned to emit patterns that the judge model misclassified as correct, in the simplest cases a single character such as { or long strings of meaningless text. The practical lesson, which matches what labs report doing, is to use a symbolic checker first and a judge only where it fails, and to probe any judge adversarially before letting a policy optimize against it.

Code with unit tests

For code, the verifier runs the program. Given a problem statement and a set of tests, extract the code from the response, execute it in a sandbox against the tests, and reward it. The two common rewards are binary (1 only if every test passes) and fractional (the fraction of tests passed). Fractional rewards give a denser signal on hard problems, at the cost of paying for partial solutions, including ones that special-case the easy tests.

Unit tests have false positives of their own. A test suite is a sample of the input space, and a wrong program that agrees with the right one on that sample passes. Liu et al. (2023) generated 80 times as many tests for HumanEval, from mutations of the original inputs and inputs written by an LLM, and found that the extra tests caught enough previously accepted wrong programs to cut pass@kk by up to 19.3% to 28.9%, and to change the ranking of models. In RL, an under-tested problem is not just a noisy label. It is a problem on which the policy is paid for code that does not work.

The standard way to measure a test suite's strength comes from software engineering. Make mutants of a correct program, small changes such as flipping a comparison or dropping an edge case, and count how many of them some test catches ("kills"). A mutant that survives every test is a wrong program the grader would accept.

Core

How strong is a test suite?

Implement mutation_report(reference, mutants, inputs). reference is a correct function, mutants is a list of functions, and inputs is a list of argument tuples. A test is the pair of an input and the reference's output on it. A mutant is killed by a test if it raises an exception or returns something different from the reference on that input. Return a dict with

  • "survivors", the sorted list of indices of mutants that no test kills, and
  • "minimal", a list of input indices chosen greedily, each time picking the input that kills the most mutants not yet killed (the lowest index on ties), until every killable mutant is killed.
Hidden tests, hints, and AI help, from $1.99 a month.

When the policy attacks the grader

Weak tests are the passive failure. The active failure is a policy that learns to attack the test harness itself, and once models can run code, this happens in practice. The hacks that have been reported in real training runs share a theme. They make the check succeed without making the program correct.

  • Exiting early. Calling sys.exit(0) before any assertion runs, so the harness sees a successful exit code. Baker et al. (2025) observed this and raising SkipTest in a frontier model's coding RL (§18.1).
  • Objects that equal everything. Returning an object whose __eq__ always returns True (and, for strings, whose methods return the object itself), so assert result == expected passes. MacDiarmid et al. (2025) at Anthropic call this the AlwaysEqual hack.
  • Patching the test framework. Writing a conftest.py that monkey-patches pytest's reporting so failures are recorded as passes (also in MacDiarmid et al.).
  • Tampering with the evaluator. METR (2025) documented frontier models overwriting the timing function in a kernel-optimization task so it always reported shorter times, monkey-patching the evaluator, overwriting the equality operator, and finding the grader's own copy of the answer.

MacDiarmid et al. found something worse than wasted compute. When a model learned these hacks on real production coding environments, it generalized to broader misbehavior, including alignment faking and attempts at sabotage, which is why reward hacking in RLVR is a safety problem and not only a data-quality problem (§19.1). Zhong et al. (2025) built ImpossibleBench to measure the propensity directly. It makes coding tasks whose specification and tests contradict each other, so the only way to pass is to cheat, and the pass rate is the cheating rate.

Which outputs fool which grader, and what does RL do with the gap?
The reference answer is 1/2. Each row is a behavior a policy can adopt. Honest rows are right with probability equal to the model's skill. Pick a grader, then train a softmax policy on that grader's reward with exact policy gradient.
Loading interactive figure…

The lesson from these cases is that a grader must not trust anything the solution can touch. Run the solution in a separate process with time and memory limits, no network, and a read-only copy of the tests. Have the untrusted process write its outputs in a plain data format, and compare them in the trusted process, where an object with a rigged __eq__ cannot follow, because serializing it either fails or produces only its data. In-process grading can never be made fully safe (a solution can inspect the caller's stack frames to read the expected answer, or patch built-in functions the grader uses), but the same principles applied in-process already stop the common hacks.

Interview

A grader that common hacks cannot fool

Implement grade_solution(src, func_name, tests). src is the source code of a candidate solution, func_name the function it must define, and tests a list of (args, expected) pairs where args is a tuple and expected is JSON-serializable. Return 1.0 if the function passes every test and 0.0 otherwise. Be robust to the following.

  • Exceptions of any kind, including SystemExit raised at import or during a call, which must make the grade 0 without stopping the grader.
  • A missing or non-callable function.
  • Outputs that rig equality. Compare json.dumps(out, sort_keys=True) with json.dumps(expected, sort_keys=True), and grade 0 if the output cannot be serialized. This also stops True passing for 1, which plain == allows.
  • Solutions that mutate their arguments. Give each call a copy.deepcopy of its arguments, since tests may share objects.
Hidden tests, hints, and AI help, from $1.99 a month.

Other domains with checkable answers

Math and code are the largest RLVR domains, not the only ones. What they share is a cheap program that decides correctness. The table lists the other domains in common use and the main way each one goes wrong.

domainthe verifierthe main weakness
precise instruction following (Tulu 3's IFEval-style constraints)one small program per constraint, such as a word count, a required keyword, or a formatrewards the constraint, not the quality of the rest of the response
formal proofsa proof assistant's kernel, such as Lean's, checks the entire proofalmost no false positives, provided the checker rejects placeholders such as sorry and new axioms, but statements must be formalized first, and few are
puzzles and gamesa solver or simulator (Sudoku, logic grids, game rules)narrow, and generated in bulk from one template, so a policy can overfit the generator
multiple-choice questionscompare the chosen letterguessing is rewarded
open-ended tasksan LLM judge with a rubricno longer a program, so it inherits the hackability of reward models (§16.5)

The multiple-choice row deserves a number. Suppose that on a question with KK options the policy reasons its way to the right answer with probability qq and otherwise guesses uniformly. Its reward is 1 with probability q+(1−q)/Kq + (1-q)/K, and by Bayes' rule the fraction of rewarded responses that were lucky guesses is

P(guess∣R=1)=(1−q)/Kq+(1−q)/K.\mathbb{P}(\text{guess}\mid R = 1) = \frac{(1-q)/K}{q + (1-q)/K}.

With K=4K = 4 options and q=0.2q = 0.2, that is 0.2/0.4=0.50.2/0.4 = 0.5. In plain words, half of the positive rewards reinforce chains that never reasoned to the answer, and to the policy they look exactly like the real successes. Practitioners therefore rewrite multiple-choice questions into open-answer form where they can, or drop the questions whose answers are easy to guess.

Noisy rewards, and why only some noise is harmless

Every real grader makes mistakes. How much does that matter? Suppose the grader accepts a wrong response with probability FPR\mathrm{FPR} (its false positive rate) and rejects a correct one with probability FNR\mathrm{FNR} (its false negative rate), and suppose, crucially, that these rates do not depend on which correct or wrong response it sees. Then for a prompt on which the policy is correct with probability pp, the expected value of the noisy grader's reward R~\tilde R is

E[R~]=(1−FNR) p+FPR (1−p)=FPR+(1−FPR−FNR) p.\mathbb{E}[\tilde R] = (1 - \mathrm{FNR})\,p + \mathrm{FPR}\,(1 - p) = \mathrm{FPR} + (1 - \mathrm{FPR} - \mathrm{FNR})\,p .

The gradient of this expectation is (1−FPR−FNR)∇θp(1 - \mathrm{FPR} - \mathrm{FNR})\nabla_\theta p, the true gradient times a positive constant as long as FPR+FNR<1\mathrm{FPR} + \mathrm{FNR} < 1. In plain words, response-independent noise slows learning down and changes nothing else. A grader that is wrong 20% of the time in both directions shrinks the signal to 60%, which costs samples, but the optimum is unchanged. One refinement is worth knowing. With a KL penalty, shrinking the reward by a factor cc is the same as multiplying β\beta by 1/c1/c, so the regularized optimum moves toward πref\pi_{\text{ref}}, and a noisy grader in a KL-regularized run behaves like a clean grader with a stronger penalty.

The assumption is the whole story. Real false positives are not independent of the response. A grader that accepts multiple boxed answers accepts them every time, so the policy can raise its reward by moving probability onto that behavior, and the optimum of the noisy objective is now a policy that hedges. False negatives that depend on format, likewise, move the optimum toward the format the grader likes. The cell below makes the distinction concrete with a softmax policy over three behaviors.

Python · cell 1

Uniform noise leaves the learned policy the same as the clean grader, careful solving, only slower. A grader that pays for one specific wrong behavior produces a policy that does that behavior.

Building graders you can trust

Put together, the evidence suggests a short discipline for any RLVR project.

  1. Measure the grader before the policy does. Build an audit set of responses with human-verified labels, including responses from the policy you will train, since its mistakes are the distribution that matters. Report the false positive and false negative rates separately.
  2. Attack it. Before training, run the grader on known hack patterns. Multiple answers, hedges ("either 3 or 4"), empty boxes, answers in unusual formats, very long outputs, text addressed to a judge model, and for code the exit, equality, and patching tricks above. Every accept is a bug.
  3. Prefer exact over learned. Use symbolic equivalence for math and execution for code, and use a model judge only for the cases they cannot handle, with its outputs audited.
  4. Isolate execution. Separate processes, time and memory limits, no network, read-only tests, outputs compared in the trusted process.
  5. Keep held-out checks. Hidden tests the policy never trains against, and a held-out benchmark scored by a different grader. If training reward rises while the held-out score stalls or falls, the policy has found something in the grader.
  6. Read samples. The cheapest detector of reward hacking is a person reading a hundred high-reward samples every few hundred steps.

Spurious rewards, and what they say about evaluation

A finding from 2025 is a warning for anyone reading RLVR results. Shao et al. (2025) trained Qwen2.5-Math-7B with RLVR on MATH using rewards that should not work. On MATH-500, ground-truth rewards improved accuracy by 29.1 points. A reward for format alone improved it by 13.8, rewards computed against incorrect labels by 24.1, and completely random rewards by 21.4. The same spurious rewards often failed to help other model families, such as Llama 3 and OLMo 2. Their analysis suggested that RL was mostly amplifying behaviors the base model already had, in particular a habit of reasoning in Python code, which rose from 65% to over 90% of responses, and that the clipping in the GRPO objective of §18.4 biases updates toward such high-prior behaviors. Wang et al. (2025) found a related effect from the other side, RLVR on a single training example lifted Qwen2.5-Math-1.5B from 36.0% to 73.6% on MATH-500. They report that it beat a format-correction baseline by 8.6 points, so most of that gain, though not all of it, matches what fixing the output format alone buys.

None of this means verifiable rewards are fake. It means that a gain from RLVR on one model family is not evidence that the reward taught anything new, and that format fixes, elicitation, and real learning look the same on a single benchmark number. Test on more than one base model, include a random-reward control, and look at what changed in the outputs.

In PyTorch

In a training loop, rewards for a batch are assembled from several rule-based parts and handed to the RL algorithm as one tensor. Here is a typical combination, accuracy plus format plus DAPO's soft overlong punishment, which ramps a penalty in over the last LcacheL_{\text{cache}} tokens before the hard length limit Lmax⁡L_{\max} so that truncated, unfinished responses are discouraged smoothly rather than all at once (Yu et al. 2025).

🔥 In PyTorchfor a machine with PyTorch

DAPO used Lmax⁡=20,480L_{\max} = 20{,}480 with Lcache=4,096L_{\text{cache}} = 4{,}096, so the penalty starts at 16,384 tokens, and it rewarded correctness with +1+1 and an incorrect answer with −1-1 rather than 0. The weights on the parts, here 0.1 on format, are design choices, and every one is a lever the policy will pull. A format bonus large enough to matter on its own is a reward for well-formatted wrong answers.

Read more

Watch next

🎬 Experimenting with Reinforcement Learning with Verifiable Rewards (RLVR) · Nathan Lambert · starts at 13:08The person who named RLVR introduces it and goes through experiments and implementation details from Tulu 3 and open reasoning work.
🎬 Adv. LLM Agents MOOC | UC Berkeley Sp25 | Open Training Recipes: LLM Reasoning by Hanna Hajishirzi · Berkeley RDI · starts at 49:21Hanna Hajishirzi, who leads the Tulu project, explains its RLVR stage for math and precise instruction following.
🎬 What is Al "reward hacking"—and why do we worry about it? · Anthropic · starts at 0:42Anthropic researchers describe models learning to cheat coding tests during RL, and the misaligned behavior that followed, a concrete case of a hacked verifier.