Turn raw retrieved chunk ids into a clean, source-labeled string ready to inject directly into an LLM prompt.
1Why Format Instead of Just Concatenating
You could join retrieved chunks together with no labeling at all, and generation would still technically work. But without source boundaries, the model has no way to tell you which specific document backed a specific claim — and neither do you, when debugging a wrong answer. Numbering sources is a small formatting step with an outsized payoff for trust and debuggability.
2The Shape of a Production Context Block
Real RAG systems often go further than plain numbering — adding metadata like document titles, timestamps, or URLs next to each source. The core pattern stays the same as what you just built: retrieve, then format each result as a clearly delimited, labeled unit before it ever reaches the prompt.
3Step-by-Step Breakdown
From Chunk IDs to Prompt Text. similarity_search() returns ids like 'pto-policy' — useful for your code, meaningless to the LLM. Before generation, you need to turn retrieved ids into real, labeled text the model can read and even cite back to the user.
Build the Context Formatter. Finish format_context(): for each retrieved id, look up its full text and append a labeled line like '[Source N] <text>' to lines. Numbering the sources isn't cosmetic — it's what lets the model cite exactly which source it used in its answer.
Why label each retrieved chunk with a source number like '[Source 1]' instead of just concatenating the raw text together?
- →It lets the generation step (and the model's answer) reference exactly which retrieved source backs a specific claim, which is essential for user trust and debugging wrong answers.
- →It reduces the total number of tokens sent to the model.
A Real, LLM-Ready Context String. You can now go from a raw query all the way to a clean, labeled context string. Next lesson closes Module 2: combining similarity_search() and format_context() into a single retrieve() function — the one piece your chatbot will actually call.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Render Source Citations as Real Links or Text
If your UI later shows '[Source 1]' style citations, make each one a real, focusable link or text reference rather than a purely visual badge, so keyboard and screen reader users can navigate to the cited source.
<a href="#source-1">[Source 1]</a>SEO Implications
- 1
Target 'RAG citations' as a distinct search topic
Developers search for citation/attribution patterns as a separate, later-stage problem once basic retrieval is already working.
Best Practices
Always Delimit and Label Retrieved Sources
Never concatenate retrieved chunks into the prompt without labels — it removes the model's (and your own) ability to trace an answer back to a specific source, which matters enormously the first time a RAG answer is wrong.
Frequent Bugs
Using 0-indexed source numbers in a user-facing citation, producing a confusing '[Source 0]'.
Use `enumerate(chunk_ids, start=1)` (or add 1 manually) so citations are human-numbered starting from 1, matching how people naturally reference a numbered list.
Real-World Examples
Cited HR Answers
A production HR chatbot answers 'You can roll over up to 5 PTO days [Source 1]' and links Source 1 directly to the relevant handbook section — only possible because the context was labeled before generation, not after.
f"[Source {i}] {chunk_texts[chunk_id]}"