What Is Abstention?

Abstention

Abstention is when a model declines to answer a case because its confidence is too low and routes the case somewhere else. In AI systems and agents, abstention lets you trade some automation for fewer wrong answers, by sending uncertain cases to a human, a fallback, or a retry.

For example, suppose a document-classification step in an agent processes 1,000 cases. You set a confidence threshold that makes it abstain on the 180 least-confident cases. It answers the other 820 and gets 41 of them wrong, so its error rate on answered cases is 41 / 820 = 5.0%.

That 5.0% only tells part of the story. The system answered 82% of cases, and 180 cases went to human reviewers. You need all three numbers to judge whether the threshold is a good one.

Try Arize AX

Build better agents with Arize

Trace, evaluate, and learn. Build agents that work with Arize AX and start tracing your runs today.

Prefer open source? Try Arize Phoenix for self-hosted, open source agent observability.

Why abstention matters for AI systems

Every model is sometimes wrong. Abstention gives you a way to control where those errors land. Instead of acting on a shaky answer, the system can hand the case to something better suited to it.

Abstention is useful for:

  • Reducing harmful errors: Keep low-confidence answers away from users when a mistake is expensive.
  • Sizing human review: Decide how many cases your reviewers will see at a given threshold.
  • Routing in agents: Send uncertain steps to a stronger model, a retry, or a person instead of guessing.
  • Setting error budgets: Choose the operating point that meets a target error rate at the highest automation level.

Abstention is a decision rule, usually a confidence threshold. It is not a personality trait of the model, and you can tune and measure it like any other rule.

For more on combining model output with human judgment, see human-in-the-loop.

How abstention works

The standard setup is called selective prediction. The formulation follows the selective classification literature, including Geifman and El-Yaniv (2017).

It works in three steps:

  1. The system produces a prediction and a confidence score for the input. Call the score s(x), where x is the input.
  2. You choose a threshold, called τ (tau).
  3. If s(x) is at least τ, the system returns its prediction. Otherwise it abstains and routes the case onward.

Coverage and selective risk

Two numbers describe any threshold.

Formula:

coverage       = cases answered / all cases
selective risk = errors among answered cases / cases answered

Where:

  • Coverage is the share of cases the system answers instead of abstaining.
  • Selective risk is the error rate on the cases it does answer.

Raising the threshold lowers coverage and usually lowers selective risk. Lowering it does the reverse.

The risk-coverage curve

If you plot selective risk against coverage as the threshold changes, you get a risk-coverage curve. It shows every tradeoff available to you with a given confidence score.

The area under the risk-coverage curve (AURC) summarizes that tradeoff across all thresholds in one number. A deployment still has to pick one operating point on the curve.

Why confidence quality matters

A threshold only works if the score ranks correct answers above incorrect ones. If wrong answers often get high scores, no threshold will separate them well.

That is a calibration and ranking problem, not something a threshold can fix. The scikit-learn calibration guide covers the general techniques.

How to calculate coverage and selective risk

The following code sweeps several thresholds over ten hypothetical held-out cases. Each case has a confidence score and a flag for whether the prediction was correct.

# Each pair is (confidence, prediction was correct) on held-out data.
cases = [
    (0.98, True), (0.95, True), (0.93, True), (0.90, False), (0.88, True),
    (0.84, True), (0.80, True), (0.72, False), (0.65, True), (0.55, False),
]

def coverage_and_risk(cases, threshold):
    answered = [correct for conf, correct in cases if conf >= threshold]
    coverage = len(answered) / len(cases)
    risk = answered.count(False) / len(answered) if answered else 0.0
    return coverage, risk

for threshold in (0.50, 0.70, 0.85, 0.92):
    coverage, risk = coverage_and_risk(cases, threshold)
    print(f"threshold {threshold:.2f}: coverage {coverage:.0%}, selective risk {risk:.1%}")

Output:

threshold 0.50: coverage 100%, selective risk 30.0%
threshold 0.70: coverage 80%, selective risk 25.0%
threshold 0.85: coverage 50%, selective risk 20.0%
threshold 0.92: coverage 30%, selective risk 0.0%

Selective risk falls as the threshold rises, but coverage falls faster. Notice the wrong answer at confidence 0.90. Until the threshold passes it, that error stays in the answered set. Imperfect ranking like this is why you need to check confidence quality on real data.

Worked example: choosing a threshold

Return to the document classifier from the opening. At the chosen threshold, it processes 1,000 cases:

coverage       = 820 / 1,000 = 0.82
selective risk = 41 / 820    = 0.05  (5.0%)
review load    = 180 cases sent to humans

Whether 5.0% is good depends on what those 180 abstentions contain and what review costs.

Suppose human review finds that 60 of the 180 abstained cases would have been errors. The other 120 would have been correct.

Outcome Cases
Answered correctly 779
Answered incorrectly 41
Abstained, would have been wrong 60
Abstained, would have been correct 120
Total 1,000

Abstention prevented 60 errors, more than the 41 that remain in the answered set. Without abstention, the system would have made 101 errors, a 10.1% error rate.

It also cost something. Reviewers spent time on 120 cases the model would have handled correctly.

Report coverage, selective risk, and the would-have-been error rate among abstentions once review labels exist. Those review labels are exactly what measuring human-LLM judge alignment work produces when humans check model judgments.

How to measure and tune abstention

Tuning abstention is a loop. Each step depends on logging the right data.

  1. Log the score, the decision, and the outcome. For every case, record the confidence, whether the system abstained, and later whether the answered prediction was correct. Without outcomes on abstained cases, you cannot know what abstention bought.
  2. Draw the risk-coverage curve on held-out data. Choose the threshold that meets your error budget at the highest coverage. Confirm it on production traffic before you lock it in.
  3. Price both kinds of error. A threshold is an economic choice between the cost of a wrong answer reaching a user and the cost and delay of human review. State those costs when you justify τ.
  4. Monitor by slice. Coverage and risk can differ sharply by language, customer, or document type. A threshold that is safe on average may abstain on most cases for one group, or answer confidently where it should not.
  5. Revisit after any model or prompt change. Scores shift between model versions. A threshold tuned on the old model may abstain far more or far less than intended.

In practice, this loop runs on traces. Filter production spans by confidence, inspect the abstained and the confidently wrong cases, and adjust.

For more on collecting the human judgments this loop needs, see human evaluation.

Abstention vs. refusal

The most important distinction is why the system did not answer.

  • Abstention: The system could answer but judges its answer too likely to be wrong. A tunable threshold governs the decision, and the case is routed onward with its context intact.
  • Policy refusal: The system will not answer because the request is disallowed or out of scope. This is a policy decision, not a confidence decision. Adding reviewer capacity does not change it.
  • Human-in-the-loop review: Abstention is one way to trigger human involvement. Human-in-the-loop also covers approval before an action and correction after one.

Measure policy refusals as their own category, as described in the policy adherence entry.

Treating refusals as abstentions corrupts both metrics. Coverage drops for reasons no threshold controls, and reviewers receive cases they were never meant to clear.

Limitations

Abstention is useful, but it moves errors around more than it removes them.

  • It relocates errors: Uncertain cases go to whoever handles them next. If the fallback is an overloaded queue or a weaker model, system-level quality may not improve.
  • Over-abstention: Selective risk looks excellent while most real work waits for humans. Any accuracy figure quoted without coverage becomes misleading.
  • Unreliable LLM confidence: Verbalized confidence (“I’m fairly sure”) and token probabilities from large language models (LLMs) are both imperfectly calibrated. A model can be confidently wrong on rare formats or adversarial inputs.
  • Unequal access: If confidence is lower for some populations, a single threshold gives them less automated service.
  • Wrong step: Abstention cannot help when the error happened earlier. If retrieval already failed, the model may confidently answer from the wrong document. Only tracing shows which step to abstain at.

For more on why the answered share matters, see coverage.

Frequently asked questions

What confidence score should I use for abstention?

Use a score you have validated on your own held-out data as ranking correct answers above incorrect ones. That could be a calibrated probability, a judge score, or an agreement measure across several samples. Validate the ranking first and choose the threshold second.

How much abstention is acceptable?

There is no universal rate. Reviewer capacity and the cost of errors set it. If reviewers can handle 15% of traffic but your error budget requires abstaining on 25%, your real options are a better model, a better score, or a larger error budget.

Does abstention improve accuracy?

Abstention improves accuracy on answered cases by construction. That is why you must always report coverage alongside it. System-level accuracy only improves if the fallback is more accurate than the model would have been on those cases.

Is a chatbot saying “I don’t know” the same as abstention?

Only if an uncertainty signal drives it and the case is routed somewhere useful. A generated “I don’t know” with no score, no threshold, and no handoff is a style of answer. You cannot tune or measure it as selective prediction.

How do I pick the threshold value?

Draw the risk-coverage curve on held-out data and pick the point that meets your error budget at the highest coverage. Then confirm the result on production traffic and recheck it after every model change.

Putting abstention to work

Start by logging three things for every case: the confidence score, the abstain decision, and the eventual outcome. Collect outcomes for abstained cases too, through human review.

When you report results, give coverage, selective risk, review load, and the would-have-been error rate among abstentions. Break all four down by important slices.

Arize AX can help you filter traced spans by confidence and send abstained or confidently wrong cases to human review. Those labels feed the next round of threshold tuning.

Example

A classifier processes 1,000 cases and abstains on the 180 least-confident ones. It answers 820 and gets 41 wrong: coverage = 820 / 1,000 = 82% and selective risk = 41 / 820 = 5.0%. Review finds 60 of the 180 abstained cases would have been errors, so abstention prevented 60 errors but spent review time on 120 cases the model would have gotten right.

Don’t ship vibes.

Arize gives AI teams observability and evals to understand and improve agent performance.