
Your RAG Gives Answers. These Lines Make It Cite Its Work.
Chris Harper
3 min read
Aug 17, 2026 · 04:04 UTC
Tag retrieved chunks with IDs, ask Claude to cite them inline, and return a sources list — your RAG answers become verifiable, not just plausible.
What you will be able to do after this:
- Return
[1]/[2]inline citations in any RAG response alongside asourceslist - Verify that cited documents actually support each claim using a structured
quotefield - Build the citation layer in under 50 lines on top of your existing retriever
A RAG system that returns "Refunds take 5-7 days" is useful. One that returns "Refunds take 5-7 days [1]" with [1]: Refund Policy, section 3.2 is trustworthy. That is the difference between a demo and a production tool.
Resource: RAG with Verified Citations — Trelis Research (YouTube, 34 min)
The pattern
Your retriever returns chunks. Tag each one with a sequential ID and include them in the user turn:
import anthropic
client = anthropic.Anthropic()
def rag_with_citations(question: str, chunks: list[dict]) -> dict:
# chunks = [{"id": 1, "text": "...", "source": "Refund Policy 3.2"}, ...]
context = "
".join(f"[{c['id']}] {c['text']}" for c in chunks)
response = client.messages.create(
model="claude-sonnet-5-20260801",
max_tokens=1024,
system="""You are a helpful assistant. Answer using ONLY the provided context.
Cite every factual claim with a bracketed ID like [1] inline.
If the answer is not in the context, say so.""",
messages=[{
"role": "user",
"content": f"Context:
{context}
Question: {question}"
}]
)
return {
"answer": response.content[0].text,
"sources": [{"id": c["id"], "source": c["source"]} for c in chunks]
}
Structured output version (more reliable for parsing)
import json
response = client.messages.create(
model="claude-sonnet-5-20260801",
max_tokens=1024,
tools=[{
"name": "answer_with_citations",
"description": "Return an answer with inline citations",
"input_schema": {
"type": "object",
"properties": {
"answer": {
"type": "string",
"description": "Answer text with [N] inline citations"
},
"citations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {"type": "integer"},
"quote": {
"type": "string",
"description": "Exact text from document [N] that supports the claim"
},
"source": {"type": "string"}
},
"required": ["id", "quote", "source"]
}
}
},
"required": ["answer", "citations"]
}
}],
tool_choice={"type": "tool", "name": "answer_with_citations"},
system="Answer using ONLY the provided context. Cite every factual claim inline.",
messages=[{"role": "user", "content": f"Context:
{context}
Question: {question}"}]
)
result = json.loads(response.content[0].input)
# result["answer"] = "Refunds take 5-7 days [1]."
# result["citations"] = [{"id": 1, "quote": "Refunds are processed in 5-7 business days", "source": "Refund Policy 3.2"}]
The quote field in each citation forces Claude to locate the exact supporting text — surfacing any hallucination where no supporting passage exists. If Claude cannot find a quote, it cannot fabricate a citation.
Sources: RAG with Verified Citations — Trelis Research (YouTube) · Citation-aware RAG — Tensorlake · Attributing sources in RAG — apxml.com