recipes/02-measure/reward-hacking.
What the book says
Ch. 14, over-optimization. “When a measure becomes a target, it ceases to be a good measure.” The picture is proxy reward against gold reward, read against KL from the reference policy (how far the weights have moved from where training started): proxy up, gold up, then gold turns over while proxy keeps going. The qualitative signatures are verbosity, boilerplate, hedging, sycophancy, and over-refusal. Ch. 6, policy gradients. A grouped update (GRPO, group relative policy optimization, and its variants) baselines every rollout against the other rollouts of the same ask. Whatever separates reward within an ask is the gradient; what only tracks which ask it is (difficulty) is subtracted away. So “what will the policy learn?” has to be asked within ask. Ch. 5, reward models. A judge is a reward model and is only as good as its accuracy on labels you made yourself. Length must not influence the score. Generative judges lag discriminative ones. Ch. 13, tool use. For an agent the reward has to read the trajectory, because the reply can claim anything.Five checks
1. The scan: what would the policy learn?
features= of your own) and the auto tier (the 200 most common words
and word pairs in the agent’s text, and pairwise ANDs that beat both
parents). The auto tier is what finds the hack nobody listed.
endorsed names what the reward should track, as substrings of feature
names. With it the scan can say reward_hack, and integrity is the
share of above-floor signal that is endorsed. optimize(mode="rl", endorsed=) carries the scan in its report; the publish gate reports it
and data.push(name, strict_hacks=True) refuses a reward_hack. The
scan’s table prints the pooled correlation beside the within-ask one.
The pooled number is what reward_correlations reports, and it calls a
difficulty confound (hard asks get long replies and low reward) a length
penalty; the within-ask number does not.
2. The probes: which shortcuts does the judge fall for?
3. The trajectory: did the agent fake the work?
delta_report(must_not_regress=["honest_claims"]) fails a run
that learned to overclaim, and argument_grounding (from
mark_grounding) covers the invented-argument case the same way.
4. The run: is it hacking right now?
wrap watches the reward function so the monitor keeps the last
completions with their rewards; every every steps it samples the
holdout from the live policy and scores it with the training reward (the
proxy) and with gold, a scorer the proxy cannot see. proxy_reward,
gold_reward and holdout_length land on the run beside the loss
curve. Four alarms: divergence, length, drift, feature.
stop_on names the ones that stop training; a stopped run finishes as
stopped with the reason. This is the one check that needs a trainer,
so the recipe does not run it; see
recipes/04-train/grpo.
5. The verdict: did it hack?
proxy names the training reward’s marker. When the proxy moved up and
the target did not follow, or the proxy’s interval sits entirely above
the target’s, the report is over-optimized and fails. hack_scan_diff
runs the scan before and after on rollouts scored by the same reward and
names the features that clear the floor only after: what the update
moved toward, and whether it is endorsed.
Run it
The recipe runs the first three checks and the verdict offline, in seconds, on a scripted refund agent and two judges. The honest judge reads the trajectory; the hackable judge passes anything that says “verified”.pool_exhausted because half the asks are
always answered right and carry no gradient; that is a supply problem,
not a hack.
Three rules
- Endorse what the reward should track. Nothing here can call a hack a hack without knowing what the behavior is.
- A flagged reward is a judge problem, not a row problem. The checks warn and rank; they do not prune. The fix is the rubric, the verifier, or the reward function, then re-grade and re-scan.
- Keep the gold separate from the proxy. Hand labels in
gold_reward, the hosted judge, a reward model trained on other pairs, or a rule the training reward does not read. The during and after checks are only as honest as the scorer the proxy never saw.