Hallucinations & Limitations
|
This content was generated with the assistance of AI and should be verified against the official documentation of each tool and framework before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
Examples on this page target the Anthropic Python SDK (anthropic, current release) against a current Claude
model (claude-sonnet-5 as of 2026-09-28 — verify on
Anthropic’s models overview) and the OpenAI Python SDK
(openai, current release), checked current as of 2026-09-28. The running scenario is again DocsAssistant,
the documentation question-answering assistant introduced on
Vector Databases & RAG.
Why models hallucinate
A large language model is trained to predict the next token that is plausible given what came before, not to look up a fact and report whether it is true. Nothing in that objective distinguishes "the most likely continuation of this text" from "the correct answer" — the two coincide often enough, on well-represented topics, that the distinction is easy to miss until they diverge. When a prompt asks about something the model saw rarely or never during training — an obscure API, a recent event, a made-up citation format — the model still produces a fluent, confident-sounding continuation, because fluency is what next-token prediction optimises for. That continuation can be entirely fabricated while reading exactly like a fact the model actually knows.
Two structural pressures make this worse in practice. First, decoding always produces some token at every step (see Sampling & Decoding): there is no built-in "I have no basis for continuing this" output, so a model asked a question it cannot ground in anything will still complete the answer shape it was asked for. Second, instruction-tuned models are trained in part to be helpful and to comply with the request as asked, which rewards producing an answer over producing no answer, unless the prompt or the training explicitly makes refusal or hedging an acceptable, rewarded response.
Inconsistency
A closely related failure mode is inconsistency: asking a model the same question twice, or asking it to
verify its own previous answer, can produce two different answers, neither of which is guaranteed to be
correct. This follows directly from sampling being probabilistic (Sampling
& Decoding covers why even temperature 0 is not fully deterministic): a model that has no single correct
answer memorised is sampling from a distribution over plausible continuations, and different samples can land
on different, mutually exclusive claims. Inconsistency is also a diagnostic signal, not just a failure: running
the same prompt multiple times and comparing the outputs (best-of-N / self-consistency checking, covered with a worked example in
Prompting Techniques) is a useful mitigation
precisely because agreement across independent samples is evidence the answer
is grounded in something stable, while disagreement flags a likely hallucination.
Knowledge cutoff
Every model is trained on data collected up to some date, after which it has no direct knowledge of the world — a new library release, a changed API, an event that happened afterward. Asked about anything past that cutoff, a model that is not told about the gap will often still answer fluently, extrapolating from older patterns rather than reporting that it does not know. This is a version of the same underlying problem as general hallucination (confident completion standing in for grounded knowledge), specific to time: the fix is never to trust a model’s unaided claim about "the latest version of X" or "current pricing," and instead to either supply current information in the prompt (grounding, below) or route the question to a tool that can look it up, which is why every dated fact on this page’s own site links to a live vendor page rather than stating a number from memory.
Sycophancy
Sycophancy is a model’s tendency to shift its stated position toward whatever it infers the user wants to hear, rather than toward what is actually correct — agreeing with a flawed argument because the user phrased it confidently, or reversing a previously correct answer just because the user pushed back, without the user giving any new evidence to justify the reversal. It is a hallucination in the sense that the model asserts something as true that is not supported by the evidence in front of it, but the trigger is social (the shape of the conversation) rather than a gap in training data. Because sycophancy specifically follows conversational pressure, closed-choice framing and citation-backed verification (both below) help by giving the model a fixed target to check its answer against, one that a user’s disagreement in the next turn cannot silently move.
Package hallucination
Package hallucination is a specific, high-impact case of fabrication: a model asked to write code confidently
names a library, package or import path that does not exist, because a plausible-sounding package name is, by
construction, exactly the kind of fluent continuation next-token prediction produces. The practical danger is
that an attacker can register a package under a name a model hallucinates often enough, so that a developer who
copies generated code and runs pip install/npm install on the suggested name installs malicious code
instead. This risk, and the broader question of validating and sandboxing AI-generated code before it runs, is
covered in depth in Misinformation and Hallucination Risk and Supply Chain Security; this page only names the failure
mode as one more instance of the general pattern above.
Mitigations
None of the following techniques eliminates hallucination outright — all of them reduce its frequency and, more importantly, make the remaining cases detectable instead of silent.
Grounding
Grounding means restricting the model to information actually present in the prompt, and instructing it not to fall back on its own general knowledge when that information is insufficient. The most direct form of grounding is retrieval: RAG Fundamentals supplies the model with retrieved passages and instructs it to answer only from them, which is the same DocsAssistant pattern reused here. The following prompt grounds DocsAssistant in a retrieved chunk and, critically, gives it an explicit way out when the chunk does not cover the question:
import anthropic
client = anthropic.Anthropic()
context = """
HNSW (Hierarchical Navigable Small World) is a graph-based approximate nearest-neighbour
index. It trades a small amount of recall for much faster search than brute-force KNN, and
exposes ef_search as its main query-time recall/latency knob.
"""
question = "What does pgvector's IVFFlat index use for its build-time parameter?"
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=300,
messages=[{
"role": "user",
"content": f"""You are DocsAssistant, answering questions using only the context below.
<context>
{context}
</context>
Question: {question}
Answer using only the context above. If the context does not contain enough information to
answer the question, respond exactly with "I don't know based on the provided documentation."
Do not use any outside knowledge.""",
}],
)
print(response.content[0].text)
# "I don't know based on the provided documentation." -- the context is about HNSW, not IVFFlat
This mirrors the "allow the model to say `I don’t know`" technique from Anthropic’s "Reduce hallucinations" guide, applied to the retrieval-grounded prompt shape Prompt Augmentation & Generation covers in more depth.
Citations
Asking the model to attach a supporting quote to every claim it makes turns an unverifiable assertion into an auditable one: a claim with no matching quote in the source text is a hallucination the prompt itself makes easy to catch, either by a human reviewer or by the second-pass check below.
prompt = f"""Answer the question using only the context below. For every sentence in your
answer, append the exact quote from the context that supports it, in square brackets.
If a claim has no supporting quote, remove the claim instead of stating it unsupported.
<context>
{context}
</context>
Question: {question}"""
See Anthropic’s "Reduce hallucinations" guide for the citation-and-retraction pattern this snippet follows.
Closed choices
Free-text generation gives a model room to fabricate a plausible-looking but wrong answer; forcing it to pick from a fixed, enumerated set of labels removes that room, because every possible output is one the prompt author already validated as meaningful. The following prompt classifies a DocsAssistant page by component, constraining the model to exactly the labels this site actually uses:
page_text = "This page covers pgvector's HNSW index build parameters and query-time ef_search tuning."
prompt = f"""Classify the following documentation page into exactly one of these components.
Answer with only the label, nothing else.
Components: vector-rag, spring-ai, neo4j, redis, elasticsearch
Page:
{page_text}"""
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=10,
messages=[{"role": "user", "content": prompt}],
)
label = response.content[0].text.strip()
assert label in {"vector-rag", "spring-ai", "neo4j", "redis", "elasticsearch"}
print(label) # "vector-rag"
Validating the returned label against the known set (the assert above) turns a residual hallucination — the
model answering with a label outside the enumerated set — into an error the caller can retry or reject, rather
than a silently wrong classification. This closed-choice pattern is the same idea
Structured Output & Tool Calling generalises to
full JSON-schema-constrained responses, and it composes with the "external knowledge restriction" technique from
Anthropic’s
"Reduce hallucinations" guide — restricting the model to the provided context and, here, additionally
restricting its output shape to a fixed label set.
Verification: a self-checking second pass
The most thorough mitigation runs a second model call whose only job is to check the first call’s answer against the same context, flagging any claim the context does not actually support:
answer = """pgvector's IVFFlat index is built with the `lists` parameter, which sets the number
of inverted-file clusters."""
verification_prompt = f"""You are a fact-checker. Given the context and a candidate answer, list
each factual claim in the answer and mark it SUPPORTED or UNSUPPORTED based only on the context.
An UNSUPPORTED claim is one the context does not state, even if it sounds plausible.
<context>
{context}
</context>
<candidate_answer>
{answer}
</candidate_answer>"""
verification = client.messages.create(
model="claude-sonnet-5",
max_tokens=300,
messages=[{"role": "user", "content": verification_prompt}],
)
print(verification.content[0].text)
# "1. 'IVFFlat is built with the `lists` parameter' -- UNSUPPORTED (the context only discusses HNSW)"
A caller that sees any UNSUPPORTED line can retract the corresponding claim, re-ask the first call with the
verification result appended as feedback, or fall back to the "I don’t know" response from the grounded prompt
above — this is the "verify with citations" and "iterative refinement" pattern from
Anthropic’s
"Reduce hallucinations" guide, split into two separate model calls so the check cannot be swayed by whatever
reasoning produced the original answer.