On this page
- RAG in one sentence, then the honest version
- The pipeline, stage by stage
- Where retrieval quality actually comes from
- The Retrieval Ladder: four gates every answer has to pass
- The arithmetic, with the assumptions on the table
- The questions RAG will never answer well
- Build the thin slice first
- How to tell whether it is working
- What it costs to keep one alive
RAG in one sentence, then the honest version
Retrieval augmented generation is a search system with a language model attached to the end of it. The model supplies fluency, synthesis and format. Every fact in the answer has to arrive from a passage the retriever found first. That is why almost every disappointing RAG system is a search problem wearing a model costume, and why three weeks of prompt tuning usually finds nothing.
The honest version has more parts. A question arrives. Something rewrites it. Two indexes are queried, one matching meaning and one matching exact tokens. The lists are fused, a reranker reorders the survivors, and a handful of passages go into a prompt with the question. The model writes an answer and, if you built it properly, tags each claim with the passage it came from. Nine of those steps are ordinary information retrieval. One is the model. Teams routinely reverse that ratio in where they spend attention.
- Search firstMost quality complaints about a RAG system trace back to retrieval, not to the model.
- Two indexesDense vectors find paraphrase. Keyword search finds identifiers, dates and part numbers. Production systems run both and fuse the results.
- The chunk is the unitA chunk is the smallest thing the system can retrieve and the smallest thing it can cite. A fact split across two chunks is effectively not held.
- Abstention is a build decisionA model given weak evidence writes a confident paragraph unless your design makes silence the easier output.
- Retrieval augmented generation (RAG)
- An architecture where a language model answers using passages fetched at query time from an external store, rather than from what it memorised in training.
- Chunk
- A passage of source text stored and indexed as one retrievable unit. It is both the smallest thing the system can find and the smallest thing it can cite.
- Hybrid retrieval
- Running a dense vector search and a keyword search over the same corpus and merging the two ranked lists, so both paraphrase and exact identifiers are findable.
- Reranker
- A second stage model that scores each candidate passage against the query directly, rather than comparing two independent vectors, and reorders the shortlist.
- Grounding
- The property that every claim in an answer is supported by a passage that was actually retrieved and placed in the model's context.
The pipeline, stage by stage
Eight stages sit between a document in a shared drive and a sentence in an answer. Each can destroy information silently, and the damage is invisible downstream because later stages cannot know what earlier ones threw away.
- Ingest and normalise
Convert the source to text and keep the structure. This is where PDFs eat their own tables and scanned pages yield nothing without OCR. Print a random sample and read it, because most teams never do and never learn that a tenth of the corpus is unusable.
- Split into chunks
Fixed token windows are fastest to build and most likely to sever a claim from the heading that scoped it. Splitting on structure costs more and caps the quality everything downstream can reach.
- Enrich each chunk
Attach source path, document title, heading trail, version, effective date and access group. Prepend a situating line so a chunk reading 'this applies only to annual plans' still means something alone.
- Embed
Record which model produced each vector. Vectors from two models are not comparable, so a model change means re-embedding everything and recalibrating every threshold.
- Index
Vectors into an approximate nearest neighbour index, the same text into a keyword index. Keep metadata queryable so you filter by access group and date during retrieval, not after generation.
- Retrieve
Query both indexes, take twenty to fifty candidates from each, fuse the lists. Reciprocal rank fusion sums one over a smoothing constant plus each rank, so no single confident retriever dominates.
- Rerank and assemble
Score candidates with a cross-encoder, keep a few, deduplicate near-identical passages, then order deliberately. Evidence buried mid-context is used less reliably than evidence at either end, so lead with the strongest.
- Generate and attribute
Send instructions, the passages with stable ids, and the question. Require a source id on every claim and give the model an explicit branch for insufficient evidence.
Stages one and two produce no error messages. A parser that drops every table exits with status zero, and the failure surfaces months later as a user saying the assistant is useless for pricing. Chunking strategies covers stage two, which has the widest quality range and the least discussion.
Where retrieval quality actually comes from
Quality comes from combining retrievers with different failure modes, not from finding one perfect retriever. Dense vectors fail on identifiers, keyword search fails on paraphrase, and each covers the other's blind spot.
| Component | Good at | Blind to | Cost to add |
|---|---|---|---|
| Dense vector search | Paraphrase and topic, questions worded nothing like the source | Identifiers, dates, version numbers, rare proper nouns, negation | An embedding model, a vector index, and a full re-embed on every model change |
| Keyword search (BM25) | Part numbers, error codes, names, acronyms, quoted phrases | Anything phrased differently from the source text | An inverted index, usually already in your database |
| Hybrid with rank fusion | Both of the above, one list covering the other's misses | Nothing new, but it doubles query fan-out and needs a fusion rule | About a day of work and one tuning parameter |
| Metadata filters | Restricting by date range, product line, version or access group | Anything not captured at ingest, which is the hard part | Discipline during ingestion |
| Cross-encoder reranker | Precision in the top five, telling near-misses from real matches | Recall. It only reorders what retrieval already found | Latency proportional to candidate count, plus a model to host or call |
The Retrieval Ladder: four gates every answer has to pass
When an answer is wrong there are exactly four places the failure can be, and each has a different fix. Most wasted RAG effort is a gate three fix applied to a gate one problem: swapping embedding models for weeks while the fact was never in the corpus.
The Retrieval Ladder
Take one wrong answer and climb in order. Stop at the first gate that fails. That gate, not your intuition, names the work.
Is the fact in the corpus at all? Grep the raw source for a distinctive string from the correct answer. Nothing back means a content problem: somebody has to write the missing document, and no retrieval work fixes it.
Did the fact survive ingestion and splitting? Search the chunk store, not the document store. A fact inside a flattened table, or split from its scoping heading, is present in the corpus and unreachable.
Does the right chunk reach the top-k the model sees? Compare recall at five with recall at twenty. A wide gap means the passage is found then buried, a fusion and reranking problem. Both low means gate two lied to you.
Given the right chunk in context, does the model use it? Hand-feed the gold passage and ask again. Still wrong means the prompt, the position of the evidence, or a distractor in the same context. This is the only gate where prompt work is the right response.
| Gate | The test that settles it | The fix that works | The fix that wastes a month |
|---|---|---|---|
| 1 Presence | Grep raw sources for a phrase from the true answer | Write the missing content, or teach the system to say it is not covered | Changing embedding models |
| 2 Survival | Search the chunk store for the same phrase | Fix the parser or the splitter, then re-index | Raising top-k |
| 3 Rank | recall@5 against recall@20 on a fixed question set | Hybrid retrieval, rank fusion, then a cross-encoder reranker | Rewriting the system prompt |
| 4 Use | Hand-feed the gold passage and re-ask | Prompt structure, evidence ordering, deduplication, an abstention branch | Buying a bigger model |
The arithmetic, with the assumptions on the table
RAG has two cost curves that behave differently. Indexing is roughly one-time, proportional to corpus size, and paid again on any embedding or splitter change. Answering is per question, dominated by the passages you paste in, and you pay it on every call forever.
The prices below are stand-in numbers so the arithmetic runs, and they are not quotes. Model prices change constantly, so substitute today's figures from your provider before reading anything into the result.
Move top-k from six to twenty and watch the dominant term triple, for a recall gain a reranker would have delivered far cheaper. This is the most common way a RAG system becomes expensive: somebody raised top-k to fix a ranking problem, it appeared to help, and nobody revisited it.
The questions RAG will never answer well
Retrieval finds passages. If the answer is stated in no single passage, retrieval cannot find it, and the model assembles something plausible from the fragments it did get. No amount of chunking work fixes this, so know the shape of these questions before promising a system that handles them.
- Aggregation. How many contracts included a termination clause last quarter. The answer lives in a count across thousands of passages, not in one. Route it to SQL.
- Superlatives. Which supplier gives the longest payment terms. Worse than aggregation, because the model names whichever supplier happened to be retrieved.
- Negative existence. Do we have any policy on this. Retrieval returns the nearest thing regardless, and a near thing reads exactly like a hit.
- Multi-hop chains. Who approved the change that caused the outage. The second query depends on the first answer, which is an agent loop rather than one retrieval pass.
- Time sensitive questions with no version metadata. Three editions of a policy and no effective dates means the system is guessing which one you meant.
If the corpus is a handful of documents, build the version that pastes them in whole first. It takes an afternoon, gives an honest quality baseline, and occasionally ships. Building a retrieval pipeline for a corpus that does not need one is the most common over-engineering in this field. Context limits and prices move, so recheck that boundary per build rather than trusting a remembered number.
Build the thin slice first
The fastest route to a working system is one narrow question type, end to end, on real documents, in front of real users, in about two weeks. Breadth after that is mostly repetition. Breadth before it is how six month RAG projects happen.
How to tell whether it is working
Measure retrieval and generation separately. One end-to-end score tells you the system got worse and nothing about which half did it, so every regression becomes an argument. Two numbers turn the same regression into a ten minute diagnosis.
# retrieval_eval.py
# Run this before you touch the prompt. It measures the search, not the writing.
#
# gold.jsonl, one line per question:
# {"q": "what is the refund window on annual plans",
# "gold_ids": ["policy-refunds-v7#s3"], "must_abstain": false}
import json, statistics
def recall_at_k(hits, gold, k):
return 1.0 if set(h["id"] for h in hits[:k]) & set(gold) else 0.0
def reciprocal_rank(hits, gold):
for i, h in enumerate(hits, 1):
if h["id"] in gold:
return 1.0 / i
return 0.0
rows = [json.loads(line) for line in open("gold.jsonl")]
r5, r20, mrr = [], [], []
for r in rows:
hits = retrieve(r["q"], k=20) # your retriever, untouched
r5.append(recall_at_k(hits, r["gold_ids"], 5))
r20.append(recall_at_k(hits, r["gold_ids"], 20))
mrr.append(reciprocal_rank(hits, r["gold_ids"]))
print("recall@5 ", round(statistics.mean(r5), 3))
print("recall@20", round(statistics.mean(r20), 3))
print("mrr ", round(statistics.mean(mrr), 3))
# How to read the gap:
# recall@20 high, recall@5 low -> ranking problem, add a reranker
# both low -> indexing or chunking problem
# both high, answers still bad -> prompt or context assembly problem
The answer side needs its own scoring: is every claim supported by a retrieved passage, does the system abstain on unanswerable questions, does it cite what it used. Writing evals for LLM systems covers the generation half, and citations and grounding covers making answers checkable.
What it costs to keep one alive
A RAG system is an index that has to stay synchronised with a corpus people keep editing, and that ongoing obligation is the part nobody budgets for.
| Obligation | How often | What happens if you skip it |
|---|---|---|
| Incremental re-index of changed documents | Continuously, nightly at worst | The system quotes last month's policy confidently, with no signal that it is stale |
| Deletion propagation | Same run as ingestion | A deleted document keeps being retrieved and cited, which is the version that reaches a lawyer |
| Permission synchronisation | Same run, filtered at query time | A user sees a passage, a title and a quote from a document they cannot open |
| Full re-embed | On any embedding model or splitter change | Half the index sits in one vector space and half in another, so every score is meaningless |
| Threshold recalibration | After any embedding or reranker change | Your abstention floor was tuned for scores that no longer exist |
| Gold set refresh | Quarterly, or when the product changes | Evals pass while real users get worse answers, the most dangerous state a system can be in |
If you are scoping a build, price the operating side explicitly instead of treating it as a rounding error on the build. Our approach to that split is on the RAG and knowledge systems page.
A RAG system is a search system with a language model attached to the end. Every fact in the answer has to arrive from a passage the retriever found first, which is why quality problems should be diagnosed in order: is the fact present, did it survive chunking, did it rank into the top-k, and did the model use it.
Questions readers ask next
How does RAG work in simple terms?
Is RAG still necessary now that context windows are large?
Why does my RAG system give wrong answers when the document clearly says otherwise?
How many chunks should I send to the model?
Can RAG answer questions that require counting across all documents?
How long does a first RAG build take?
ChatGPTalker. "RAG Explained for People Who Have to Build It." chatgptalker.com, 2026-08-26. https://chatgptalker.com/guides/rag-explained-for-builders/