Archive/PROMPTS

Prompting for citations that actually check out

Source IDs, quote-then-answer, automatic quote checks and a real "not found" path. How to make every claim traceable and verify it in code.

Prompting for citations that actually check out

Citations are the main way users can trust an AI answer without redoing the work. A claim with a link to its source can be checked in seconds; a claim without one has to be taken on faith. That is why most retrieval-augmented generation (RAG) systems ask models to cite their sources.

The problem is that citations can be wrong in ways that look right. A model can cite a real document that does not support the claim, cite the right document for the wrong sentence, or produce a plausible-looking reference that does not exist at all. This guide covers why citation errors happen, prompting techniques that make citations more accurate, and how to verify them automatically.

How citations go wrong

Research on citation quality, such as Gao et al. (2023), "Enabling Large Language Models to Generate Text with Citations," found that even strong models frequently produce citations that do not fully support their statements, which is why verification matters as much as prompting.

Technique 1: give every source a short ID

Label each retrieved passage with a short, unique ID, and ask for those IDs in citations. IDs are easier for models to reproduce exactly than titles or URLs, and easier for your code to check.

textsources-format
<sources>
<source id="S1" title="Refund policy" updated="2026-06-01">
Annual plans can be refunded in full within 30 days of purchase...
</source>
<source id="S2" title="Billing FAQ" updated="2026-08-12">
Pending authorisations usually disappear within 5 business days...
</source>
</sources>

Map IDs back to titles and links in your interface, not in the model output.

Technique 2: quote first, then answer

Ask the model to extract the exact quotes that support its answer before writing the answer. Quoting forces it to locate evidence, makes unsupported claims more obvious, and gives your code something concrete to check.

PROMPT · TESTED ON ANY MODEL WITH RETRIEVED SOURCES
Answer the question using only the sources provided. Step 1: Under "Quotes:", copy the exact sentences from the sources that answer the question, each prefixed with its source id, e.g. [S2] "...". Step 2: Under "Answer:", write the answer. After each claim, cite the source id(s) of the quotes that support it. If the quotes do not answer the question, write "Answer: The provided sources don't cover this." and nothing else.

Technique 3: make "not found" a first-class answer

Models fabricate most when the honest answer is unsatisfying. Give an explicit, acceptable response for missing information, and treat it as a success in your evals when the sources really do not contain the answer. Include such cases in your eval set; a system that never says "not found" is guessing.

Technique 4: one claim, one citation

Ask for citations at the claim level, placed immediately after the sentence they support, rather than a list of sources at the end. Claim-level citations make misattribution visible and allow automatic checks per sentence.

Technique 5: separate knowledge from sources

If you allow the model to add general knowledge, make it mark that explicitly ("General knowledge, not from sources:"). Better, for high-stakes domains, forbid it entirely and rely on retrieval.

Verifying citations automatically

Prompting improves citation accuracy; verification catches what prompting misses. Layer checks from cheap to expensive:

Citation verification layers
CheckHowCatches
ID existsEvery cited ID is in the retrieved setFabricated sources
Quote matchEach quote appears verbatim (or near-verbatim) in its sourceInvented quotes
Claim supportA model or entailment classifier checks the claim against the quoteMisattribution
CoverageEvery factual sentence has a citationUncited synthesis
pythonverify_quotes.py
import re
from difflib import SequenceMatcher

def verify(answer: str, sources: dict[str, str], min_ratio=0.9):
    problems = []
    for sid, quote in re.findall(r'\[(S\d+)\]\s*"([^"]+)"', answer):
        text = sources.get(sid)
        if text is None:
            problems.append(f"unknown source {sid}")
        elif quote not in text:
            # allow small differences in whitespace or punctuation
            best = max((SequenceMatcher(None, quote, text[i:i+len(quote)]).ratio()
                        for i in range(0, max(1, len(text) - len(quote)), 20)), default=0)
            if best < min_ratio:
                problems.append(f"quote not found in {sid}: {quote[:60]}")
    return problems

When checks fail, you can retry with the error, drop the unsupported claim, or show the answer with a warning. Log failure rates; a rising rate signals problems in retrieval or prompts.

Retrieval quality limits citation quality

A model cannot cite what was not retrieved. If the right passage is missing from the context, the model will either say "not found," which is good, or cite something nearby, which is bad. Improving chunking and retrieval often improves citations more than prompt changes; see RAG chunking strategies compared. And remember that a long context is not a substitute for retrieval; see context windows are not memory.

Showing citations to users

For the system prompt section that sets up grounded answers, see the RAG template in system prompt templates for production. For a second check on high-stakes answers, a grounded self-review step can help; see the red-team yourself prompt.

Citations in long answers and reports

Short answers usually cite one or two sources. Long outputs, such as research summaries, reports and comparisons, bring extra problems: dozens of claims, many sources, and a strong temptation for the model to cite loosely. Three practices help:

Measuring citation quality

Add citation metrics to your eval set:

  1. Citation precision: the share of citations that support their claim.
  2. Citation recall: the share of factual claims that have a supporting citation.
  3. Correct abstention: the share of unanswerable questions answered with "not found."
  4. Fabrication rate: the share of answers containing unknown IDs or quotes not found in sources.

Track them per release; they move independently of answer accuracy.

Frequently asked questions

Why do LLMs make up citations?

When asked for sources without retrieval, models generate text that looks like a reference based on patterns in training data, which can produce plausible but non-existent sources. Even with retrieval, they may cite a real source that does not support the specific claim.

How do I make an LLM cite its sources accurately?

Give retrieved passages short IDs, ask the model to quote supporting text before answering, require a citation after each claim, provide an explicit "not found" answer, and verify quotes and IDs in code.

Can I automatically check LLM citations?

Yes. Check that cited IDs exist, that quoted text appears in the cited source, and use an entailment model or a calibrated LLM grader to check whether each quote supports its claim.

What should the model do if the sources don't answer the question?

It should say so clearly rather than guessing. Make this an explicit, acceptable answer in the prompt and reward it in your evals when the sources truly lack the information.

RK
WRITTEN BYRafael KimAgents and tooling. Has personally been booked into a yurt by a language model.

Keep reading

Liked this? The Sunday Diff has one like it every week.