Retrieval
Grounded answers with citations
The query-time path of RAG, from question to top-k chunks to a grounded prompt that refuses when evidence is missing and cites sources that code can check.
At query time, RAG has to do three things: find the right passages, put them in the prompt in a way the model will use, and return an answer the user can check. A grounded answer ties each claim to a passage you supplied. A citation is a pointer, such as a chunk ID or URL, that lets a person verify the claim.
Concept
Before you start: top-k means the k passages with the highest similarity score to the question. Grounding means the model's claims come from the evidence in its context, not from memory.
The big idea
The query path has six steps:
- Optionally rewrite the question. Skip this at first.
- Embed the question with the same model used at ingestion.
- Retrieve the top-k chunks. Start with k between 5 and 10.
- Assemble the prompt: instructions, sources and the question.
- Generate, telling the model to use only the sources and to say "I don't know" when they are silent.
- Map the citations back to metadata, and return the answer with links.
A research assistant who answers from a folder of papers is a fair picture. Good assistants quote the page and say "not in the folder" when the answer is missing. The analogy stops at one point: the assistant can refuse, but code has to check that each cited number really exists.
Walking through it
Take the question "How do refunds work?" The steps look like this:
1. embed("How do refunds work?")
2. nearest chunks: refund-v3#2, refund-v3#3, faq#11, ... (top 5)
3. build prompt: rules + 5 sources + question
4. model answers: "Damaged items are refundable if the order shipped
less than 14 days ago [1]."
5. check: [1] is one of the 5 sources given, so the citation is valid
6. return answer plus links to refund-v3#2The prompt template keeps the rules and the sources apart:
Answer the question using only the sources below.
If the sources do not contain the answer, say you don't know.
Cite sources by id like [2].
<sources>
<source id="1" title="Refund policy" url="https://example.com/refunds">
...</source>
<source id="2" title="Billing FAQ" url="https://example.com/billing">
...</source>
</sources>
<question>{{QUESTION}}</question>Three practical rules follow from this template:
- Cap the total source tokens. Five strong chunks beat twenty weak ones.
- Log the retrieved chunk IDs with every answer. You need them for debugging and evals.
- Check citations in code. If the model cites
[4]but you sent three sources, reject the answer.
Common mistakes
- "Use the context if relevant." Without an explicit "I don't know" path, a retrieval miss turns into a confident guess.
- Trusting citations without a check. A model can cite a source number that does not exist.
- Dumping too many chunks. More text dilutes the useful evidence and costs more.
- Logging nothing. Without retrieved IDs, you cannot tell retrieval failures from generation failures.
Warning
Make refusal easy and acceptable. If the prompt never mentions abstention, the model will try to be helpful with weak evidence.
Check yourself
- Why reject an answer that cites
[4]when only three sources were sent? The citation cannot be verified, so the answer is not grounded in the evidence you provided. - Why must the query embed use the same model as ingestion? Otherwise the question and the chunks sit in different spaces, and the nearest matches are meaningless.
Key takeaways
- The query path is embed, retrieve top-k, assemble, generate and cite.
- Put the rules first, then the sources, then the question.
- Require an "I don't know" path and make it easy to take.
- Check citations in code and log the chunk IDs with each answer.
Further learning
Next, see how to tell which stage broke when an answer is wrong, in failure modes.
Related
Retrieval-augmented generation
The core RAG pipeline: ingest, chunk, embed, retrieve, generate with citations.
Chunking for RAG
How to cut documents into passages for retrieval, why naive character cuts break facts, and how size, overlap and context prefixes change what can be found.
Evaluating LLM apps
A fixed set of inputs plus a way to score outputs, so you can tell whether a change helped.