July 10, 2026ยท8 min readยทBy Innovibe

How to Fix LLM Hallucinations in Your Production App

Hallucinations aren't random bugs โ€” they're predictable failure modes with specific fixes. Here's the production playbook we use on every AI project.

AILLMProductionTutorial

Hallucinations cost real money. A customer support bot that invents refund policies, a document summarizer that adds facts, a coding assistant that references non-existent APIs โ€” these aren't edge cases, they're what happens when you deploy an LLM without guardrails.

Here's the framework we use to reduce hallucinations to an acceptable rate in production.

Why LLMs hallucinate

The model doesn't "know" facts the way a database does. It predicts the next token based on patterns in training data. When asked something outside its training or context, it confidently generates plausible-sounding text instead of saying "I don't know."

Four main causes:

  1. Question is outside the context โ€” the answer isn't in the prompt
  2. Ambiguous question โ€” multiple valid interpretations, model picks one
  3. Model overconfidence โ€” high-temperature or poorly calibrated outputs
  4. Conflicting context โ€” documents in the prompt contradict each other

Fix 1: Ground every response in retrieved context (RAG)

The single highest-ROI fix. If the model can only answer from documents you provide, it can't invent facts it wasn't given.

def build_grounded_prompt(question: str, retrieved_docs: list[str]) -> str:
    context = "\n\n".join(f"[Doc {i+1}]: {doc}" for i, doc in enumerate(retrieved_docs))
    return f"""Answer the question using ONLY the documents below.
If the documents don't contain enough information, say: "I don't have that information."
Do not add facts not present in the documents.

Documents:
{context}

Question: {question}

Answer:"""

The key instruction: explicitly forbid adding information not in the documents.

Fix 2: Set temperature to 0.0โ€“0.2

Temperature controls randomness. Higher temperature = more creative = more hallucinations. For factual tasks, set it low.

response = client.chat.completions.create(
    model="gpt-4o",
    messages=messages,
    temperature=0.1,  # NOT the default 1.0
)

For creative tasks (writing, brainstorming), higher temperature is fine. For factual retrieval, classification, or extraction โ€” always low.

Fix 3: Force structured output and validate it

When the model returns structured data (JSON, specific fields), use response_format to enforce valid JSON, then validate the schema.

from pydantic import BaseModel, ValidationError

class Answer(BaseModel):
    response: str
    confidence: float  # 0.0 to 1.0
    sources_used: list[int]  # which doc numbers were cited

response = client.beta.chat.completions.parse(
    model="gpt-4o",
    messages=messages,
    response_format=Answer,
    temperature=0.1,
)

answer = response.choices[0].message.parsed

# If confidence is low, route to human review
if answer.confidence < 0.7:
    return route_to_human_review(question, answer)

Fix 4: Add a self-check pass

Ask the model to verify its own answer against the source material. Adds latency but catches obvious fabrications.

async def answer_with_verification(question: str, docs: list[str]) -> str:
    # First pass: generate answer
    answer = await generate_answer(question, docs)

    # Second pass: verify
    verification_prompt = f"""
    Question: {question}
    Answer: {answer}
    Source documents: {docs}

    Is every fact in the answer supported by the source documents?
    Reply with JSON: {{"verified": true/false, "issues": ["list any unsupported claims"]}}
    """

    check = await client.chat.completions.create(
        model="gpt-4o-mini",  # cheaper model for verification
        messages=[{"role": "user", "content": verification_prompt}],
        response_format={"type": "json_object"},
        temperature=0,
    )

    result = json.loads(check.choices[0].message.content)
    if not result["verified"]:
        # Re-generate with issues highlighted
        return await regenerate_with_corrections(question, docs, result["issues"])

    return answer

Fix 5: Require citations

Force the model to cite which document each claim comes from. Uncited claims become obvious and easy to catch.

system_prompt = """
When answering, cite your sources using [Doc N] notation after each claim.
Example: "The refund window is 30 days [Doc 2]."
If you make a claim without a citation, that means you're unsure โ€” don't make it.
"""

Fix 6: Implement a human review queue

For high-stakes outputs (legal, medical, financial, customer-facing), don't fully automate. Build a confidence threshold below which answers go to a human.

CONFIDENCE_THRESHOLD = 0.85

async def process_question(question: str) -> dict:
    answer = await generate_answer_with_confidence(question)

    if answer["confidence"] < CONFIDENCE_THRESHOLD:
        await add_to_review_queue(question, answer)
        return {"status": "pending_review", "eta": "2 hours"}

    return {"status": "answered", "response": answer["text"]}

Measuring hallucination rate

Track it. Pick 100 representative questions where you know the ground-truth answer, run them weekly, and measure what % the model gets wrong or fabricates. That's your hallucination rate. Set a target and alert when it degrades.

Most teams don't do this and discover hallucinations from angry customers instead.


Building an LLM-powered product? We've shipped production AI systems with hallucination rates under 2%. Get in touch.

K
Innovibe
Founder & Technical Lead, Innovibe

Building software for 15+ years. Passionate about AI, system design, and shipping things that work.

Frequently asked questions

Do I need a GPU to run this in production?+

For hosted APIs (OpenAI, Anthropic, Google) โ€” no. You call an HTTPS endpoint. GPUs only matter if you're self-hosting models, which is overkill for most production use cases.

How do I keep LLM costs under control?+

Cache identical prompts aggressively, use the smallest model that meets your quality bar, and set hard token limits per request. A response cache alone can cut costs 40โ€“60% on typical workloads.

What's the difference between fine-tuning and RAG?+

Fine-tuning bakes knowledge into model weights โ€” expensive, slow to update. RAG retrieves context at query time โ€” cheap to update, easier to debug. Use RAG for most production use cases and fine-tune only when you need a very specific tone or format.

How do I prevent an AI agent from doing something destructive?+

Design for reversibility first โ€” log before you act, prefer soft-deletes, require human confirmation for irreversible actions. Add explicit guardrails in your system prompt and test with adversarial inputs before going live.

How long will this take to implement?+

Most readers ship a working version in an afternoon. The first implementation is always the hardest โ€” once you understand the pattern, iterations get much faster.

Building something with AI?

We scope and ship AI features quickly. Let's talk.

Start a Conversation