Lesson 4 · Confidence and routing

About 25 minutes · the lesson the benchmark was really about

Ninety-three percent, and wrong the problem

Goal: feel the difference between a probability and a guarantee.

In the community benchmark of 2026-09-17, call 028 was an incomplete German transcript. The expected label was "unclear". Jev labelled it "not sales" with a probability of 0.93. Thirty-nine other calls went well; this one did not, and it did not look uncertain (benchmark brief, section "blind spot").

What 0.93 means, and what it does not

A calibrated 0.93 is a claim about frequency: across many answers given at 0.93, about 7 in 100 are wrong. It is not a promise about this answer. Call 028 was one of the 7. A workflow that treats 0.93 as "certain" will act on every one of those 7 with full force.

The brief's conclusion became this course's refrain: give uncertainty a route. Two changes fix call 028 without touching the model. First, an unclear option so the honest answer exists (lesson 2). Second, a confidence floor below which no automated action fires, plus a higher bar for actions that are expensive to undo.

The rest of this lesson is about that second change. It rests on one field in every Choice and Score answer: confidence.

A second axis, not the top probability concept

Goal: explain why confidence and the winning probability are different numbers.

The docs describe confidence as "a statistic computed from the distribution" over the options or levels, collapsed to a single 0 to 1 number that says how peaked the distribution is (docs: Confidence). The formula is not published, and this course will not invent one. What can be said from the recordings:

Recorded answer (2026-09-19)DistributionTop probabilityConfidence
Stripe message → departmentbilling 0.69 · technical 0.31 · sales 00.690.53
Cut-off call → outcomeunclear 0.99 · support 0.010.990.98
Cut-off call → mood (Score)level 0 at 0.89 · level 1 at 0.110.890.84
Numbers-only mood ladder0.02 · 0.50 · 0.480.500.26
Docs: requested_resolutionexchange 0.37 · refund 0.29 · replacement 0.24 · info 0.100.370.16

Confidence falls faster than the top probability as the mass spreads out. Two options at 0.50 / 0.48 give 0.26, not 0.50. Four options with a 0.37 leader give 0.16. That is the useful property: confidence punishes "several plausible answers" harder than the top probability alone does.

Choice and Score onlyNouls have no confidence field. For a Noul, distance from 0.5 plays the same role: 0.93 and 0.07 are confident, 0.55 is not.
Three rangesThe docs frame it as high → act automatically, medium → confirm, flag or gather more, low → hand to a human or another system. Where the lines sit is yours to set.
Not a quality scoreConfidence says how peaked the answer is, not how good the question was. A confidently wrong answer to a bad question is exactly what call 028 looks like. Confidence gating reduces damage; question design reduces errors.

Thresholds scale with risk hands-on

Goal: set two thresholds for a real workflow and see what each setting lets through.

The docs' worked examples use a floor of about 0.5 for anything automated and a bar of 0.85 to 0.9 for actions that move money or cannot be undone (docs: choosing thresholds, pattern: confidence-gated routing). The simulator below routes nine recorded answers through two sliders. The first six are this course's recordings; the last three are from the docs and from the benchmark. One of them is call 028.

Threshold simulator

"Risky" marks an action that is costly to undo: booking a site visit, issuing a refund, closing a ticket. Move the sliders until no wrong answer is acted on unattended, then look at how much work went to humans.

What the simulator teaches

  • At the docs' defaults (0.50 / 0.85), call 028 still gets acted on. A threshold alone does not catch a confident miss. Only the unclear option (which the benchmark's question set lacked) or a human sample catches it.
  • Push the high bar to 0.95 and call 028 goes to "confirm", at the price of two more confirmations per nine calls. That trade is a business decision, and it should be made from numbers like these, on your own data.
  • The 0.16 and 0.39 cases are exactly the ones the floor exists for. Both were legitimately ambiguous tickets. A human reading them for twenty seconds is cheaper than a wrong refund.

Three outlets for every decision code + no-code

Goal: implement act / confirm / human once and reuse it everywhere.

The docs' confidence-gated routing pattern in the shape this course uses. Python first, then the same thing as n8n nodes.

from typesafe_sdk import TypeSafeClient, Choice, Noul

client = TypeSafeClient()   # reads TYPESAFE_API_KEY

RISKY = {"sales_lead", "vendor_or_spam"}  # actions that are hard to undo
FLOOR, HIGH = 0.5, 0.9

def route(transcript: str) -> tuple[str, str]:
    r = client.system_one(
        state=transcript,
        questions={
            "outcome": Choice("What the caller wants from this call", {
                "sales_lead": "Wants a quote, purchase or consultation",
                "support": "Existing customer with a technical or billing problem",
                "vendor_or_spam": "Selling something to the company",
                "unclear": "Too little information to tell",
            }),
            "callback_requested": Noul("The caller asks to be called back or agrees to an appointment"),
        },
    )
    a = r.answers["outcome"]
    if a.choice == "unclear" or a.confidence < FLOOR:
        return "human", a.choice          # review queue
    if a.choice in RISKY and a.confidence < HIGH:
        return "confirm", a.choice        # ask a human to approve, or ask the caller
    return "act", a.choice
n8n readingHTTP Request node (lesson 6) → IF node: {{$json.answers.outcome.choice}} == "unclear" OR {{$json.answers.outcome.confidence}} < 0.5 → human branch. Second IF: choice in the risky list AND confidence < 0.9 → confirm branch. Everything else → act.
Make readingSame shape with a Router module and three filters. Put the thresholds in a Data Store or scenario variables so they can be tuned without editing filters.
Voice agent reading"confirm" can mean asking the caller: "Just to be sure, you would like us to come out for a quote?" The model's doubt becomes one polite sentence instead of a wrong booking.

Keep thresholds in one place

The TypeSafe agent skill gives the same advice for code: questions and thresholds in a single file, versioned, so tuning is a diff and not an archaeology project (docs: Agent skill). Log every routed decision with its confidence; lesson 6 uses that log to set the numbers from data instead of from taste.

Uncertainty on the other two primitives concept

Goal: gate a Score and a Noul without a confidence field to lean on.

Score: read confidence, then probabilitiesA churn-risk score of 1.0 with confidence 1.0 (lesson 3) is one clear level. A score of 1.12 with confidence 0.81 is level 1 with a lean toward 2. A score of 1.46 with confidence 0.26 is "the ladder failed". Same number range, three different meanings; confidence tells you which.
Noul: use distance from 0.5The docs' examples threshold Nouls at values like 0.7 or 0.8 for "yes" and 0.2 or 0.3 for "no", leaving a band in the middle for review. Recorded: 0.93 needs-attention (act), 0.20 (no), 0.03 (no). Nothing landed in the band on these four calls; on 400 calls something will.
Composite decisionsWhen a workflow combines several answers (lead quality from outcome + callback + mood), gate on the weakest input. One low-confidence component makes the whole decision a "confirm". Lesson 5 shows the composite pattern.

Rule of thumb from the docs, in one line each

  • Choice: confidence < floor → human, risky and confidence < high → confirm.
  • Score: act on the level only when confidence is high; otherwise read the two largest probabilities and treat it as a split.
  • Noul: two thresholds, a yes line and a no line; between them is review.
  • All three: unclear or other in the options where the model needs somewhere honest to go.
Sources: Confidence, cookbook: classification using confidence.

Quiz, then set your own two numbers quiz

Goal: never again treat a probability as a guarantee.

1. A Choice returns 0.50 / 0.48 / 0.02. Roughly what confidence should be expected?

Recorded: 0.26. Confidence punishes a split between plausible answers harder than the top probability does.

2. Benchmark call 028 was labelled wrong at 0.93. Which change would most directly have prevented an automated action?

The honest answer had nowhere to go. Thresholds limit damage from confident misses; an escape option lets the model not miss.

3. Which action deserves the higher confidence bar?

Thresholds scale with the cost of being wrong. A refund is hard to undo; a tag is one click to fix.

4. How is uncertainty read on a Noul?

Nouls have no confidence field. 0.93 and 0.07 are decisive; 0.55 is a review case.

Ship it

For the decision you have been carrying since lesson 1, write down two numbers and one list: the floor, the high bar, and which actions count as risky. Then add the third outlet to the workflow, even if it is just a Slack message saying "not sure about this one". Lesson 6 shows how to tune the numbers from a shadow run.

Primary source: docs.typesafe.ai/confidence and the community benchmark, in particular the blind-spot section.