Soba Labs Blog

Stop asking the LLM how confident it is

8 min read Simon Budziak By Simon Budziak

A stream of luminous tokens flows left to right toward a single gold threshold gate. Most pass straight through, while a small subset is diverted upward along one gold path, the exceptions being routed elsewhere.

Most teams building an agent eventually add a check that sounds responsible: ask the model how confident it is, then route the low-confidence answers to a human. It feels like a safety net. It behaves more like a coin flip. A language model’s self-reported confidence is badly calibrated and clusters near certainty, so gating on it means gating on noise. The fix is not a better prompt. Compute a signal you can actually measure, gate on it with a plain deterministic rule, and escalate the exceptions to a person. This post covers why verbalized confidence fails, what a deterministic gate is, how to wire one into a LangGraph agent, and where to put the threshold.

Why self-reported confidence is not a real signal

Anyone who has shipped an LLM feature has watched this happen. You ask the model to rate its own confidence, it returns 0.95, and it returns 0.95 just as cheerfully on the answers it got wrong. The number is fluent, specific, and almost entirely disconnected from whether the answer is correct. Asking a model to grade its own work hands the audit to the least reliable component in the system.

The reason is structural. The training that turns a raw model into a helpful assistant, learning from human feedback, rewards answers that sound helpful and self-assured. It does not reward the model for saying “I am not sure.” So the model learns to sound sure, and its stated confidence drifts toward the top of the scale whether or not the answer deserves it. You are asking for a number from the one part of the pipeline built to be agreeable.

That would be harmless if nobody acted on it. But a confident tone makes the people downstream trust an answer more, not less, so a wrong answer wrapped in “95% confident” is more dangerous than the same answer with no number attached. It manufactures trust in exactly the place you have not earned it.

This is not a fringe position. It is built into the tools you would actually ship with. LangGraph provides human-in-the-loop interrupts so a run can “pause before executing critical actions” and “let humans review and modify LLM outputs or tool calls before continuing.” A framework only builds that if the working assumption is that the model cannot be the final judge of its own output. So the real question is not whether to review, it is which cases to review, and the model’s self-reported confidence is the wrong thing to decide that with.

The trap: a confidence number the model writes about itself looks like a control, so teams ship it as one. It reads as diligence and behaves as decoration.

Drake Hotline Bling meme. Top panel, Drake rejecting: trusting the LLM's self-reported confidence. Bottom panel, Drake approving: gating on a signal you can actually measure.

What a deterministic confidence gate actually is

So replace the number with something you can measure and control.

A deterministic confidence gate is a plain rule that decides whether the system acts on its own or hands the case to a person, based on a signal you compute rather than a number the model reports about itself. The signal is whatever genuinely correlates with being right in your domain: the retrieval score or margin behind a RAG answer, how cleanly a rule matched, the agreement count when you sample the model several times (self-consistency), a schema or validator result, or a cross-check against a system of record. Any of those you can log, plot, and calibrate. “How sure are you?” you cannot.

The gate needs a decision it can inspect, not a paragraph. Have the agent emit a validated structured output rather than free-form prose: bind a schema in LangChain (structured output), where a Pydantic schema gives you “automatic validation” on every field instead of text you have to parse and hope about. Note the trap this does not solve on its own: a schema field the model fills in called confidence is still the model grading itself. The signal you gate on is computed outside the model, from things it cannot talk its way around.

The word that carries the weight is deterministic. Same inputs, same route, every time. That makes the gate testable, and it makes the threshold a dial you can turn and then measure. You cannot unit-test a vibe, and you cannot nudge it two points and replay last month’s traffic to see what changed.

A flow diagram. An Agent node emits a validated decision and a measurable signal into a deterministic gate, a plain rule that tests whether the signal is at or above a threshold. Cases at or above the threshold auto-proceed, the majority path. Cases below it follow a gold path that escalates to a person, the exceptions.
The model proposes. A deterministic rule, not the model's self-report, decides what a human sees.

Let a different model judge the first one

Often the strongest signal is a second model. Have one model do the work and a separate model judge the result: the generator produces the answer, the judge scores whether it holds up. Because the judge is a different model looking at the output cold, it is not the generator grading its own homework, which is the exact failure this whole post is about.

The economics work in your favor. The generator can be a heavyweight (say GPT-5.5), while the judge can be a lighter, cheaper model (a smaller Claude, for instance), because deciding “is this answer actually supported?” is usually easier than producing the answer in the first place. A cheap judge is one you can afford to run on every output, which is the point, since the whole job is to catch the bad ones before they ship.

The judge does not make the decision. It emits a structured verdict (a pass or fail, a score, a short reason) through structured output, and the deterministic gate acts on that verdict exactly as it would on any other signal. The judge produces the number, the plain rule still decides proceed or escalate. This is the LLM-as-judge pattern, which LangChain documents as an evaluator; the same idea runs online as a judge node in the graph.

Two honest caveats, because a judge is still a model. Keep it independent: a different model, handed only the output to assess, not the generator’s own explanation of why it is right. And for anything high-stakes, do not lean on a single judge. Run a small panel and take the majority, or combine the judge’s verdict with a computed signal such as a retrieval score, so no one model’s opinion quietly becomes the final word. A judge is a far better signal than a self-report. It is not a licence to stop measuring.

Wiring the gate into a LangGraph agent

In LangGraph this is two pieces: the node that produces the decision and the signal, and a routing function that gates on the signal. The routing function is ordinary Python.

from typing import Literal

THRESHOLD = 0.80  # a dial you calibrate, not a constant handed down from on high

def confidence_gate(state: AgentState) -> Literal["auto_proceed", "escalate"]:
    # `signal` was computed deterministically upstream: a retrieval margin,
    # a rule-match score, an agreement count across samples, a validator result.
    # It is never the model's answer to "how confident are you?".
    return "auto_proceed" if state["signal"] >= THRESHOLD else "escalate"

builder.add_conditional_edges(
    "assess",
    confidence_gate,
    {"auto_proceed": "act", "escalate": "human_review"},
)

The escalate path is where a person enters. LangGraph’s interrupt support pauses the run, surfaces the case, and resumes when a decision comes back.

from langgraph.types import interrupt

def human_review(state: AgentState) -> dict:
    # Pauses the graph and surfaces the case to a reviewer. The run resumes
    # when you invoke the graph again with Command(resume=<the human's decision>).
    decision = interrupt({
        "proposed": state["decision"],
        "signal": state["signal"],
        "reason": "signal below threshold",
    })
    return {"decision": decision}  # the person's call replaces the model's

Resuming needs a checkpointer and a thread id so the paused run has somewhere to wait. The shape is the point: the model proposes a decision, a deterministic rule decides whether that decision is allowed to stand on its own, and only the cases the rule flags ever reach a person. Nobody reviews the routine 95%. Somebody always reviews the ones the signal could not vouch for.

Where the threshold goes, and who owns it

The threshold is a business decision wearing a technical costume. It is the trade between how much the system handles alone and how much it sends to a person, and the right setting depends entirely on what a wrong call costs.

Because the gate is deterministic, you can set it the honest way. Take labeled cases, sweep the threshold, and look at what auto-proceeds when it should not against what you escalate needlessly. A step that moves money, touches a contract, or affects someone’s health escalates aggressively, even at the cost of reviewing plenty of cases that would have been fine. A low-stakes step can run wide open and flag only the genuine outliers. Same machinery, different dial.

This is the concrete version of a principle that is easy to say and easy to fake: keep a human in the loop on what matters. A deterministic gate is what turns what matters into a definition you own and can defend, rather than a hope that the model will raise its hand at the right moment.

The takeaway

Asking a model how confident it is feels like adding a control and mostly adds a reassuring number. The self-report is miscalibrated by design, clusters near certainty, and nudges the people downstream to trust it more than they should. Gate on a signal you compute and can calibrate, and escalate the exceptions to a person.

That is how we build judgment-heavy agentic systems at Soba Labs: the model proposes, a deterministic gate decides what a human sees, and people stay at the edge on the cases that carry real risk. It is the same lesson as where the bottleneck moved once writing code got cheap. The hard part was never producing an answer. It was knowing which answers you are allowed to trust.

Sources

Book a call

Let's find the work you can hand off.

Bring one workflow that's slow, repetitive, or stuck on a few experts. We'll map what a custom agentic system could do, and what should stay human.

No sales pitch. Just a straight read on whether it should become software, training, or nothing yet.

Not ready for a call? Write to [email protected]