Retrieval & RAG
In one line
Fetch the relevant text at request time and put it in the prompt, because almost everything worth answering about is either private, recent, or needs a citation.
Why it exists
A model knows what was in its training corpus, frozen at a date, with no notion of your private data and no ability to cite anything. That covers almost nothing a business actually asks about: current inventory, this customer's history, the policy that changed last Tuesday, the internal runbook.
is the fix, and it is not a clever trick — it is the obvious one. Search for the relevant passages, put them in the , ask the model to answer from them. is that pattern, and its main virtue is that updating a fact is a database write rather than a training run.
The pipeline is mostly search#
The generation half of RAG is a prompt. The retrieval half is an information retrieval system, and that is where essentially all the engineering lives:
- — split documents into retrievable passages
- Embedding — turn each chunk into a vector, store it with its metadata
- Query — embed the question, find nearest neighbours
- — rescore the shortlist with a stronger model
- Assembly — put the survivors in the prompt with instructions
The most useful diagnostic habit in this whole area follows from that list. When a RAG system gives a bad answer, check what was retrieved before touching the prompt. Most of the time the right passage was never in the context, and no amount of prompt engineering can make a model use text it did not receive.
That is also why is the metric that matters. You can have a perfect generator and a useless system if the search misses one relevant document in three.
Chunking is the decision that matters most#
Chunk boundaries determine what can be retrieved, and they are chosen before any query exists. Get them wrong and no downstream component recovers.
Too small and chunks lose their context. A paragraph reading "This does not apply to enterprise accounts" is meaningless without knowing what "this" was, and it will be retrieved for queries it actively misleads.
Too large and precision collapses. A 4,000-token chunk retrieved for one relevant sentence drags 3,900 tokens of noise into the prompt, crowding out other results and diluting attention.
The starting point that works for most prose is 400 to 800 tokens with of 10 to 15 per cent, so an idea split across a boundary still appears whole somewhere. Better than any fixed number, though, is splitting on structure: a heading, a section, a function, a table. Documents already contain the author's own boundaries, and those are usually better than anything a character counter will find.
Two refinements repay their cost quickly. Contextual prefixing prepends a line of document and section context to each chunk before embedding, so a chunk carries where it came from — this is one of the largest single quality gains available and costs a few extra tokens per chunk. And metadata on every chunk — source, date, section, permissions — lets you filter before searching, which is both a relevance win and, for permissions, a correctness requirement.
Retrieval quality beats model quality#
The reflex when RAG underperforms is to reach for a bigger generator. The ordered list of things that actually help looks nothing like that.
Add keyword search. runs alongside the vector query and merges the rankings. Embeddings are poor at exact identifiers — error codes, SKUs, surnames, version numbers — and keyword search is perfect at them. One extra query, and it removes most of the embarrassing misses.
Add a reranker. A scoring the top fifty candidates sees query and document together, which no pair of independently computed s can. It typically improves what reaches the prompt more than any embedding upgrade, and it only runs on a shortlist so the cost is bounded.
Rewrite the query. "What about the other one?" is unanswerable standalone. Rewriting it against conversation history into "What is the refund window for annual plans?" fixes a large class of multi-turn failures for one cheap model call.
Then, maybe, a better embedding model. It is the expensive option — a full corpus re-embed and index rebuild — and usually the smallest gain of the four.
Grounding, and what it does not fix#
Putting sources in the prompt reduces substantially. It does not eliminate it, and the residual failure modes are specific enough to design against.
The model can contradict the passages, blending retrieved text with training knowledge. It can answer from parameters when retrieval returned nothing useful, which is the most dangerous case because the answer looks identical. And it can cite a passage that does not support the claim it is attached to.
Three mitigations, in order of cost. Instruct explicitly that the answer must come from the provided context and that "I don't know" is an acceptable response — cheap, and it works more often than it sounds like it should. Require inline citations by chunk id, then verify programmatically that every cited id was actually retrieved; a fabricated id is a bug you can catch in code. And for high-stakes paths, run a second cheap call that checks whether each claim is supported by the cited passage.
Note that this is where RAG and divide cleanly. Retrieval carries facts, because facts change. Fine-tuning carries form, because form does not.
Worked example
An internal documentation assistant over 2,000 pages. First version: 1,000-token fixed chunks, vector search, top 3, straight into the prompt. Accuracy on 100 real questions: 61%.
Failures, categorised by hand — which is the step people skip:
retrieval missed the answer entirely 27 cases
right document, wrong chunk 8 cases
model ignored the context 4 cases
Thirty-five of thirty-nine failures were search. Changes, measured one at a time:
baseline 61%
+ split on headings instead of fixed size 68% (+7)
+ prepend doc title and section to each chunk 74% (+6)
+ hybrid search with BM25 79% (+5)
+ cross-encoder rerank, top 50 -> top 5 86% (+7)
+ query rewriting against chat history 89% (+3)
61% to 89%, and the generator never changed. The two interventions that look least like AI work — splitting on headings and adding keyword search — accounted for twelve points between them.
Gotchas
-
Debugging the prompt when retrieval is the problem. Log what was retrieved for every request. If the answer was not in the context, the prompt is irrelevant, and you will otherwise spend days rewording instructions that cannot possibly help.
-
Skipping keyword search because vectors feel more modern. Any query containing an exact token — an error code, an account id, a person's name — is a case where BM25 wins outright and embeddings have nothing to contribute. Hybrid is the default, not an optimisation.
-
Retrieving without filtering on permissions. A has no concept of who is asking. Every chunk needs an access-control field applied as a pre-filter, and this is a data leak rather than a relevance bug if you get it wrong.
-
Stuffing the context window because it is large. More passages mean more noise, more cost and worse attention to the ones that mattered. Five good chunks beat twenty mediocre ones, reliably, and the difference grows with context length.
-
Having no retrieval . Generation quality and retrieval quality are separate numbers and need separate measurement. Track recall at k against a labelled set, and you will usually find the ceiling on your system sitting there.
Mental model
RAG is a cache-aside read path with a very unusual cache. You check the store, assemble what you found, and hand it to something that renders an answer. All the familiar cache-aside questions apply — what is the key, how stale can it be, what happens on a miss — and one new one: your lookup is fuzzy, so "miss" is not a binary. It is a recall percentage, and it is the number your whole system's quality sits on top of.
In practice
Problem statements that lean on this topic. Rated by the phase that makes them land.
Where would the answer come from?
Every answer a model gives has one of three sources — its training, your prompt, or a tool — and asking which one, before building, decides most of the architecture.
no prerequisites · 4 min · #framing #retrieval #architecture
The bot quotes last year's policy, with a citation
Retrieval worked exactly as built — it found the most similar document, which was the stale one — and the fix is in what gets indexed and logged, not in the prompt.
after phase 3 · 4 min · #retrieval #debugging #observability
Chunking a contract so the answers survive
A 500-token window cut clause 7.2 in half; the document already had boundaries, and using the author's beats any character count.
after phase 3 · 4 min · #retrieval #search #architecture
Make it sound like us
One request, two different problems — the facts change weekly and belong in retrieval, the voice is stable and can be taught — and the ladder tells you how far to climb for each.
after phase 3 · 4 min · #prompts #retrieval #product
It got worse and nothing changed
Every dashboard you already had was green; the one that moved is one you would only have if you built it for this kind of system.
after phase 4 · 4 min · #observability #debugging #retrieval
Done reading?
Nothing marks itself complete. Say so only when you could explain this to someone else.
This topic has 4 subtopics.