Book Deep Read · Generative AI System Design Interview · Ch 6
Generative AI System Design Interview · Ch 6 · Ali Aminian, Hao Sheng & Alex Xu · 2024
You ask your company's AI assistant how much you can expense for a hotel, and it answers fast and fluently — but that rule changed last month. How could it possibly know? This chapter is about the machinery that makes a machine look things up first and only then speak.
Someone who doesn't know the answer usually says so. This kind of machine doesn't. It answers anyway, and the made-up answer sounds exactly as smooth as a true one. Worse, you can't ask where it got that. It can't tell you either — everything it knows is smeared across trillions of words it once read, and it cannot point at any particular sentence.
Two obvious routes both fail. One is to teach it all over again: fold the new documents into its textbooks and have it reread them. That's reprinting a whole dictionary to change one phone number — expensive, slow, and the documents change again next week. The other is to spread everything on the desk: haul in the entire filing room. The desk is only so big; and even when it just about fits, finding one sentence in a roomful of paper is hard, and whatever sits in the middle of the pile is the most likely to be skipped.
The trick that works is to hire a librarian, and split the job in two.
Step one happens on quiet days: build the card catalogue. Cut every document into cards ahead of time, then file them by meaning — cards about the same thing sit together even when the wording is completely different ("accommodation policy" and "hotel spending cap" land in the same drawer). None of this happens while anyone is waiting.
Step two happens the moment you ask: the librarian grabs the hundred most similar cards, skims them down to the five that really bear on your question, and hands those five to the person who answers, along with your question. That person has nothing but the five cards, and exactly one rule: answer only from what is written on them, and mark which card each sentence came from. When no card fits, the correct answer is "it's not in the files."
Three benefits arrive immediately: a document edited today takes effect today, with no retraining; every answer can be traced back to the original text and checked; and files this person isn't allowed to see get blocked at the card-grabbing step. The cost is a single sentence, but a hard one: the whole thing is capped by that card-grabbing step — pick the wrong cards and the more fluent the answer, the worse it is, because it is wrong in a way that reads like truth.
What it produces is not just an answer, but an answer plus where it came from. You think this is about topping up what the machine knows; really it converts "speaking from memory" into "reading off the page" — and from then on, every sentence has somewhere you can go and check.
Want the mechanisms, the notation and the diagrams? → Switch to the deep read
You think retrieval-augmented generation (RAG) is the cheap substitute for "teaching the model more," but what it actually ships is a checkable evidence trail: knowledge you can swap out the same day, sources you can click back to, and failures you can localise to one stage. Fine-tuning and giant context windows give you none of the three. And the engineering conclusion worth carrying out of this chapter is a single sentence: a RAG system's quality ceiling is set by retrieval; the generator only applies a discount beneath it.
384–1536 of them); similar meanings land on similar numbers.The fifth of the ten case studies in Part II, and the closing problem of the text cluster. It follows Ch4 ChatGPT, where all knowledge lived in parametric memory; here an external knowledge base is wired into the generation path for the first time, and from Ch7 onward the book turns to image generation. In the wild it maps to enterprise knowledge-base Q&A, support assistants, document copilots, and every search-style AI product that shows its sources.
Parametric memory has three sins, and none of them is fixed by making the model bigger.
One: it goes stale. The weights freeze on the training cutoff date, while a knowledge base has documents changing every day. Re-running a fine-tune for one policy update takes weeks end to end, from data prep to evaluation and rollout; documents change by the minute. Four or five orders of magnitude apart — not a gap tuning can close.
Two: it can't cite. When the model says "the cap is $120," that number is smeared across trillions of tokens of training text and traces to no sentence anywhere. In legal, medical and financial settings, a correct answer you cannot verify is worth exactly as much as a wrong one — you can't tell which one you are holding.
Three: private data can't get in. Internal documents, a user's own files, material with access tiers — none of it should or can be pressed into one set of shared weights. Weights have no ACL (access control list): once memorised, knowledge cannot be un-remembered for just some people.
What happens if you don't solve it? The model keeps answering fluently about things it does not know, and nowhere in the pipeline is there anything to check against. Which is the upgraded form of the previous chapter's conclusion: the dangerous failure of a generative system is not silence, it is fluent wrongness.
One hard boundary splits the pipeline in two, and once you see it, every later trade-off explains itself.
Offline (indexing): documents → chunks → an embedding per chunk → write into the vector index. Turning a million documents into ten million passages, embedding them and building the index is a batch job measured in hours — because nobody is waiting.
Online (answering): question → embed → retrieve → rerank → assemble the prompt → generate. The whole thing has to fit inside one or two seconds, and generation alone often eats more than a second, leaving retrieval plus reranking perhaps 100–300 milliseconds — and that budget, not the data size, is the real constraint behind every index choice below.
The unit of retrieval is not the document, it is the chunk. How you cut all but decides whether anything can be found.
The instinct is "smaller is sharper": one chunk, one topic, an undiluted embedding, an easier match. But small chunks tear a complete argument in half — handed the first half of a sentence, the model is more likely to invent the second. Too large and a single chunk carries five or six topics, so the embedding averages out into a vector that resembles nothing, scores poorly, and wastes prompt budget besides.
The usual landing zone is 200–500 tokens per chunk with 10%–20% overlap (so an answer straddling a cut isn't lost). But three things matter more than those numbers: cut along structure (headings and paragraph boundaries, not a fixed character count that saws a table in half); carry metadata (title, section path, date, access labels — used for filtering as well as ranking); and contextualise — prepend the section heading or a one-line summary so the chunk stands on its own. That last one targets a concrete failure: a chunk reading "this cap rises to $150 from next month" is, in isolation, about nothing identifiable, and will never match a query.
The two routes fail in almost perfectly complementary ways.
BM25 (keywords) is unbeatable on exact strings: error code ERR_5021, part number X-200, proper names, statute numbers. Embedding those is meaningless; literal matching never misses. Its fatal flaw is paraphrase: the user asks "how do I get my money back," the document says "refund procedure," no shared terms, score zero.
Dense retrieval (vectors) is the mirror image: it crosses wording differences to catch meaning, but derails on rare proper nouns — an embedding model that has never seen that part number treats it as an ordinary string and returns a pile of chunks that merely look technical.
Hybrid retrieval merges the two rankings (commonly with reciprocal rank fusion, which weights by position rather than score and so sidesteps two incompatible score scales). It is the default in most production systems; the price is two indexes to keep in sync and one more fusion weight to tune.
A second layer is how you find the nearest few among ten million vectors. Scoring every one gives 100% recall but costs hundreds of milliseconds to seconds at that scale — the budget is gone. ANN buys speed with structure: HNSW builds a layered neighbour graph, and a query starts on the sparse top layer and hops down, landing in single-digit milliseconds, at the risk of missing the true nearest neighbour. How much it misses is governed by one dial, the search width; turn it up and recall and latency rise together. It is a continuous dial, not a switch — set it as part of your SLO instead of copying a default.
Retrieval uses a bi-encoder: question and passage are encoded separately, which is precisely why passage vectors can be computed offline and stored — and also why the two sides never meet, leaving only a coarse similarity to compare.
A reranker inverts that: question and passage go through the model together, so it can judge whether this passage actually answers this question. The cost is that nothing can be precomputed — every candidate is a fresh forward pass — which makes it one to two orders of magnitude slower than the bi-encoder and usable only on a short list. Hence the standard funnel: ANN pulls 100, the reranker scores them, 3–5 reach the prompt.
Assembly hides two more details. First, position matters: material parked in the middle of a long context is the most likely to be overlooked, so the strongest passages belong at the start and the end rather than laid out in similarity order. Second, every chunk costs tokens and costs latency: 5 chunks × 400 tokens = 2000 tokens, paid again on every single question. Going from k=5 to k=20 rarely moves accuracy much, while the bill and time-to-first-token move for real.
Once the passages arrive, generation's job is not to shine but to restate under constraint. Three concrete requirements: state in the prompt that the answer must come only from the supplied material; attach passage ids per sentence, so citations can be validated by code rather than admired by humans; and allow "I don't know" — when retrieval scores fall below threshold or passages contradict each other, the correct output is "not covered by the material."
That last one is the most counterintuitive product decision in the system: the refusal rate is a dial to be set deliberately, not a defect to be driven to zero. Enterprise Q&A would rather refuse a few more percent of questions than ship one invention nobody can spot.
The first decision comes before any code: how should this knowledge reach the model at all?
Table 1 · Four ways to give a model knowledge
| Put it in the prompt | RAG | Fine-tuning | Stuff the long context | |
|---|---|---|---|---|
| Freshness | Real time | Minutes (re-embed those chunks) | Weeks, plus a re-run of evals | Real time |
| Traceable? | Yes | Yes, citations per sentence | No | Barely; the model must self-report |
| Knowledge ceiling | A few thousand tokens | Effectively unbounded | Bounded by the training corpus | Bounded by the context window |
| Cost per question | Lowest | Low (a handful of chunks) | Low (no material carried) | Highest — you pay for the whole corpus every time |
| Access control | Caller's problem | Filter at retrieval by metadata | Impossible; weights have no ACL | Caller's problem |
| Main cost | Not much fits | A whole retrieval system to run and evaluate | Slow, costly, risks catastrophic forgetting | Latency and bill grow linearly; mid-context material gets skipped |
| Good for | A few stable rules | Large, changing knowledge that must be checkable | Tone, format, domain style | One-off Q&A over a single long document |
Note the last row: fine-tuning and RAG were never competitors — one changes how the model speaks, the other supplies what it says. Production systems routinely run both.
The second decision is the retrieval route, which sets the ceiling on recall@k directly.
Table 2 · Four retrieval configurations
| BM25 only | Dense only | Hybrid | Hybrid + rerank | |
|---|---|---|---|---|
| Strong at | Error codes, part numbers, names, statutes | Paraphrase, colloquial questions | Both | Both, plus "does this actually answer it?" |
| Typical miss | Any rewording scores zero | Rare proper nouns read as noise | A badly tuned fusion weight drags both down | A tight budget forces the candidate list shorter |
| Online cost | Lowest | Low (millisecond ANN) | Two parallel routes; the slower one wins | Tens of ms more plus a model call |
| Ops burden | One inverted index | Vector index + embedding version management | Two indexes to keep in sync | One more model to monitor |
| When to use | Jargon-heavy corpus and jargon-heavy queries | Prototyping; conversational corpora | Default starting point for most systems | Precision-sensitive, with latency to spare |
The third decision is the index itself — really a matter of picking two out of four: recall, latency, memory, and update cost.
Table 3 · Three classes of vector index
| Exact brute force | HNSW (graph) | IVF + quantization | |
|---|---|---|---|
| Recall | 100% | High, tunable via search width | Medium-high; harsher compression costs more |
| Latency | Linear in corpus size; unusable at 10M | Milliseconds | Milliseconds |
| Memory | Raw vectors | Heaviest: raw vectors + graph | Lightest: vectors squeezed to tens of bytes |
| Updates | Trivial | Incremental inserts fine; quality degrades after heavy churn | Periodic rebuilds or codebook retraining |
| Good for | Under 100k vectors, or as a recall baseline | Mainstream scale that fits one machine | Billions, when memory is the hard constraint |
One practical rule: whatever index you end up shipping, first measure recall@k with brute force on a labelled question set and keep it as your baseline. How much recall ANN gave away, and whether that was worth it, is only discussable against that line.
Three landing zones already run at scale: enterprise knowledge-base Q&A (internal documents plus access filtering — where the commercial value concentrates), search-style answers with citations (clickable sources under the answer, so users verify for themselves), and customer and technical support (tickets, manuals and change logs indexed together, so an answer traces to a specific passage of a specific document). The third reveals what this really is: not a smarter model, but the infrastructure that wires an organisation's existing written assets into the generation path.
① What RAG really ships is not an answer but a checkable evidence trail: minute-level freshness, clickable sources, and failures you can localise.
② Parametric memory's three sins — staleness, no citations, private data locked out (weights have no ACL) — survive any increase in model size.
③ The pipeline splits in two: indexing runs offline in hours; answering fits in 1–2 seconds, of which retrieval plus reranking gets 100–300 ms.
④ Retrieval sets the ceiling and generation discounts from it; a passage never retrieved cannot be rescued downstream.
⑤ Chunking is the underrated decision: 200–500 tokens with 10%–20% overlap is typical, but cutting along structure, carrying metadata and prepending the section heading matter more than the numbers.
⑥ BM25 and dense retrieval fail complementarily — one dies on paraphrase, the other on rare proper nouns; hybrid is the production default.
⑦ ANN trades recall for speed through a continuous dial; measure a brute-force recall@k baseline first, then argue about what the trade is worth.
⑧ The funnel shape is fixed: pull 100, rerank, keep 3–5. Rerankers are one to two orders of magnitude slower, so they only ever touch a short list.
⑨ Two assembly rules: strongest passages at the ends (the middle gets skipped), and a larger k reliably raises cost and latency while rarely raising accuracy.
⑩ Refusal rate is a dial you set on purpose; citations must be machine-validated; permissions must be enforced at retrieval.