What is AI hallucination and how do you reduce it?
Hallucination is when an LLM confidently generates false information - invented facts, fake citations, or incorrect code. It is a fundamental property of how LLMs work, not a bug you can fully eliminate.
Overview
Key Points
- •LLMs have no internal "I don't know" gate - they generate the most plausible continuation of the prompt, true or not.
- •Common hallucinations: fake citations/URLs, invented statistics, non-existent functions in libraries, incorrect dates.
- •Hallucination rate increases with obscure topics, prompts with no clear answer, and high temperature settings.
- •RAG reduces hallucination by grounding the model in retrieved source text.
- •Asking the model to cite its sources or say "I don't know" helps but does not eliminate the problem.
- •Self-consistency (sampling multiple responses and taking the majority) reduces factual errors for reasoning tasks.
Examples
Prompt techniques that reduce hallucination
typescript// ✗ Vague prompt - high hallucination risk
const bad = 'What were the sales figures for Tesla in Q3 2023?';
// ✓ Grounded: force model to answer from provided context only
const withRAG = `Based ONLY on the following data, answer the question.
If the answer is not in the data, say exactly: "I don't have this information."
Do NOT guess or make up numbers.
DATA:
${retrievedContext}
QUESTION: What were Tesla's Q3 2023 sales figures?`;
// ✓ Cite sources explicitly
const withCitation = `Answer the question and cite which part of the document supports your answer.
Format: [Answer]. Source: [direct quote from document].`;Self-consistency: reduce errors by sampling multiple times
typescript// Ask the same question N times at non-zero temperature and take the majority answer
// Works well for math, logic, and factual questions with discrete correct answers
async function selfConsistency(question: string, samples = 5): Promise<string> {
const responses = await Promise.all(
Array.from({ length: samples }, () =>
client.chat.completions.create({
model: 'gpt-4o',
temperature: 0.5,
messages: [
{ role: 'system', content: 'Answer with a single number or short phrase. No explanation.' },
{ role: 'user', content: question },
],
})
)
);
const answers = responses.map(r => r.choices[0].message.content?.trim() ?? '');
// Return the most common answer
const counts = answers.reduce<Record<string, number>>((acc, a) => {
acc[a] = (acc[a] ?? 0) + 1;
return acc;
}, {});
return Object.entries(counts).sort((a, b) => b[1] - a[1])[0][0];
}
await selfConsistency('What is 17 × 24?'); // majority vote across 5 samples → '408'Output verification pipeline
typescript// After getting an LLM response, run a second verification pass
async function verifyAnswer(
question: string,
proposedAnswer: string,
sourceContext: string
): Promise<{ verified: boolean; reason: string }> {
const result = await client.chat.completions.create({
model: 'gpt-4o',
temperature: 0,
response_format: { type: 'json_object' },
messages: [{
role: 'user',
content: `Given this source context:
"${sourceContext}"
Is this answer accurate and supported by the context?
Question: ${question}
Answer: ${proposedAnswer}
Respond: {"verified": true/false, "reason": "brief explanation"}`,
}],
});
return JSON.parse(result.choices[0].message.content!);
}Using a second model call as a verifier adds latency and cost but significantly reduces harmful hallucinations in high-stakes applications.
Pro Tip
Design for failure: assume the model will occasionally hallucinate and build your system around that assumption. For critical facts (medical, legal, financial), always retrieve from authoritative sources via RAG and include a disclaimer. For code generation, always run the code and verify the output rather than trusting the model's output directly.