Marketing

Calibrating a Refusal Threshold from a Labeled Sample

Antonio Evans11 min read

A cost curve with a dashed vertical line at the chosen threshold, shading missed edits on one side and wrong edits on the other, beside a notepad headed calibration set and validation set.
Key points

Key points

  1. 1Split labeled rows into a calibration set and a validation set before choosing any threshold, so the threshold is tested on rows it never saw.
  2. 2For every candidate threshold, count missed edits and wrong edits, then total cost = missed edits times cost of a miss plus wrong edits times cost of a wrong edit.
  3. 3A wrong edit usually costs more than a missed edit because it writes bad data downstream, so the cost ratio, not accuracy, drives the cutoff.
  4. 4The threshold you can trust is bounded by sample size: small validation sets produce wide uncertainty bands around the cost estimate.

Framing the problem: two errors, one cutoff

An edit-detection system reads a row, proposes a corrected value, and attaches a confidence score. Your job is to pick the cutoff: above it, the system writes the edit; below it, the system refuses and leaves the row for a human or for later review. The refusal threshold is therefore a decision rule, not a model property. Probabilistic classifiers output scores between 0 and 1, and the threshold is what converts a score into a class label, which is why a default like 0.5 is often the wrong choice in production the Evidently threshold guide.

Two error types matter here, and they pull in opposite directions:

  • Missed edit (false negative of the "apply" decision): the system refused, but the row did need a change. You keep the old, wrong value until someone notices.
  • Wrong edit (false positive): the system applied a change that does not match the known correct value. You have now corrupted a value that may have been fine.

Lowering the threshold reduces missed edits and increases wrong edits. Raising it does the reverse. The right cutoff depends on the relative cost of each, and that cost is a business fact you have to state explicitly before any arithmetic. The same logic governs any score-to-label decision: the default cutoff misrepresents the trade-off when costs are asymmetric or one class is rare the Evidently threshold guide.

A worked framing: for a product catalog, a missed edit means a stale description lingers another week (cheap, recoverable). A wrong edit means a price field or a spec gets silently corrupted and a customer sees it (expensive, hard to trace). That asymmetry is the whole design input.

Building the labeled sample

You need rows where you know the correct value independently of the model: a human-verified gold set, an upstream system of record, or a manual audit. Two properties matter more than raw size.

First, the sample must contain a realistic mix of rows that need edits and rows that do not. If 98% of your sample needs no change, your threshold curve will be dominated by easy negatives, and the interesting region (rows near the boundary) will have too few examples. This is the same imbalance problem that motivates stratified sampling: select a representative sample from each stratum, such as document type, confidence band, or field type, rather than sampling uniformly the human review and calibration guide.

Second, the sample must be segmented. A single aggregate accuracy number can hide catastrophic failure on one segment: one documented case shows a 97% aggregate figure sitting on top of 60% accuracy for handwritten receipts and 45% for international formats, because the easy document type dominated volume the human review and calibration guide. If your edit system handles several row types, calibrate per type or accept that one threshold is a compromise.

Before you trust any score, check whether it is calibrated at all. A reported 0.90 might be correct 94% of the time on one field and 82% on another, and LLM self-reported confidence tends to be top-skewed, which creates a confidence floor you must account for when setting thresholds the LLM grader calibration paper. In one comparison across seven models and three datasets, self-reported confidence was the best-calibrated method, with average expected calibration error of 0.166 versus 0.229 for self-consistency voting, despite the latter costing 5x the inference the LLM grader calibration paper. The practical lesson: measure the reliability curve of your own scores on labeled rows before you assume a score of 0.8 means 80% correct.

If your pipeline extracts structured fields, make sure the score you calibrate is the one that gates the write, and treat the schema as fixed while you calibrate. Changing field names, meanings, or types mid-calibration invalidates the labels; schema evolution rules exist precisely because a renamed or re-typed field breaks consumers silently the schema evolution guide.

Why you split the sample

If you pick the threshold that minimizes cost on the same rows you used to draw the curve, you will overstate performance. The curve is noisy, and the minimum on a noisy curve tends to be a lucky dip. Split first:

SetShare of labeled rowsPurposeTouched how often
Calibration60 to 70%Sweep thresholds, compute costs, pick the cutoffMany times
Validation30 to 40%Measure cost of the chosen cutoff onceOnce, then frozen

Rules that keep the split honest:

  • Assign rows randomly, but stratify by segment and by whether an edit was needed, so both sets resemble production.
  • Keep rows from the same source document or the same account in one set only, otherwise near-duplicates leak information across the split.
  • Never re-tune on the validation set after seeing its cost. If you do, it becomes a second calibration set and you need a third holdout.
  • Freeze the sample and the labeling rules before you start. If a labeler decides a value was correct that the model had flagged as wrong, record that decision, do not quietly drop the row.

A practical guardrail: keep the validation set large enough that a cost difference between two candidate thresholds is visible. If your validation set has 200 rows and 10 of them need edits, the cost estimate swings wildly with one or two flips. Confidence intervals around accuracy estimates help communicate exactly this kind of uncertainty, and methods for constructing them for classifier performance are standard the confidence intervals guide.

Because you only get one honest look at the validation set, keep a record of the threshold and cost assumptions you tested. If you later add rows, append them to the validation set rather than reusing the calibration rows, and note that the estimate now covers a different set of rows.

The cost curve: computing the trade-off

For each candidate threshold t, walk the calibration rows and classify each one into one of four cells. Only two cells carry cost:

CellConditionCost term
Correctly appliedEdit needed, applied, matches gold0
Correctly refusedNo edit needed, refused0
Missed editEdit needed, refusedmissed_edits x cost_miss
Wrong editApplied, does not match goldwrong_edits x cost_wrong

Then total cost = missed_edits * cost_miss + wrong_edits * cost_wrong. Sweep t over the observed score values (or a fixed grid of 0.01 steps), compute total cost at each, and pick the minimum. Note that a row with no edit needed but where the system refused is free, which is why a high refusal rate is not automatically bad: refusal is the safe default.

Here is the sweep in plain Python, kept short enough to read:

rows = [(score, needs_edit, applied_matches_gold) for score, needs_edit, applied_matches_gold in calibration]

def cost_at(t, cost_miss, cost_wrong):
    missed = wrong = 0
    for score, needs_edit, matches in rows:
        applied = score >= t
        if applied and not matches:
            wrong += 1
        elif not applied and needs_edit:
            missed += 1
    return missed * cost_miss + wrong * cost_wrong

grid = sorted({s for s, _, _ in rows})
best = min(grid, key=lambda t: cost_at(t, 1.0, 5.0))

Two implementation details that change results. First, ties: define whether a score exactly equal to t applies or refuses, and apply that rule in both calibration and production. Second, the "applied but no edit was needed" case: if the system applies an edit to a row that needed none, count it as a wrong edit, not a free action, because it changed correct data. When matching applied values to gold, decide how strict the comparison is (exact string, normalized whitespace, numeric tolerance) and fix that rule before the sweep.

The cost ratio is the lever. With cost_wrong at 5x cost_miss, the optimum moves toward refusing borderline rows. With cost_wrong equal to cost_miss, the sweep lands near the minimum-error point. This mirrors standard threshold analysis, where the operating point should reflect the cost of false positives versus false negatives rather than a blanket 0.5 the Evidently threshold guide. Precision-recall curves show the same trade-off across thresholds and help you see where a small change in cutoff sharply reduces precision for only a small gain in recall the scikit-learn precision-recall example. Precision is the share of applied edits that were correct, and recall is the share of needed edits that were applied, so plotting both against the cutoff makes the two error types visible as you sweep the scikit-learn precision-recall example.

One caution on curve-based shortcuts: picking the threshold that maximizes a summary statistic like Youden's J or minimizes error rate assumes equal costs and a single well-behaved boundary, and it can be suboptimal when the score is not calibrated or the decision needs more than one cut point the ROC threshold critique. Since you have labeled rows and stated costs, compute the cost directly.

A worked example with numbers

Suppose the calibration set has 1,000 rows. 300 need an edit and 700 do not. You assign cost_miss = 1 and cost_wrong = 5, on the reasoning that a corrupted value costs about five times a stale one.

At three candidate thresholds, the confusion counts come out like this:

ThresholdMissed editsWrong editsCost = missed x 1 + wrong x 5Refusal rate
0.55409040 + 450 = 49011%
0.75853085 + 150 = 23524%
0.901708170 + 40 = 21041%

The naive instinct (catch every possible edit, threshold low) produces the worst cost because wrong edits are five times more expensive. The sweep picks 0.90 if these are the only candidates, but the true minimum may sit between 0.75 and 0.90, so run the grid rather than three hand-picked points. On the validation set, the chosen threshold costs, say, 220 against a calibration cost of 210. That gap is your estimate of optimism, and it is the number you report, not the calibration figure.

Now shift the ratio. If cost_wrong stays 1 and cost_miss rises to 4 (say, a missing edit triggers a compliance failure), recompute: 0.55 gives 160 + 90 = 250; 0.75 gives 340 + 30 = 370; 0.90 gives 680 + 8 = 688. The optimum flips to the low threshold. Nothing about the model changed. Only the cost statement did.

Sensitivity check worth running: recompute the optimum at cost ratios one step either side of your point estimate (for 5, try 3 and 8). If the chosen threshold does not move, your decision is robust. If it jumps by 0.15 or more, you need more labeled rows or a sharper cost estimate before shipping. The same discipline of measuring per segment applies when you deploy: track accuracy by segment and by confidence band, including high-confidence rows nobody reviews, because a systematic error on a high-confidence segment is invisible without sampling the human review and calibration guide.

When the model itself varies (multiple providers, model swaps, or a gateway across several APIs), keep the calibration pipeline model-agnostic so you can rerun it per model. An OpenAI-compatible layer over many model types lets you point the same sweep at each candidate and compare cost curves on identical rows; Quanta Inference is one such option at https://quantaintelligence.ai/inference.

Choosing the threshold and shipping it

The decision rule, in order:

  1. State the cost ratio in writing, with a reason. "A wrong edit costs about 5x a missed edit because correcting bad data downstream takes a manual audit" is a decision others can challenge.
  2. Sweep on the calibration set, record the full curve, not just the minimum.
  3. Evaluate once on validation. If validation cost is much worse than calibration cost, your sample is too small or not representative; collect more rows.
  4. Run the sensitivity check at adjacent cost ratios.
  5. Ship the threshold with its cost assumptions, its validation cost, and the validation set size recorded alongside it.

Then monitor. Recalibrate when the mix of input rows shifts, when the underlying model changes, or when a new segment appears. Set a review cadence and a trigger, for example a monthly stratified sample of applied edits. If you route low-confidence rows to humans, order the queue by uncertainty, not arrival time, and reserve reviewer capacity for low-confidence and historically weak segments rather than spreading it evenly the human review and calibration guide.

A note on what not to do: do not choose the threshold by eyeballing the score histogram. Scores are frequently miscalibrated, and a visible cluster at 0.9 does not mean those rows are 90% correct the LLM grader calibration paper. The labeled sample is the only thing that ties a score to an error rate.

If the labels need to be refreshed but the model output is already flowing, keep the two apart during audit: sample production rows, have a person record the correct value, and add the pair to the next validation batch without retraining the model on those rows.

Sample size guidance

You do not need a huge sample, but you need enough of the rare, costly events. Two rules of thumb carry most of the weight:

  • Count wrong edits, not total rows. If your validation set at the candidate threshold produces fewer than about 30 wrong edits, the cost estimate will be too noisy to distinguish thresholds. Size the sample so the expected wrong-edit count at your operating point clears that bar, then add rows.
  • Split unequally when errors are rare. If only 5% of rows need edits, put 70 to 80% of rows in calibration and keep the validation set as large as you can afford, because recall on those rare rows is what moves cost.

Quick sizing table for a system where 10% of rows need edits and you expect roughly half of applied edits near the cutoff to be correct:

Validation rowsExpected rows needing editsTypical wrong edits at a cautious cutoffUsable for a threshold decision?
200202 to 5No, too few events
1,00010010 to 25Marginal, expect a wide range
3,00030030 to 75Yes, cost differences become visible
10,0001,000100 to 250Yes, and per-segment checks become possible

These are planning figures, not guarantees: your actual rates depend on the model and the data. The point is that the binding constraint is the count of errors, not the count of rows, and confidence intervals on the error rate make the uncertainty explicit when you present the result the confidence intervals guide.

Two more sizing traps. If a segment has fewer than a few hundred rows, the sweep for that segment will be too noisy to trust, so borrow a global threshold and monitor it rather than calibrating per segment. And if your labeled rows were collected from a preview of the first few hundred rows of a batch, they may not resemble later production traffic; resample after a few weeks and rerun the split.

Finally, decide in advance what you will do with rows in the ambiguous band just below the threshold. Options include queuing them for review, holding the old value and flagging the row, or attempting a cheaper second pass. This is the same selective-automation pattern used in grading and extraction systems: automate above a calibrated threshold, review below it, and sample the automated band to catch novel errors the human review and calibration guide.

FAQ

FAQ

How many labeled rows do I need to calibrate a threshold?

Size the sample around the errors, not the rows. You want at least 30 wrong edits and 30 missed edits in the validation set at your candidate threshold, which often means roughly 1,000 to 3,000 rows when a tenth of rows need edits and most applied edits near the cutoff are still wrong. If segments behave very differently, multiply that budget per segment or accept a single blended threshold with known blind spots.

What cost ratio should I use for a wrong edit versus a missed edit?

Start from consequences, not intuition. A wrong edit writes bad data that others trust, so its cost includes detection and repair; a missed edit leaves a stale value that a later pass or a human will likely catch. Many teams find a wrong edit costs several times a missed edit, but write the number down with a reason and rerun the sweep at one step either side to see whether the chosen threshold moves.

Can I just use 0.5 as the threshold?

0.5 is a default, not a decision, and it is optimal only when the two error types cost the same and your scores are well calibrated. On labeled rows you can measure the actual trade-off, and the cost-minimizing cutoff frequently lands well above 0.5 when wrong edits are expensive. Calibration also varies by field and row type, so a single 0.5 rarely holds across segments the Evidently threshold guide.

What if my model's confidence scores are poorly calibrated?

Measure the reliability on labeled rows first: bucket scores and compare average confidence with actual accuracy per bucket. Self-reported confidence has been the best-calibrated of the common methods in published comparisons, but it is still top-skewed, so do not read a score as a probability the LLM grader calibration paper. The threshold sweep on labeled data sidesteps the issue, because you optimize on observed error counts rather than trusting the score's nominal meaning.

How often should I recalibrate?

Recalibrate on a schedule and on triggers: a change to the model, the prompt, the schema, or the mix of input rows. Between runs, keep a small stratified sample of applied edits checked each month, including high-confidence ones nobody reviews, because systematic errors on confident rows go unseen without deliberate sampling. If you route low-confidence rows to reviewers, order that queue by uncertainty so capacity goes where the risk is the human review and calibration guide.

Sources

Sources

  1. How to use classification threshold to balance precision ...
  2. 5.5, Human Review & Confidence Calibration | AI Cert Guides
  3. When Can We Trust LLM Graders? Calibrating Confidence for ...
  4. Schema Evolution: 8 Kafka Best Practices
  5. ML Classifier Confidence Intervals
  6. Precision-Recall
  7. Classifier Calibration and the End of ROC-Based Threshold ...
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles