AI/ML Explained: Hallucination & Calibration

Day 48 · 2026-07-05 · Difficulty ★★★☆☆
For: engineers with coding experience, non-AI background
Engineering companion → super-individual D10: Hallucination mitigation (guardrails, verification in production)
This issue covers the mechanism: why models fabricate, why confidence is untrustworthy, why alignment makes it worse. "How to fix it" lives in the engineering weekly.

Statistical Origin of HallucinationStatistical Origin

mechanismtraining objective
One-line analogy

Think of an LLM as an API that always returns 200 OK: query a record that doesn't exist and it won't return 404 or null—it fabricates a perfectly-formatted response on the spot. The problem isn't that it "wants to deceive you"—it's that its architecture has no "not found" return value at all. At every step it must emit a token; "silence" or "unknown" is never the default option.

What it solves + how it works

First, dispel a misconception: hallucination is not a bug, it's a mathematical inevitability of the training objective. An LLM does next-token prediction—essentially density estimation over language, learning a distribution P(next word | context). This objective contains no fact-checking term whatsoever: the model is rewarded for "sounding like the training data," not for "being correct."

OpenAI's Kalai et al. (2025) nailed this down: even with 100% error-free training data, the cross-entropy objective itself forces hallucination. The intuition—generating a valid answer is no easier than a binary classification task "is this statement true?"; and for a rare fact seen only once or twice in training (a person's birthday, a paper's author), the model has insufficient statistical signal to tell it apart from plausible wrong answers, so the error rate has an irreducible lower bound.

The nastier layer is evaluation incentives: nearly every benchmark scores "1 point for correct, 0 for both wrong and blank." Under this rule, the expected score of guessing is strictly higher than honestly saying "I don't know"—just like on a standardized test, leaving it blank beats guessing. So the entire training-evaluation pipeline systematically trains the model into a confident test-taker, not an honest knower.

Code example
from openai import OpenAI
client = OpenAI()  # needs OPENAI_API_KEY

# Ask about a purely fictional entity—the model has no "not found" return
r = client.chat.completions.create(
    model="gpt-5",
    messages=[{"role": "user",
               "content": "Describe the contributions of 2019 Turing Award winner Zael Kirmani"}],
    logprobs=True,  # get per-token log probabilities
)
msg = r.choices[0].message.content
print(msg)  # → likely a fluent but entirely fabricated biography

# Key observation: token probabilities of the fabrication are often NOT low—
# the model "confidently fabricates." High confidence != grounded.
lp = r.choices[0].logprobs.content
print(sum(t.logprob for t in lp) / len(lp))  # mean logprob
Common pitfall + practical scenario
"Hallucination comes from errors in training data, so cleaning the data will cure it"—wrong. Kalai et al.'s core conclusion is precisely that perfect data cannot cure it, because the root cause is the objective function and scoring rules, not dirty corpora. Cleaning data reduces some hallucinations, but as long as "guessing beats blank," the model always has an incentive to fabricate.
📌 Scenario: when using AI for a literature review, treat every "specific citation" it gives (title, author, year, page) as a guess to be verified by default, not as fact. Rare, low-frequency information is exactly where hallucination concentrates—allocate your verification effort by "how common is this fact in the training corpus."
Takeaway + reflection
💡 Hallucination isn't the model being "broken"—it's been trained into a test-taker that "guesses rather than leaves blank." The root cause is the objective and scoring, not the data.
🤔 If we changed the scoring to "wrong answers penalized, blanks get 0," would the model automatically learn to say "I don't know"? What does that hint about mitigation?

CalibrationCalibration

metricconfidence
One-line analogy

Whether calibration is good is easiest to grasp via weather forecasting: a forecaster who said "70% chance of rain" 100 times is well-calibrated if it actually rained on about 70 of those days. That's separate from how "accurate" he is—he can always say 70% and never 100% (not sharp enough), but as long as the frequencies match, his confidence is a trustworthy signal. Whether an LLM's confidence can be used as an alert threshold depends on the same thing.

What it solves + how it works

The model attaches an implicit confidence (token probability) to every answer. Calibration asks: does its stated confidence match the actual accuracy? Bin predictions by confidence; ideally "in the confidence-0.8 bin, exactly 80% are correct." The metric is ECE (Expected Calibration Error)—the weighted absolute difference between each bin's "average confidence" and "actual accuracy," closer to 0 is better:

Reliability Diagram: x=model confidence, y=actual accuracy

1.0 ┤ ideal = diagonal (say p% → p% correct)
    │                     
0.7 ┤               ← ideal
0.5 ┤        ← actual
    │
    └────────────────────→ confidence
       0.5      0.7    0.9
↑ curve falling below the diagonal = overconfident: says 0.9 but only 0.6 correct

The classic fix is Temperature Scaling (Guo et al. 2017): don't touch model weights, just divide the output logits by a learned temperature T, then softmax. T>1 flattens an over-peaked distribution, pulling confidence back in line with true accuracy—one parameter, post-hoc, no accuracy loss. Note it fixes "the confidence number is untrustworthy," it doesn't fix hallucination itself: calibration tells you how much to believe, but won't make a wrong answer right.

Code example
import numpy as np

def expected_calibration_error(confs, correct, n_bins=10):
    # confs: confidence per prediction (0~1); correct: whether right (0/1)
    bins = np.linspace(0, 1, n_bins + 1)
    ece = 0.0
    for i in range(n_bins):
        # predictions falling in this confidence bin
        m = (confs > bins[i]) & (confs <= bins[i + 1])
        if m.sum() == 0: continue
        acc  = correct[m].mean()   # actual accuracy of this bin
        conf = confs[m].mean()     # mean confidence of this bin
        # gap × fraction of samples in bin, accumulate
        ece += (m.sum() / len(confs)) * abs(acc - conf)
    return ece

# Overconfident model: confidence broadly above true accuracy → large ECE
confs   = np.array([0.9, 0.9, 0.8, 0.95, 0.7])
correct = np.array([1,   0,   0,   1,    0])   # 5 questions, only 2 right
print(f"ECE = {expected_calibration_error(confs, correct):.3f}")
Common pitfall + practical scenario
"Well-calibrated = the model is accurate"—two different things. A model that only guesses, with 50% accuracy, is perfectly calibrated as long as it honestly reports 0.5 confidence every time. Calibration measures "is the confidence trustworthy," not "is the answer correct." You want both: high accuracy and honest confidence.
📌 Scenario: when building an "AI-assisted decision" pipeline, don't take model output as conclusion directly—first run a batch of questions with known answers and plot a reliability diagram to see if it's overconfident in your domain. If it's only right 60% of the time when it says "very confident," you know to discount its "certainty" by 30% before trusting it.
Takeaway + reflection
💡 Calibration = confidence aligned with true accuracy; it tells you "how much to believe," but won't make a wrong answer right.
🤔 Which of the AI's judgments do you currently trust because you were persuaded by the certainty of its tone rather than by calibrated confidence?

Why RLHF Hurts CalibrationRLHF & Calibration

alignmentmode collapse
One-line analogy

Picture an honest advisor who says "I'm not too sure about this", optimized for half a year against a "customer satisfaction KPI"—he gradually becomes a salesman who's always emphatic. Sounds more credible, more reassuring, yet is actually less accurate. That's exactly what RLHF does to a model: to please human preferences, it sacrifices the honesty of its confidence. You know the old distributed-systems tradeoff—sacrificing consistency for p99 experience.

What it solves + how it works

A counterintuitive fact: the raw model right after pretraining (the base model) is actually quite well-calibrated—it only does next-token prediction, so its probabilities are its true statistical beliefs about language. But after RLHF (Reinforcement Learning from Human Feedback, aligning the model to human preferences) and instruction tuning, calibration degrades markedly. The GPT-4 technical report has a famous figure: pretrained GPT-4's reliability curve hugs the diagonal, while after RLHF the curve visibly bulges toward the overconfident side.

The mechanism lies in the shape of human preference. When annotators score responses, they systematically prefer answers that are confident, fluent, and give a clear conclusion, and dislike hedging like "it depends…" or "I'm not sure." The reward model learns this preference, and PPO optimization squeezes probability mass onto a few high-confidence phrasings—this is mode collapse: the distribution collapses from "honestly spreading out uncertainty" into "always looking very certain."

Confidence on the same uncertain question, across two stages

Base (pretrained): 0.55 ← spreads out uncertainty, near true accuracy, well-calibrated
                      ↓ RLHF optimizes "humans prefer confident answers"
After RLHF:       0.92 ← tone gets certain, actual accuracy unchanged → overconfident

Cost: more likeable · more fluent · but confidence no longer trustworthy (calibration tax)

This explains a daily observation: aligned models like ChatGPT / Claude read as more assured than raw base models, and therefore lower your guard more easily. It's not that the model "got dumber"—it was optimized into a tone that feels good. After RLHF, the certainty of tone and the reliability of content have become decoupled.

Code example
from anthropic import Anthropic
client = Anthropic()  # needs ANTHROPIC_API_KEY

# One prompting trick against overconfidence: explicitly ask for a "calibrated"
# numeric confidence, and require thinking "when would I be wrong" first—
# forcing the model to spread out its uncertainty
prompt = """Answer the question, then give a confidence 0-100.
Confidence definition: across all questions where you give this confidence,
exactly that fraction should be correct.
First list scenarios where you might be wrong, then give the score.

Question: What is the exact depth in meters of the deepest point in the Pacific?"""

r = client.messages.create(
    model="claude-opus-4-8", max_tokens=400,
    messages=[{"role": "user", "content": prompt}])
print(r.content[0].text)
# "Calibration definition + reason-about-errors first" usually yields a more
# honest score than just asking "how confident are you"
Common pitfall + practical scenario
"Just ask the model 'how confident are you' and use the number"—not necessarily. After RLHF, the model's verbalized confidence is also polluted by "appearing confident is more likeable" and tends to be inflated. Having it first list failure scenarios, then give a score with a calibration definition is closer to the truth than plainly asking "how confident"—but still validate against your own historical data, don't take it at face value.
📌 Scenario: when using AI for high-stakes judgments like investing or tech selection, be wary that its assured tone is itself an optimized artifact. Deliberately ask "under what premises would you be wrong? Give me the strongest counterargument"—you're manually prying back open the uncertainty that RLHF flattened.
Takeaway + reflection
💡 RLHF makes the model more usable and likeable, at the cost of calibration—the certainty of tone and the reliability of content are now decoupled.
🤔 An assistant that's "honest but often unsure" vs one that's "confident but occasionally wrong"—which would you trust more? Humans' answer to this is the very source of the sacrificed calibration.
Engineering companion → super-individual D10: hallucination mitigation in practice

Knowledge Boundary & Self-KnowledgeSelf-Knowledge

mechanismP(True)
One-line analogy

Like a cache-miss signal: internally the system actually knows this was a miss, but if it doesn't expose the miss signal to the upper layer, the caller wrongly assumes every access hit. A model is the same—internally it has a signal distinguishing "I know" from "I'm fabricating" (e.g. the entropy of the output distribution, internal activations), but by default it doesn't report it. Having it self-evaluate means explicitly exposing that cache-miss signal.

What it solves + how it works

The core question: does the model know what it doesn't know? Anthropic's Kadavath et al. (2022, the paper is literally titled "Language Models (Mostly) Know What They Know") gave a somewhat optimistic answer: large models to a substantial degree "know whether they know." They used two operational probes:

  • P(True)—the model first gives an answer, then evaluates the probability that this answer is true. Across diverse tasks this self-assessment is reasonably calibrated and improves with model scale;
  • P(IK) (Probability I Know)—without looking at any specific answer, the model directly predicts "can I answer this?" The model can be trained to produce a usable P(IK) signal.

The mechanistic intuition: when the model is confident, the output distribution is sharp (a few tokens with very high probability, low entropy); when unsure, the distribution is flat (many tokens with similar probability, high entropy). This "internal uncertainty" is a genuine signal—the problem was never that the model lacks a sense of boundary, but that the default generation pipeline throws this signal away, emitting only the final answer. Having it explicitly do a P(True) self-eval picks the discarded signal back up.

Of course it's "Mostly," not "Always": the more a question is unseen in training and requires multi-step reasoning, the less reliable the self-eval—echoing the statistical origin from section 1, the rare low-frequency region is exactly where self-knowledge also fails.

Code example
from anthropic import Anthropic
client = Anthropic()

def answer_with_self_eval(question):
    # Step 1: answer normally
    a = client.messages.create(
        model="claude-opus-4-8", max_tokens=300,
        messages=[{"role": "user", "content": question}]
    ).content[0].text

    # Step 2: a fresh independent call to assess P(True) of the answer above
    # independent call avoids it "defending" what it just said
    check = client.messages.create(
        model="claude-opus-4-8", max_tokens=10,
        messages=[{"role": "user", "content":
            f"Question: {question}\nCandidate answer: {a}\n"
            "What is the probability this answer is correct? Reply one number 0-1."}]
    ).content[0].text
    return a, float(check.strip())

ans, p_true = answer_with_self_eval("Who formulated Bayes' theorem?")
# low p_true → trigger human review / route to RAG, don't trust directly
Common pitfall + practical scenario
"P(True) self-eval catches all hallucinations"—it can't. It's Mostly: useful in well-trained domains, but on rare, long-reasoning questions the self-eval also fails—overconfident questions tend to be overconfident even in self-assessment. So P(True) is a cheap first filter, not the last line of defense; low scores trigger escalation (route to retrieval, to human), high scores do not mean exempt from review.
📌 Scenario: when building a personal AI workflow, add a "self-eval gate" to critical answers—use one independent call to have the model score P(True), and below a threshold auto-route to RAG retrieval or flag "needs human verification." Far cheaper than being burned later by one confident piece of misinformation.
Takeaway + reflection
💡 The model "Mostly knows what it doesn't know"—the uncertainty signal exists; the default pipeline drops it, and explicit self-eval picks it back up.
🤔 If the model internally has an "I don't know" signal yet doesn't voice it by default, is the responsibility the model's, or ours for only rewarding "giving an answer"?

Further ReadingFurther Reading

Deep QuestionsDeep Questions

1. Section 1 says "guessing beats blank" forces hallucination; section 4 says the model "Mostly knows what it doesn't know." Do these contradict?
No contradiction—they're complementary and point at the same mitigation direction. Section 4 says the model internally has an uncertainty signal (P(True)/P(IK) reasonably calibrated)—it's not "blind." Section 1 says: current evaluation rules don't reward the model for voicing that signal, and instead reward "guess even when unsure." Together, a large part of hallucination is incentive misalignment rather than capability deficit: the model knows it's uncertain, but external rules tell it "expressing uncertainty loses points, only a correct guess gains points," so it rationally chooses to answer with eyes closed. This is exactly Kalai et al.'s policy suggestion—fix the evaluation: make "I don't know" score no worse than "a wrong guess," even positively reward calibrated abstention. In your own workflow you can go first: when designing prompts and trust rules, make "honest abstention" beat "confident wrong answer," fixing this incentive on a small scale.
2. Temperature scaling (calibration) and sampling temperature (Day 45 decoding) are both "temperature" and both modify softmax—are they the same thing?
The math form is almost identical (divide logits by T, then softmax), but the purpose and point of action are entirely different—don't conflate them. Sampling temperature (at decoding) changes generation behavior: high T is more random and creative, low T more deterministic and conservative; it affects "which token to emit." Calibration temperature (Guo 2017) changes the reported confidence number: using a T learned on a validation set to flatten over-peaked probabilities into alignment with true accuracy; it doesn't change the most likely answer (argmax is unchanged, since it scales all logits proportionally), only "how much confidence to report for this answer." One moves "what to pick," the other "how much to believe it." The interesting connection: both admit "the raw absolute values of logits can't be used directly as probabilistic beliefs"—decoding temperature is tuned to control diversity, calibration temperature to make the numbers trustworthy. A distributed-systems analogy: sampling temperature is like random weights in load balancing (which route), calibration temperature is like a calibration coefficient on a monitoring metric (how much to trust the reading).
3. If human preference for "confident answers" is the root of sacrificed calibration, can we just add "calibration" to the training reward and have both?
The direction is right, but there's a real tension—no free lunch. You can indeed add a calibration reward to RLHF (penalize overconfidence, reward honest abstention); the field is also trying to "train models to express uncertainty." The difficulties are threefold: (a) conflicting objectives—humans prefer confidence vs calibration demands honesty; the two reward terms fight, and weighting them is a product value judgment; weight it too heavily and the model becomes timid, full of "I'm not sure," and UX collapses; (b) the calibration signal is hard to get—at training time you don't necessarily have a "ground truth" per response to compute how confident it should be, especially for open-ended generation; (c) Goodhart risk (Day 47, alignment failures)—once "expressing uncertainty" becomes an optimized metric, the model may learn to perform uncertainty (fake hesitation even when it should be confident) to game the reward, rather than truly become more calibrated. So in practice it's more of a division of labor: on the training side, try not to wreck calibration too badly; on the inference side, use P(True) self-eval, temperature scaling, and external verification (RAG/tools) to restore trustworthiness. "Having both" is an asymptotic goal, not a switch.
4. Stringing the four sections together: from generation to your trust, how many gates can you set on "a confident answer from AI"?
Design it as a data pipeline with quality gates, four gates from cheap to expensive: ① source triage (section 1)—first judge whether this info is high-frequency or rare/low-frequency in the training corpus; rare (specific citations, birthdays, niche numbers) defaults to high hallucination risk, flag "to verify." ② self-eval gate (section 4)—one independent call to get P(True), escalate below threshold; cost is one API call, the cheapest filter. ③ calibration discount (sections 2, 3)—remember that post-RLHF models are broadly inflated in tone, so discount their "certainty"; if you can, plot a reliability diagram on your domain's historical questions to get the empirical discount coefficient. ④ external grounding—high-risk conclusions must land on a verifiable external source (RAG retrieval, running code, checking an authoritative database), making the answer refutable rather than merely "sounding right." The key mindset: allocate effort across these four gates by risk and frequency—not every answer gets the full suite, but "low-frequency info + high-risk decision" stacks all four, while "high-frequency common sense + low-risk chat" needs none. This itself is the core skill of a super-individual: spend your limited verification attention where hallucination is most likely and the cost is highest.