# Confidence-Gated Routing
Confidence-gated routing means you look at TWO things when a model answers: what it said, and how sure it was. The answer tells you *what* to do; the confidence tells you *whether* to do it automatically. High confidence: act. Medium: ask for confirmation or flag it. Low: hand it to a human, a stronger model, or a safer fallback.
Why write a note about something that sounds this obvious? Because it's so easy to skip with LLMs. You take the model's answer and run with it, since an LLM doesn't give you a usable confidence in the first place ("I'm 90% sure" is just more generated text). The moment you have a real probability, a whole family of well-studied techniques opens up, and they make automation both safer and cheaper.
## The general idea
This is one of the oldest ideas in pattern recognition. In 1957, and then in "On optimum recognition error and reject tradeoff" (1970), C.K. Chow showed that a classifier allowed to *reject* uncertain inputs trades a bit of coverage for a lower error rate, and derived the optimal rejection rule. The modern name is **selective prediction** (or selective classification): Geifman and El-Yaniv applied it to deep neural networks in 2017. You pick a threshold; above it the model answers, below it the model abstains. The curve you tune is risk vs coverage: how many errors you accept for how much automation.
A few variations are worth knowing:
- **Risk-scaled thresholds.** Different actions deserve different bars inside the same system. Reading a balance can go ahead at a lower confidence than moving money
- **An abstention band.** Instead of one cutoff at 0.5 (yes/no), use three zones: no, uncertain, yes. Small fluctuations around 0.5 then land in "uncertain" instead of firing opposite automatic actions
- **Hierarchical backoff.** When the model isn't sure about the fine-grained label, report the coarser parent label instead of dropping the answer
- **Conformal prediction.** Vovk, Gammerman and Shafer's framework (2005; see Angelopoulos and Bates 2021 for a readable intro) turns scores into prediction *sets* with a distribution-free coverage guarantee (e.g. "the right label is in this set 90% of the time"), calibrated on your own held-out labeled data. You don't have to trust the vendor's calibration at all
The whole family rests on one assumption: that confidence *ranks* errors well, i.e. wrong answers tend to have lower confidence than right ones. That's related to [[AI Model Calibration|calibration]] but not the same thing. A model can be calibrated on average and still be bad at separating its own mistakes.
## How Jev makes it cheap
[[Jev]] returns a probability with every answer, by construction. A Choice or a Score comes back with a full distribution plus a `confidence` field; a Noul *is* a probability, so it needs no separate confidence. TypeSafe trains for [[AI Model Calibration|calibration]] (RLCD), and the docs treat "I don't know" as a feature: "If an intelligent system... cannot express honest uncertainty, the system cannot be trusted."
The `confidence` field is a simple formula (see [[System One Primitives]]): the top probability rescaled so that a uniform distribution gives 0 and a certain one gives 1, i.e. `(n * p_max - 1) / (n - 1)`. It describes the *shape* of the answer, not whether it's correct. You also get the raw `probabilities`, so you can compute your own measure.
Since the gate is plain code, you can re-tune thresholds without new API calls. That's the part I find really practical.
## Worked examples from the docs
**Risk-scaled thresholds (voice banking).** One Choice over `check_balance` / `approve_transfer` / `other`:
```python
if action.confidence < 0.6:
route_to_support_agent(account_id) # global floor
elif action.choice == "check_balance":
show_balance(account_id) # worst case: user hears their balance
elif action.choice == "approve_transfer":
if action.confidence > 0.85:
approve_transfer(account_id) # high stakes, high confidence
else:
ask_user_to_confirm(...) # high stakes, moderate confidence
```
One floor for everything, then a bar per action based on what a wrong call would cost.
**An abstention band (moderation repeatability).** The Choice self-consistency cookbook ran 8 moderation questions on one borderline post, 15 times. Taking the top label every time, Jev agreed with itself 90.8% of the time (it flipped between Harassment and Violence, for instance). Adding one rule, "top probability under 0.60 means uncertain, send to a human", took policy agreement to **99.2%**, with 25.8% of answers routed to review and zero cases where two runs produced two different concrete labels. No extra calls. The Noul version uses `< 0.30` no, `0.30 to 0.70` uncertain, `> 0.70` yes.
**Hierarchical backoff (SEC filings).** 60 annual reports, one Choice over 75 industry groups. Confidence ≥ 0.9 splits the set in half. The confident half was right 27/30 times (90%). The unsure half was right only 12/30 times (40%) at group level, but reporting those same answers at the *division* level (the parent category) made them right 70% of the time. Overall, 48 of 60 useful answers instead of 39. The broad label follows from the narrow one, so there is no second call. See [[Hierarchical Classification]].
**Min-aggregated confidence.** When one result is built from several answers (a date from month, day and year; a function call from its arguments), take the *minimum* confidence over the parts, not the product. One bad part spoils the whole, and a product shrinks with every extra argument even when nothing is shaky. The date extraction cookbook sends anything under 0.60 to review.
**Confidence on every question you branch on.** The intent routing page checks confidence on the complexity Score too, not only on the routing Choice: a complaint goes to a human if complexity is high *or* if the model isn't sure about the complexity.
## Gotchas
- **Confidence isn't correctness.** A peaked distribution can still be wrong. Validate on labeled examples before you trust a threshold
- **Thresholds don't transfer between question types.** The docs found a Noul "refund?" at 0.22 while a yes/no Choice on the same question gave yes at 0.01. Tune per question
- **Bands have edges too.** A value near 0.30 or 0.70 can still flip between runs. A band reduces flips; it doesn't remove them
- **Calibration is distribution-specific.** Archer Hume measured an expected calibration error of 0.031 on MMLU; Rajesh Beri measured 0.107 on synthetic support tickets, with Nouls underconfident and Choices overconfident. Measure on your own data
- **Composition breaks calibration.** Anthony Maio's point: individually calibrated answers don't automatically compose into a calibrated workflow once you pass them through thresholds, weights and branches. A conformal layer on top, refreshed with fresh labels, is the robust answer
- **Don't threshold everything.** If you just need the best option, take the argmax. Gate the decisions where a wrong call costs something
- **Pin the model version.** Thresholds tuned on `jev-1.13.0` can drift when `jev-latest` moves
## My take
This is, to me, the single most important pattern in the TypeSafe docs, and it applies to any model that gives you a real probability. It's how you build AI systems that know when to step aside. The [[Human-in-the-Loop]] conversation usually treats the human as a blanket safety net ("a human reviews everything"). Confidence gating makes the human a targeted resource: they see the 26% that's genuinely ambiguous, and the machine handles the 74% it's sure about.
What I'd add in practice: plot confidence against accuracy on a few hundred of your own labeled cases before choosing any number, start conservative, and write the thresholds as named constants in one file so humans can review them. And if the decision matters, put a conformal layer on top. It turns "trust the vendor's calibration" into "trust my own held-out data", which I find a MUCH easier promise to keep.
## References
- [Confidence-gated routing (TypeSafe docs)](https://docs.typesafe.ai/patterns/confidence-routing)
- [Confidence (TypeSafe docs)](https://docs.typesafe.ai/confidence)
- [Intent routing (TypeSafe docs)](https://docs.typesafe.ai/patterns/intent-routing)
- [Self-consistency: choices cookbook (TypeSafe docs)](https://docs.typesafe.ai/cookbooks/consistency_choice_cookbook)
- [Self-consistency: nouls cookbook (TypeSafe docs)](https://docs.typesafe.ai/cookbooks/consistency_noul_cookbook)
- [Classification using confidence cookbook (TypeSafe docs)](https://docs.typesafe.ai/cookbooks/classification_using_confidence)
- [Date extraction cookbook (TypeSafe docs)](https://docs.typesafe.ai/cookbooks/date_extraction_cookbook)
- [Chow, On optimum recognition error and reject tradeoff (IEEE Trans. Information Theory, 1970)](https://ieeexplore.ieee.org/document/1054406/)
- [Geifman and El-Yaniv, Selective Classification for Deep Neural Networks (2017)](https://arxiv.org/abs/1705.08500)
- [Angelopoulos and Bates, A Gentle Introduction to Conformal Prediction (2021)](https://arxiv.org/abs/2107.07511)
- [Jev's Architecture Unmasked (Archer Hume)](https://archerhume.com/posts/jevs-architecture-unmasked/)
- [Rajesh Beri on Jev calibration and decomposition](https://www.beri.net/article/typesafe-jev-typed-decision-model-calibration-decomposition-shadow-eval)
- [Jev: the language model that won't talk (Anthony Maio)](https://anthonymaio.substack.com/p/jev-the-language-model-that-wont)
## Related
- [[AI Model Calibration]]
- [[Human-in-the-Loop]]
- [[AI Model Cascades]]
- [[Hierarchical Classification]]
- [[Self-Consistency]]
- [[System One Primitives]]
- [[Model routing]]
- [[Jev]]
- [[Decision Models (DMs)]]
- [[AI Guardrails]]