cookbook/data_labeling/_21_rejection_sampling/README.md
Generate K candidate outputs per prompt, verify or score each one, and keep only the survivors. The filter is the product: what passes becomes training data (verified reasoning traces, best-of-N picks), and the pass rates themselves tell you which prompts are worth training on. This is the data type behind cold-start reasoning recipes: sample from a teacher, check every sample, keep what checks out.
This is not _17_llm_as_judge/. There, the judge
emits a score report and a human reads it. Here, the verifier or judge gates
a generation loop: its verdict decides row by row what enters the dataset.
judge_gate.py writes all N scores with each kept row and
rl_prompt_selection.py writes the pass rate; basic.py rows carry no
score - their provenance is the verified final answer itself.
step_rewards.py keeps every row and moves the verifier's verdict inside
the trace: K rollouts per step prefix turn outcome checks into per-step
scores.
basic.py — verified reasoning traces. A teacher samples K=4 solutions
per math/code problem; a pure-code verifier (integer equality against a
hand-checked gold) keeps only traces whose final answer verifies. The
reasoning text itself is not checked - a flawed derivation that lands on
the right integer is kept. No judge anywhere in the keep path.judge_gate.py — best-of-N for prompts with no programmatic verifier. A
generator samples N=3 candidates; a temperature-0 judge scores each
against a rubric; the argmax candidate is kept only if it clears an
absolute bar (score >= 4). All N scores are written with each row.rl_prompt_selection.py — pass rates as a prompt filter. Problems the
model solves 4/4 teach nothing; problems it solves 0/4 give no reward
signal. Keep the band in between (0 < pass@4 < 1) as RL training prompts.step_rewards.py — per-step process rewards from the same outcome check
(Math-Shepherd-style Monte-Carlo step scoring). basic.py pays an
outcome reward: the whole trace is kept or dropped on its final answer.
Here each step prefix gets K=3 continuation rollouts, and the step's
score is the fraction that still reach the verified gold - a process
reward with no judge grading steps
(_17_llm_as_judge/) and no per-step human
labels. DeepSeek-R1 skipped neural PRMs because step correctness is hard
to define, step annotation does not scale, and a trained reward model
invites reward hacking; MC step scoring gives you per-step credit
assignment anyway, priced at K rollouts per step and hacking-proof to
the extent the verifier is. One solution carries a deliberately
corrupted step so the score cliff is visible.Rows written by basic.py (every final_answer verified equal to the gold
before the row is kept):
{"prompt": "How many ways can you choose 3 books from 7 distinct books?", "reasoning": "To find the number of ways to choose 3 books from 7 distinct books, we use the combination formula C(n, k) = n! / (k!(n-k)!). Applying this with n = 7 and k = 3 yields C(7, 3) = (7 * 6 * 5) / (3 * 2 * 1) = 35.", "final_answer": 35, "sample_index": 1}
{"prompt": "A train travels 180 km at 60 km/h, then another 120 km at 40 km/h. How many minutes does the whole trip take?", "reasoning": "The train's journey consists of two parts. First, it travels 180 km at 60 km/h, which takes 180 / 60 = 3 hours. Second, it travels 120 km at 40 km/h, which takes 120 / 40 = 3 hours. The total time for the trip is 3 hours + 3 hours = 6 hours. Since 1 hour is equal to 60 minutes, the whole trip takes 6 * 60 = 360 minutes.", "final_answer": 360, "sample_index": 2}
A row written by judge_gate.py, with all N scores as provenance:
{"prompt": "Write a coherent paragraph of 30 to 40 words about winter mornings that does not contain the letter 'e' anywhere.", "chosen": "Cold air grips a frosty world. A soft light slips through our window. Frost clings to glass. Our sun glows with gold, warming a cold, still city. Fog drifts, but this bright dawn brings joy.", "chosen_score": 5, "all_scores": [5, 5, 5], "judge_reason": "The response is a coherent paragraph of exactly 35 words about winter mornings that completely avoids the letter 'e'."}
A row written by step_rewards.py. Step 2 is the deliberately corrupted
splice (72 - 15 miscomputed as 67); its score cliffs to 0.0 and recovers
at step 3, which re-derives the correct daily count:
{"problem": "A bakery makes 12 trays of muffins per day, with 6 muffins per tray. Each day 15 muffins are set aside for staff and the rest are sold. How many muffins are sold across 5 days?", "steps": ["Multiply 12 trays of muffins by 6 muffins per tray to find the daily total of 72 muffins.", "Each day the bakery bakes 12 * 6 = 72 muffins; setting aside 15 for staff leaves 72 - 15 = 67 muffins sold per day.", "Multiply 57 muffins sold per day by 5 days to find the total of 285 muffins sold."], "step_scores": [1.0, 0.0, 1.0], "k": 3}
Three observations from testing against gemini-3.5-flash (a reasoning
model), worth knowing before trusting these gates:
_05_text_pairwise_preference/)
instead of absolute scores.step_rewards.py scored
0.67: rollouts noticed the arithmetic error and repaired it mid-flight,
so the score measured recoverability, not step correctness. The shipped
instruction pins the prefix ("treat the given steps as fixed ... even if
you believe one contains an error"), and the same corrupted step scored
0.0 with a clean recovery to 1.0 on the following step. Scores are also
coarse at K=3 - the only observable values are 0, 1/3, 2/3, and 1.basic.py when answers are programmatically checkable, judge_gate.py
when they are not.rl_prompt_selection.py.step_rewards.py. For
a judge that grades steps directly instead of rolling them out, see
_17_llm_as_judge/._17_llm_as_judge/._22_dataset_curation/.python cookbook/data_labeling/_21_rejection_sampling/basic.py
python cookbook/data_labeling/_21_rejection_sampling/judge_gate.py
python cookbook/data_labeling/_21_rejection_sampling/rl_prompt_selection.py
python cookbook/data_labeling/_21_rejection_sampling/step_rewards.py
rl_prompt_selection.py is the slow one - expect roughly 15 minutes,
dominated by reasoning tokens on the hard problems.
Requires GOOGLE_API_KEY.