mixle.task.calibrated_generator module¶
CalibratedGenerator – certified selective generation with abstention.
The generation-side sibling of CalibratedTaskModel. That class gates
classification: it turns an uncalibrated softmax into conformal label sets and escalates on an
ambiguous label set. Open-ended generation has no fixed label space: candidates are newly sampled
and their identities change by prompt, so applying label-set conformal prediction to candidate slots
would not provide classification coverage.
This module instead certifies one fixed measurable outcome: whether the top-scored generated
candidate is correct when its score clears a threshold. Calibration is split into threshold
proposal and independent certification halves. Candidate thresholds are proposed on the first half;
the second half supplies simultaneous Bonferroni-corrected exact binomial upper bounds, allowing the
most permissive threshold whose accepted-error upper bound is at most alpha to be selected without
reusing its evidence. The guarantee is a confidence statement about selective risk under the usual
i.i.d./exchangeability and stable-generation assumptions, not conformal coverage of changing strings.
An uncertified prompt returns ABSTAIN (None), the same sentinel as
mixle.task.calibrate.ESCALATE, so cascades can escalate without special casing.
- class CalibratedGenerator(generate, score, alpha=0.1, *, k=8, qhat=None, seed=0, confidence=0.95)[source]
Bases:
objectDraw
kcandidates and serve the best under a certified selective-risk gate.- Parameters:
generate (Callable[..., Sequence[Any]]) –
generate(prompt, k) -> Sequence[candidate](anrngkeyword is passed if the callable accepts one; falls back to the two-argument form otherwise). Any generator that can drawkcandidates for a prompt works: a wrappedCallableLLMsampledktimes, a beam, a stochastic sampler.score (Callable[[Any], float]) –
score(candidate) -> float, any mixle-scoreable model. Higher is better; the score need not be a calibrated probability; calibration thresholds its ordering statistic directly.alpha (float) – maximum certified error rate among accepted candidates.
k (int) – number of candidates to draw per prompt.
qhat (float | None) – optional manually supplied acceptance threshold. This remains callable but has no risk certificate; only
calibrate()populatesrisk_receipt.confidence (float) – simultaneous confidence level for the held-out risk certificate.
seed (int) – base seed for candidate draws; combined with the prompt (see
_derive_seed()) so different prompts get different, but reproducible, draws.
- calibrate(prompts, is_correct, *, seed=None, outcomes='per-prompt', sampling='constructed')[source]
Certify a held-out accepted-error threshold using an explicit correctness oracle.
The trailing half proposes score-margin thresholds; the independent leading half evaluates every proposal with simultaneous exact binomial bounds. Only the certification half consults
is_correct, once per row in order, so a metered or side-effecting oracle is not spent on rows that cannot reach the bound (MXR-080-1849). If no nonempty accepted subset certifies risk<= alpha, the threshold is+infand serving abstains everywhere.Scope of the certificate: it covers exactly the SERVED stochastic policy – candidate draws seeded from the generator’s own
seedand the prompt alone, the same derivationcandidate_set()/serve()use (STAT-RR17-07: certifying under a per-row schedule measured 1/150 errors and bounded risk at 0.0366 while the served policy produced 1000/1000 errors). Assuming the calibration prompts and future queries are i.i.d. draws from the same distribution, with probability at leastconfidenceover the calibration draw, the TRUE accepted-slice error at the deployed threshold is<= alpha(the per-threshold binomial bounds are Bonferroni-corrected across the proposal family, so the selection of the loosest passing threshold stays covered). Distribution shift voids the statement silently; re-certify on drifted traffic.WHAT the bound is a bound ON depends on how duplicated prompts got into the stream, and only the caller knows that –
samplingis that declaration (the same premise-declaration contract asoutcomes):sampling="constructed"(fail-safe default): the prompt list is a curated set, so underoutcomes="per-prompt"duplicates are redundant copies of one Bernoulli and COLLAPSE to one certification row (300 copies of one always-correct prompt certify from n = 1, bound 0.975 – STAT-RR18-04). The certified estimand is then UNIFORM over the DISTINCT certification prompts. It is NOT traffic-weighted: measured on 40%-heavy i.i.d. traffic whose heavy prompt always errs, collapsing certified error_upper 0.080 while the served traffic risk was 0.37-0.41, every trial (the pass-19 blocker). If your serving mix repeats prompts, this default’s certificate does not cover it – declare the sampling truthfully instead.sampling="iid-traffic": the caller’s recorded assertion that the calibration rows are an i.i.d. draw of the serving traffic itself. Row error indicators are then i.i.d. Bernoulli(traffic accepted-error rate) EVEN under per-prompt outcomes – the randomness is the prompt draw, and a duplicate’s multiplicity IS its traffic weight – so rows all count and the bound covers the TRAFFIC-WEIGHTED accepted-error rate serving experiences. On the measurement above, this declaration refuses to certify alpha = 0.15 (the heavy errors are ~40% of rows), which is the correct answer.
Disagreeing duplicate verdicts are refused under
outcomes="per-prompt"in both sampling modes (a deterministic decision with a fixed per-prompt outcome cannot differ between copies); the receipt records both declarations and names the certified estimand.
- candidate_set(prompt, *, seed=None)[source]
Return
[best_candidate]when its calibrated statistic clears the risk gate, else[].
- serve(prompt, *, seed=None)[source]
Return the best candidate only when the certified risk gate accepts, else
ABSTAIN.
- decide(prompt, *, seed=None)[source]
Alias for
serve()with the same name asCalibratedTaskModel.decide(), so aCalibratedGeneratordrops intoCascadeunmodified.
- smallest_certifiable_calibration_set(alpha, *, confidence=0.95, thresholds_tested=2, limit=100_000)[source]
Smallest
calibrate(...)set size whose risk certificate can reachalphaat all.CalibratedGenerator.calibrate()splits the set in half and certifies on the leading half with a one-sided Clopper-Pearson bound, Bonferroni-corrected across the thresholds it tests. That bound has a floor set by the certification count alone: withccertification rows and zero observed errors it is still1 - (tail)**(1/c). Below the size returned here,alphasits under that floor, no threshold can ever be eligible,qhatstays+infand serving abstains on every input – for a reason that has nothing to do with the model. Sizing a calibration set from this avoids mistaking a structurally impossible target for a model that needs tuning.thresholds_testedis the Bonferroni divisor;calibrate()tests one threshold per distinct proposal-split statistic plus-inf, so 2 is the floor and the realistic best case. Pass the number you expect if the statistic takes many distinct values, since more thresholds tighten the tail.