AI in Production / RAG in Production

Grounded Citations in RAG: Verifying Every Claim Against Its Source Passage

Why a citation marker proves nothing until checked, how claim-level entailment verification works, and how to trade unsupported claims against recall and cost.

By Sandeep Belgavi · Published 2026-10-30

Three-step diagram: Split the answer into atomic claims. Then Score each claim against its cited passage. Then Drop, re-cite or regenerate what fails.
Original conceptual illustration by Sandeep Belgavi. A teaching diagram, not a measurement.

A RAG answer with bracketed citations looks trustworthy, and that is the problem. The model chose the brackets the same way it chose the words: by predicting what usually comes next. A citation can point at a passage that says something slightly different, at a passage that supports a neighbouring sentence, or at nothing relevant at all. Users rarely click through, so an unsupported claim with a citation marker is more persuasive than the same claim without one.

This guide covers how to turn citations from decoration into a checked contract: what "supported" means operationally, why you should verify atomic claims rather than sentences or whole answers, the arithmetic of verifier thresholds, what to do when a claim fails (drop it, re-cite it from another passage, or regenerate), and how to keep the check inside a latency and cost budget. The embedded lab runs synthetic answers through each choice and shows how many unsupported claims ship and how many true ones you lose.

What grounded actually means

The research literature gives a precise definition worth adopting. The AIS framework (Attributable to Identified Sources) asks whether a reader, given only the cited source, would agree that the statement is true according to that source. ALCE, a benchmark for generating text with citations, turns that into two automatic measures: citation recall (is each statement entailed by the passages it cites?) and citation precision (does each cited passage actually contribute support?). Both are judged with a natural language inference (NLI) model, a classifier that takes a premise and a hypothesis and predicts entailment, contradiction or neutral.

Three properties fall out of that definition and drive the engineering. Support is judged against the cited passage, not against the model's knowledge and not against the whole context: a true fact with the wrong citation is a citation error. Support is judged per statement, so the size of the statement matters. And support is a probabilistic judgement made by another model, so it has false positives and false negatives that you trade with a threshold.

It is worth being explicit about what this check does not do. It verifies that the answer is faithful to the retrieved passages. If the passage itself is stale or wrong, a perfectly grounded answer is still wrong. Grounding verification and source quality are separate problems.

Why claims, not sentences

A sentence like "The paperback ships in three days, costs $14 and includes the author's afterword" contains three checkable facts. If the passage supports two of them and says the price is $16, a sentence-level verifier sees mostly supported content and is likely to pass it. In score terms, averaging one unsupported claim with two supported ones pulls the sentence score toward the supported side. With the lab's illustrative NLI model and a threshold of 0.4, a three-claim sentence containing one unsupported claim passes about 90% of the time.

The fix is to decompose the answer into atomic claims, each a single fact, and verify each claim against its citation. FActScore introduced atomic-fact decomposition for factual precision, and RAGAS uses the same idea for its faithfulness metric: break the answer into statements, check each against the context, report the supported fraction. Decomposition costs an extra LLM call, or you can ask the generator to emit one claim per citation in a structured format so that no separate pass is needed. Either way, the unit you verify is the unit you can drop, so claim-level checks also preserve more good content when something fails: dropping one claim is better than dropping a whole sentence or refusing a whole answer.

Verification unitHides a bad claim among good onesCollateral damage on failureExtra cost
Whole answerVery oftenEntire answer refusedOne check
SentenceOftenGood claims in the sentence lostOne check per sentence
Atomic claimRarelyOnly the bad claimDecomposition plus one check per claim

The arithmetic of a verifier threshold

Treat the verifier as a scorer that separates supported from unsupported claims with some overlap. The lab models the score as a logistic function of a latent value that sits at +d/2 for supported claims and −d/2 for unsupported ones, plus unit Gaussian noise. The separation d is the verifier's quality: about 1.4 for lexical overlap, 3.0 for a small NLI cross-encoder and 3.6 for an LLM judge in this illustrative model. A threshold τ then fixes both error rates:

z_threshold = logit(tau) / 1.7
P(bad claim passes)  = P(N(0,1) > z_threshold + d/2)
P(good claim fails)  = P(N(0,1) < z_threshold - d/2)

NLI, d = 3.0, tau = 0.4 -> z_threshold = -0.24
  bad passes  = P(N > 1.26)  = 0.10
  good fails  = P(N < -1.74) = 0.04

base rates: 8% no source, 5% wrong citation, 3% number drift
shipped unsupported ~ 2.8%, true claims kept ~ 91%   (lab, calculated)

Raise τ and fewer bad claims pass, but more good ones fail; there is no free setting. A sharper verifier moves both curves apart, which is the only way to improve both numbers at once. That is why the verifier choice matters more than threshold tuning, and why you should calibrate τ on a labelled set of your own claims instead of using 0.5 by default.

Some failure types are harder than others. Number drift ("ships in 5 days" when the passage says 3) shares almost every token with its source, so lexical overlap scores it as supported. Small NLI models do better but are known to be weak at numerical reasoning. An LLM judge prompted to compare quantities explicitly does best. In the lab, number drift is modelled as a separate claim type that each verifier separates with a different strength.

When a claim fails: drop, re-cite or regenerate

Detecting an unsupported claim is half the job. The other half is deciding what the user sees.

  • Drop removes the claim (and, if you verify at sentence level, the sentence). It is cheap and safe but lowers completeness, and an answer can become empty. Track the share of answers emptied by verification; a spike means the generator or the retriever has changed.
  • Re-cite checks the failing claim against the other passages already in the prompt and re-attaches the citation if one supports it. This rescues true facts with wrong brackets, which become common after model or prompt changes. It multiplies verification pairs by the number of passages, and every extra comparison is another chance for a false match, so demand a stricter score to re-attach than to pass in the first place (the lab uses τ + 0.15).
  • Regenerate asks the model to rewrite the failing part from the passages, then verifies again. It can recover answers that would otherwise be empty, but it adds a full generation on the hot path and the rewrite can fail the same way.

A fourth option, showing the claim with a visible "not verified" marker, is reasonable for internal tools and research assistants where users want to see everything. For customer-facing answers, an unverified claim with a confident tone is the outcome you were trying to prevent.

Cost and latency of verification

Verification sits between generation and the user, so its latency adds directly to time to final answer (or to the delay before a streamed answer is confirmed). Illustrative numbers from the lab's model:

VerifierAdded latency for about 6 claimsCost per 1k answersWeak spot
Lexical overlapA few msAbout $0Paraphrase, number drift
NLI cross-encoder (batched on a GPU)About 45 ms, plus decompositionCents, plus decompositionNumbers, long premises
LLM judge (one batched call)About 600 ms, plus decompositionAbout $12, plus decompositionLatency, cost, its own errors
Cascade: NLI, LLM only for claims with digitsNLI latency when no digits, LLM when there areBetween the twoRouting rule must match your data

Two engineering choices make a large difference. Batch every claim-passage pair for an answer into one call (one forward pass for the cross-encoder, one prompt with numbered claims for the judge) instead of one call per claim. And route by difficulty: a regular expression for digits, currencies and dates is a crude but effective router that sends the risky claims to the strong judge and the rest to the fast model. Cross-encoder NLI checkpoints based on DeBERTa are widely available on Hugging Face; check the model card for the label order and the maximum premise length, because long passages are often truncated silently. Some model APIs now return citations that point to exact spans of the provided documents, which makes decomposition easier, but a span the model chose is still a claim the model made, so verify it the same way.

Streaming needs a decision too. If you stream tokens to the user and verify afterwards, a claim that fails has already been read, and retracting it is awkward. Three patterns work in practice: buffer each sentence and release it once its claims pass, which adds roughly one verification round per sentence to the stream; stream immediately but render citations as pending until verified, then remove or mark failures; or verify only the final answer for non-streaming surfaces such as email replies and summaries. The first pattern suits short factual answers, the second suits long research-style answers where users read slowly, and the choice should be made per surface rather than globally.

A worked example: Belgavi's Book Store

Suppose the hypothetical Belgavi's Book Store assistant answers questions about prices, delivery times and editions from catalogue and policy passages. In the lab's synthetic model, about 16% of generated claims are not supported by their citation before any check. The numbers below are calculated by the lab, not measured:

  1. No verification: about 16% of shipped claims are unsupported and only 38% of answers are fully grounded.
  2. NLI at sentence level, τ = 0.5: unsupported claims fall to about 9%, because mixed sentences still pass, while 11% of true claims are lost with their sentences.
  3. NLI at claim level, τ = 0.4: unsupported falls to about 2.8% with 91% of true claims kept, for about 235 ms at p95 including decomposition.
  4. A model update makes one claim in five cite the wrong passage. With drop-on-failure, true claims kept falls to about 75%. Switching to re-cite brings it back to about 94% at τ = 0.6 with unsupported near 2%.
  5. A catalogue launch makes answers numeric-heavy. The NLI-only setup lets about 9% unsupported claims through; a cascade that sends claims with digits to an LLM judge gets back to about 3% at roughly half the cost of judging every claim with the LLM.

The pattern generalises: start with claim-level checks and a fast verifier, recover rather than drop when the failure is a citation error, and spend the expensive judge only on the claim types your fast verifier is known to miss.

Detecting grounding problems in production

Verification gives you metrics for free if you log its decisions. The useful ones:

  • Unsupported-claim rate before verification, per model version and prompt version. This is the generator's grounding quality and the first thing to move when someone changes a prompt.
  • Drop, re-cite and regenerate rates after verification, and the share of answers emptied. Re-cite rising alone points at citation formatting or passage ordering; drop rising points at hallucination.
  • Score distributions for verified claims. A distribution that slides toward the threshold usually means a new document type (tables, code, long legal text) that the verifier handles poorly.
  • A weekly human audit of a small sample of passed and failed claims, to estimate the verifier's own error rates. Without it, you are trusting one model to grade another with no ground truth.

Common mistakes are predictable. Verifying against the whole context instead of the cited passage hides citation errors. Verifying sentences hides compound claims. Using a fixed threshold across verifiers ignores that their scores are not calibrated the same way. Truncating long passages to fit the NLI model's window turns a supported claim into a failure when the support was near the end. And reporting only the final unsupported rate hides how much good content verification removed, which users experience as a less helpful assistant.

Playing the lab

The lab follows the same path as the worked example. Mission one starts with no verification and asks you to cut unsupported shipped claims to 3% while keeping 90% of true claims: you will find that the unit of verification matters as much as the verifier. Mission two turns on loose citations and asks you to keep 93% of true claims, which dropping cannot do. Mission three turns on numeric-heavy answers with a lexical verifier and rewards the cheapest setup that catches number drift. Mission four combines both incidents under a cost cap, so you have to combine routing, recovery and threshold tuning. The histogram on the right shows the verifier's scores for supported and unsupported claims with your threshold; when the two curves overlap, no threshold can satisfy both targets, and the fix is a sharper verifier.

Run the lab: Grounded citations: catch every claim its source does not support

The lab below generates 320 synthetic answers of two to four sentences, each sentence holding one to three claims with a citation to one of five passages. Some claims are supported, some have no source, some cite the wrong passage and some change a number. Each chip shows one claim: its outline is the hidden truth, the fill shows the verdict and a strike-through means it was removed. The histogram shows verifier scores for all claims against your threshold τ. Start with mission one.

Prefer a full-width view? Open the standalone lab. Your stars are saved in this browser and shown on the series hub.

What to do next

  1. Make the generator emit one claim per citation in a structured format, so each claim can be verified against exactly the passages it cites.
  2. Label 300 claims from production answers as supported, unsupported or mis-cited, and use them to choose a verifier and calibrate its threshold.
  3. Log the verifier score, verdict and action for every claim, and chart the unsupported rate before verification per model and prompt version.
  4. Add re-citation against the other retrieved passages before dropping a claim, with a stricter threshold for re-attachment.
  5. Route claims containing numbers, dates or prices to a stronger judge, and measure whether the cascade beats a single verifier on cost and errors.
  6. Track the share of answers emptied by verification and alert when it moves.

Sources and further reading

Related in this series:

Diagrams, examples and the lab model are original educational material. Lab numbers are calculated by a synthetic model, not measured on real hardware or services.

Views are my own and do not represent any employer, past or present.