All insights
June 30, 2026·8 min read

Why Citations Have to Come From Retrieval, Never From the Model's Own Text

The easy way to add citations to a RAG system is to ask the model to append them — "cite the document and page you used" — and parse that text afterward into clickable links. It's also the wrong way, because it makes the citation exactly as trustworthy as the prose it's attached to. A model that can misstate a fact can misstate which document it came from, on which page, with the same fluent confidence either way, and a citation nobody can verify is worse than no citation, because it looks like proof.

The source of truth exists before the model ever runs

By the time generation starts, the retrieval step has already returned an exact list of what the model is working from: specific chunk records, each carrying a chunk id, a document id, a tenant id, a page number, and a character span, selected before a single output token exists. That list is the only trustworthy account of what was actually available to answer from, because it was produced by a deterministic lookup, not a language model narrating its own process. Citations get built from that list, filtered to the current tenant, and rendered independently of whatever the model's prose does or doesn't mention — a response with no citation markers in its text still shows the right sources, because the sources were never derived from the text in the first place.

Why this closes an isolation gap, not just an accuracy one

Parsing citations out of model prose creates a second path into an isolation problem the data layer was supposed to have already closed. A document engineered to include a plausible-looking reference to some other identifier — planted specifically to be echoed back — can get repeated by the model verbatim, and a system that trusts that echoed text at citation-render time might resolve it into a link without re-checking who's allowed to see it, because the decision came from the model's output instead of the system's own retrieval record. When citations are built exclusively from the chunk list retrieval already fetched and already scoped to the current tenant, there's no second decision point for a poisoned document to hijack — the model's prose is never consulted to decide what gets linked.

Chunking has to respect page boundaries, or the citation contract breaks

A citation that resolves to "page 4" only means something if every chunk maps to exactly one page. Chunk a document by fixed character count without regard to page breaks, and a single chunk can straddle pages 4 and 5 — at which point "the answer came from this chunk" no longer has one correct page number to show the reader, only a range to guess between. Chunking within page boundaries — never letting a chunk span two pages, splitting on the page break even when it produces an uneven chunk — keeps the page-and-span pair unambiguous by construction. It's a constraint applied once at index time, and it's what makes every later citation resolvable to a single, exact location instead of something a rendering layer has to reconcile after the fact.

Offsets drift, so citations match fuzzily, not exactly

Extraction pipelines rarely produce character offsets that line up perfectly with the document as a person actually sees it rendered. Ligatures collapse into single characters, hyphenated line breaks get rejoined or split differently than the source, and OCR introduces small character-level noise — all of which shift a chunk's stored span by a handful of characters relative to where that text visually sits on the page. Treat a stored offset as exact and a citation link will occasionally land one line above or below the sentence it's supposed to highlight. The fix is to re-anchor at click time with approximate string matching — searching for the stored text near the stored offset rather than trusting the offset outright — so a citation lands on the actual sentence even when the extraction pipeline's numbering has drifted slightly from the rendered page.

What this adds up to in a production RAG system

None of these are exotic techniques — a chunk list from retrieval, a page-respecting index, a fuzzy re-anchor at render time. What they add up to is a citation a user can click and verify against the actual source, every time, instead of a citation that's right until the one time the model's version of events and the system's don't agree, and nothing downstream catches the difference because nothing downstream ever checked.

Does asking the model to include citation markers still serve any purpose?

It can help the model stay on-topic and reference the right chunk in its own reasoning, but the markers themselves never build the final citation link — that always comes from the retrieval-time chunk list, so a marker the model gets wrong or omits doesn't change what the user sees cited.

What happens if the model's answer doesn't match any retrieved chunk at all?

That's a signal the response isn't grounded in retrieval, and it's handled the same way an ungrounded number is: surfaced as a low-confidence or fallback response rather than shown with citations that don't correspond to anything actually retrieved.

Is page-bounded chunking worse for retrieval quality than fixed-size chunking?

It constrains chunk boundaries, not chunk content — target chunk size within a page stays a free choice, a chunk just never crosses into the next one. The retrieval-quality trade-off is negligible next to what it buys: every chunk id maps to exactly one page, permanently.

Want a clear estimate for your project?

Book a scoping call — no commitment, just a clear-eyed read on what to build and a fixed-price estimate.

Book a scoping call