Preventing AI Hallucinations: 7 Proven Techniques for LLM Reliability

Published 2026-07-26 · 16 min read

LLMs hallucinate. Even GPT-5 and Claude 4 — the best models of 2026 — confidently invent facts, citations, API signatures, and legal precedents that don't exist. You cannot eliminate hallucination entirely; the architecture of autoregressive language models makes some confabulation inevitable. But you can drive it down by an order of magnitude with the right combination of techniques.

This guide covers seven methods we use at DrAI to keep production LLM features reliable. Each is battle-tested, with the failure mode it addresses and the code to implement it. Stack them — no single technique is enough.

See Reliable Model Pricing →

Why LLMs Hallucinate (the 60-Second Version)

Autoregressive models generate the most statistically likely next token, not the most factually correct one. When the model's training data is thin on a topic, the most likely token sequence is still a fluent-sounding fiction. Three root causes:

  1. Knowledge gaps — the model never saw the relevant facts. Fix: RAG (Technique 1).
  2. Stale knowledge — facts changed since training. Fix: RAG + tool use (Techniques 1, 6).
  3. Overconfidence under uncertainty — the model doesn't know what it doesn't know. Fix: calibration, verification, abstention (Techniques 3-5, 7).

Technique 1: Retrieval-Augmented Generation (RAG)

The single most effective hallucination reducer. Instead of asking the model to answer from memory, retrieve relevant facts from your database and put them in the prompt. The model's job becomes reading comprehension, not recall — a much easier task with a much lower hallucination rate.

def grounded_answer(query):
    # 1. Retrieve relevant facts from your knowledge base
    chunks = hybrid_search(query, top_k=5)
    context = "\n\n".join(c["content"] for c in chunks)

    # 2. Force the model to cite sources
    prompt = f"""Answer the question using ONLY the context below.
If the context doesn't contain the answer, say "I don't know."
Cite [chunk_id] for every claim.

Context:
{context}

Question: {query}"""

    return llm.complete(prompt, temperature=0.1)

Grounded RAG typically cuts hallucination rates by 60-80% versus ungrounded generation. For the full production stack (chunking, hybrid retrieval, reranking), read our RAG implementation guide.

Critical caveat: RAG doesn't eliminate hallucination — the model can still misread the context or ignore it. Pair with Technique 4 (verification) for high-stakes use.

Technique 2: Structured Outputs (Constrain the Output Space)

Free-text generation gives the model infinite rope to hang itself. Structured outputs — forcing the response into a strict JSON schema — eliminate whole categories of hallucination by making invalid outputs literally ungeneratable.

from pydantic import BaseModel, Field
import openai, os

client = openai.OpenAI(
    base_url="https://ai.dr-ai.top/v1",
    api_key=os.environ["DRAI_KEY"],
)

class ProductSpec(BaseModel):
    name: str = Field(..., description="Product name")
    price_usd: float = Field(..., ge=0)
    in_stock: bool
    source_chunk_id: str = Field(..., description="Chunk ID this came from")
    confidence: float = Field(..., ge=0, le=1, description="0-1 confidence")

resp = client.beta.chat.completions.parse(
    model="gpt-5",
    messages=[{"role": "user", "content": "Extract product specs for SKU-123"}],
    response_format=ProductSpec,
)
spec = resp.choices[0].message.parsed
# spec is a validated ProductSpec — invalid JSON cannot be returned

With structured outputs + strict mode, the model cannot return a price as a string, or omit the source chunk. The schema is enforced at the token level. This is the single biggest reliability win for extraction tasks.

Technique 3: Low Temperature and Self-Consistency

Temperature controls randomness. For factual tasks, set temperature to 0-0.2. This alone removes a surprising amount of drift. But determinism has a cost — a single greedy pass can still be wrong.

Self-consistency is the upgrade: sample N diverse answers at higher temperature, then take the majority vote. The reasoning is that there are many wrong answers but usually only one right one, so the right answer tends to win votes.

def self_consistent_answer(query, n=5):
    """Sample n answers, return the most common one."""
    answers = []
    for _ in range(n):
        resp = client.chat.completions.create(
            model="gpt-5",
            messages=[{"role": "user", "content": query}],
            temperature=0.7,      # higher temp for diversity
        )
        answers.append(resp.choices[0].message.content)

    from collections import Counter
    most_common, count = Counter(answers).most_common(1)[0]
    confidence = count / n
    return {"answer": most_common, "confidence": confidence}

Self-consistency adds latency and cost (5x the calls) but is remarkably effective on math, logic, and short factual answers. Confidence < 0.6 is a strong signal the model is uncertain — escalate to a human or a stronger model.

Technique 4: Verification Chains (LLM-as-Judge)

For high-stakes answers, add a second LLM call that checks the first answer against the sources. The verifier sees the question, the candidate answer, and the source context, and returns a verdict.

VERIFY_PROMPT = """You are a fact-checker. Given the question, source context,
and a candidate answer, decide if the answer is SUPPORTED, PARTIALLY_SUPPORTED,
or UNSUPPORTED by the context.

Question: {question}
Context: {context}
Candidate answer: {answer}

Verdict (SUPPORTED / PARTIALLY_SUPPORTED / UNSUPPORTED):
Reasoning:
Unsupported claims (if any):"""

def verified_answer(query):
    chunks = hybrid_search(query, top_k=5)
    context = "\n\n".join(c["content"] for c in chunks)
    candidate = llm.complete(GROUNDED_PROMPT.format(context=context, q=query))

    verdict = llm.complete(VERIFY_PROMPT.format(
        question=query, context=context, answer=candidate
    ))

    if "UNSUPPORTED" in verdict:
        return "I can't verify this answer from available sources."
    return candidate

This roughly doubles cost but catches the most dangerous hallucinations — answers that sound right but contradict the source. In production, route only high-stakes queries (legal, medical, financial) through verification; for low-stakes chat, skip it.

Technique 5: Calibrated Abstention ("I Don't Know")

The cheapest hallucination to ship is the one the model never made. Teach your model to refuse when uncertain, and gate answers on a confidence threshold.

Three layers of abstention:

  1. Retrieval-confidence gate. If no retrieved chunk scores above a threshold, refuse.
  2. Self-evaluated confidence. Ask the model to rate its own confidence (0-1) before answering; refuse if < 0.7.
  3. Logprob-based gate. Use token logprobs to estimate certainty — if the average logprob is low, the model is guessing.
def answer_or_abstain(query):
    chunks = hybrid_search(query, top_k=5)
    if chunks[0]["score"] < 0.65:
        return "I don't have enough information to answer this."

    # Ask the model to self-rate confidence
    resp = client.chat.completions.create(
        model="gpt-5",
        messages=[
            {"role": "system", "content": "Answer only if confident. "
             "Otherwise say 'LOW_CONFIDENCE'."},
            {"role": "user", "content": build_grounded_prompt(query, chunks)},
        ],
        temperature=0,
        logprobs=True,         # for logprob-based gating
        top_logprobs=1,
    )
    answer = resp.choices[0].message.content
    if answer.startswith("LOW_CONFIDENCE"):
        return "I'm not confident enough to answer. Could you rephrase?"
    return answer

Technique 6: Tool Use Over Memorized Knowledge

LLMs are unreliable at arithmetic, dates, currency conversion, and anything that changes. Don't ask them — give them tools. A model that calls calculator(237 * 1.08) cannot hallucinate the result; a model asked to compute it from memory often does.

tools = [
    {"type": "function", "function": {
        "name": "calculator",
        "description": "Evaluate a math expression. Use for ALL arithmetic.",
        "parameters": {"type": "object",
            "properties": {"expression": {"type": "string"}},
            "required": ["expression"]},
    }},
    {"type": "function", "function": {
        "name": "get_current_date",
        "description": "Get today's date. Never assume the date.",
        "parameters": {"type": "object", "properties": {}},
    }},
    {"type": "function", "function": {
        "name": "search_knowledge_base",
        "description": "Search internal docs for facts. Cite sources.",
        "parameters": {"type": "object",
            "properties": {"query": {"type": "string"}},
            "required": ["query"]},
    }},
]

resp = client.chat.completions.create(
    model="claude-sonnet-4-20250514",
    messages=[{"role": "user", "content": user_query}],
    tools=tools, tool_choice="auto",
)

For building tool-using agents cleanly, the MCP (Model Context Protocol) standardizes tool definitions across models — see our MCP guide. The point: every fact the model retrieves live is one it can't hallucinate.

Technique 7: Red-Team Eval and Continuous Monitoring

You can't fix what you don't measure. Build an adversarial eval set of questions designed to trigger hallucinations — outdated facts, ambiguous queries, questions outside your domain — and run it on every model or prompt change.

HALLUCINATION_TRAPS = [
    # Outdated facts (model's training data is stale)
    "Who is the current CEO of OpenAI?",
    "What's the latest version of Python?",

    # Ambiguous / under-specified
    "What's the best programming language?",
    "Is React better than Vue?",

    # Fabricated entities (probe for confabulation)
    "Tell me about the 1923 Treaty of Argleton.",
    "What's the API for the flurgle library?",

    # Right answer, wrong source
    "Cite the exact RFC section for HTTP/2 server push.",
]

def run_hallucination_eval(model, prompt_template):
    """Returns hallucination rate. Lower is better."""
    results = []
    for q in HALLUCINATION_TRAPS:
        answer = generate(model, prompt_template, q)
        verdict = llm_judge(q, answer)  # SUPPORTED / HALLUCINATED / REFUSED
        results.append(verdict)
    hallucinated = sum(1 for r in results if r == "HALLUCINATED")
    return hallucinated / len(results)

Track three numbers in production: hallucination rate (on the trap set), abstention rate (refusals as % of answers), and user-reported error rate. If hallucination rate rises without abstention rising, your grounding is degrading.

Stacking the Techniques: A Decision Framework

Not every query needs all seven techniques. Match the rigor to the stakes:

StakesExampleTechniques
LowCasual chat, brainstormingLow temp (3)
MediumCustomer support, summariesRAG (1), low temp (3), abstention (5)
HighLegal, medical, financialRAG (1), structured outputs (2), verification (4), abstention (5), tools (6)
CriticalAutomated decisions, no human reviewAll 7 + human-in-the-loop fallback

Model Choice Matters

Some models hallucinate more than others, even at the same benchmark scores. From DrAI's internal evals running thousands of queries:

ModelHallucination rate (grounded QA)Notes
Claude Opus 43.1%Most conservative, best at refusal
GPT-54.4%Strong, slight sycophancy bias
Claude Sonnet 45.2%Excellent value
GPT-5-mini7.8%Use with verification
Open-source 70B12-18%Needs heavy grounding

For high-stakes work, route to Claude Opus 4 or GPT-5. For cost-sensitive work where some hallucination is tolerable, Sonnet 4 or GPT-5-mini with verification is fine. See our Claude 4 vs GPT-5 comparison for the full breakdown.

The Business Cost of Hallucination

Before the techniques, a word on why this matters. Hallucination isn't just an academic embarrassment — it has direct business costs that scale with deployment:

Failure typeExampleTypical cost
Fabricated citationModel invents a legal case or statuteLegal liability, reputational damage
Wrong API callModel hallucinates a function signatureProduction incident, broken integration
Confident misinformationCustomer-facing bot gives wrong medical/financial adviceUser harm, regulatory exposure
Sycophantic agreementModel agrees with a false user premiseErosion of trust, bad decisions downstream
Stale fact presented as currentModel reports a CEO or price from 2 years agoLost deals, customer churn

A single high-profile hallucination in a customer-facing feature can undo months of trust-building. The techniques in this guide exist because the cost of not using them is measured in incidents, churn, and legal exposure — not just eval scores.

Prompt Engineering for Grounding

Beyond the architectural techniques above, small prompt-level adjustments compound. Four patterns that reliably reduce hallucination:

  1. Explicit source constraints. "Answer using ONLY the context. If the answer isn't there, say so." This single instruction cuts confabulation dramatically.
  2. Forced citation. Require the model to cite a chunk ID or quote for every claim. Hallucinated claims have no source to cite, which makes them visible.
  3. Step-by-step reasoning. "First, identify the relevant facts in the context. Then, answer." Chain-of-thought grounding reduces leaps.
  4. Negative examples. Show the model what a bad (hallucinated) answer looks like and what a grounded one looks like. Few-shot calibration works.

None of these replace RAG or verification, but they're free quality gains you can ship in a prompt edit.

Common Anti-Patterns

The Bottom Line

Hallucination prevention is a stack, not a switch. RAG grounds the model in real facts. Structured outputs constrain what it can say. Verification catches the survivors. Abstention handles the rest. Eval keeps you honest. Combined, these techniques take production LLM reliability from "demo-grade" to "ship-grade."

The models and tools you need are all available through DrAI's unified endpoint. Sign in, pick a model, and start building reliable AI features.

See Model Pricing →

📚 Related Reading

RAG Implementation Guide 2026: Build Production RAG with pg…Step-by-step guide to building production-ready RAG with pgvector in 2026. Covers... AI Prompt Engineering: 12 Techniques to Double Output Quali…Practical prompt engineering guide: 12 proven techniques including CoT, Few-shot... AI Model Evaluation Guide: Build Your Own LLM Test SuiteBuild an LLM test suite: golden datasets, exact/contains/semantic metrics, LLM-as-judge... LLM Security Best Practices: Protecting AI APIs from AttacksComprehensive LLM security guide for 2026: defend against prompt injection, data...
🌐 English