Day 117 ยท The librarian double-checks the pile

Reranking & Query Transforms

You will be able to
  • Explain bi-encoder vs cross-encoder architectures and why cross-encoders judge relevance better
  • Justify two-stage retrieval economics: cheap recall over millions, expensive precision over twenty
  • Apply query rewriting, expansion, and HyDE, and say which failure each one targets
  • Implement parent-child (small-to-big) retrieval and measure a precision@k improvement
Today's ~120 minutes
Spaced-rep: due cards + write the RRF formula from memory (D116)10 min
ELI5 + tech read; rerank-flow visualizer20 min
Guided: two-stage lab + query transforms45 min
Practice: rerank-depth economics memo18 min
Project: extend retrieval.py20 min
Quiz + flashcards7 min

Builds on: Day 116 โ€” Hybrid search ยท Day 115 โ€” Embeddings & vector DBs ยท Day 94 โ€” Attention (Q/K/V)

The analogy

The library assistant sprints through the stacks and returns with twenty books that "seem about right" โ€” fast, because she only glanced at the spines. Then the senior librarian sits down with your actual question, opens each of the twenty books, reads a page of each WHILE re-reading your question, and hands you the best three in order. Slow per book โ€” which is exactly why she only does it for twenty, never for the whole library.

That's two-stage retrieval. Stage one (your bi-encoder embeddings + BM25) is the sprinter: it compressed every book into a point on the map long before you arrived, so it can't consider your specific question deeply. Stage two, the reranker, is a cross-encoder: it reads query and document TOGETHER, letting every word of one attend to every word of the other, and scores the pair properly. And sometimes the librarian fixes your QUESTION before searching: "the thing where salary keeps coming when you have a baby?" becomes "parental leave pay policy" โ€” query rewriting. Or she imagines what the perfect answering page would look like and searches for THAT โ€” that trick is called HyDE.

Why this matters on the job

Reranking is the highest-leverage single upgrade in most RAG stacks โ€” teams routinely report the largest quality jump per line of code changed, because stage one optimizes recall ("is the answer somewhere in these 20?") while the LLM needs precision ("are the top 3 actually it?"). It also fights lost-in-the-middle (Day 104): reranking puts the best chunk first, where the model actually reads. Query transforms attack the other half of failures โ€” bad queries, not bad indexes. As an FDE, "we added a reranker and rewrote queries" is the before/after demo that wins renewals; expect interview questions on bi- vs cross-encoders verbatim.

Watch it happen

The librarian double-checks the pile โ€” rerank turns recall into precision

step 1 / 5
Queryโ†’Fast retrievaltop-20, ~10 msโ†’Rerankercross-encoderโ†’Top-3to the promptโ†’Generate
โœ‰ 20 candidates: the answer is in thereโ€ฆ somewhere around rank 7

Fast retrieval (ANN + BM25) is optimized for RECALL: cast a wide net, top-20 candidates in milliseconds. But the net catches plausible-looking junk too.

Guided practice

guided 1

Two-stage retrieval with a measurable precision@3 gain

25 min
  1. Create rerank_lab.py with the starter code. Stage one is Day 116's hybrid retriever over a 12-chunk corpus with several near-miss distractors. Stage two is a simulated cross-encoder: it scores (query, doc) PAIRS using phrase-level evidence โ€” bigram matches and coverage of query terms โ€” which a bag-of-words bi-encoder structurally cannot see. (In local runs you'd swap in sentence-transformers' CrossEncoder โ€” the harness is identical.)
  2. Run the labeled eval: 5 queries, each with known relevant chunk IDs. The script prints precision@3 for stage-one-only vs reranked.
  3. Confirm the mechanism on query 1: stage one ranks the distractor ("vacation REQUEST process") above the answer ("vacation ACCRUAL policy") because single words overlap; the pair-scorer sees the bigram "roll over" and flips them.
  4. Record your precision@3 lift. Then set RERANK_DEPTH to 3 (rerank only stage one's top-3) and watch the gain shrink: a reranker cannot promote what stage one never fetched. Recall first, then precision.
๐Ÿ python โ€” editable, runs in your browser
Ctrl/โŒ˜+Enter runs ยท Tab indents ยท numpy/pandas/sklearn auto-load on import (torch and network calls need a local run)
guided 2

Query transforms: rewrite, HyDE, small-to-big

20 min
  1. Append the starter code. It demonstrates three transforms against the same corpus.
  2. Rewriting: the conversational query "and what about carrying them over?" retrieves garbage alone. The rewritten, self-contained version (simulating what an LLM produces given chat history) retrieves hr-1. In production the rewrite prompt is: "Given the conversation, rewrite the last user message as a fully self-contained search query."
  3. HyDE: the query "use it or lose it?" shares no vocabulary with any chunk. The fake hypothetical answer (write it yourself: one sentence a policy doc WOULD say) retrieves correctly โ€” wrong facts, right vocabulary, right neighborhood. Verify by making your hypothetical say "20 days roll over" (factually wrong) and watching retrieval still succeed.
  4. Small-to-big: sentences are indexed as children pointing at parent sections; retrieval matches a crisp sentence, but the returned context is the whole parent. Confirm the returned parent contains BOTH the accrual rate and the rollover cap โ€” completeness the child alone lacked.
๐Ÿ python โ€” editable, runs in your browser
Ctrl/โŒ˜+Enter runs ยท Tab indents ยท numpy/pandas/sklearn auto-load on import (torch and network calls need a local run)

On your own

Rerank-depth economics memo

18 min

Your capstone will rerank with a cross-encoder at ~30 ms per (query, doc) pair, after a stage one that takes ~50 ms total. Write a short memo (code optional) answering: (1) total added latency at rerank depths 5, 20, 50, 100 assuming sequential scoring, then assuming batches of 16 scored in parallel at 40 ms/batch; (2) using your lab result that gains shrink with depth, which depth do you recommend for an interactive docs-QA UI with a 2-second answer budget, and why; (3) one situation where you would rerank with an LLM prompt instead of a cross-encoder.

Hints: depth ร— 30 ms sequential; ceil(depth/16) ร— 40 ms batched. LLM-as-reranker fits when volume is tiny and you already pay for the LLM call.

Ship before you stop

Add rerank + transforms to the capstone retriever

Extend Day 116's retrieval.py: (1) a Reranker class with the pair-scoring interface (score(query, text) -> float), shipping today's heuristic scorer and a documented drop-in stub for sentence-transformers' CrossEncoder locally; (2) HybridRetriever.search(..., rerank_depth=20) running fuse-then-rerank; (3) a rewrite_query(history, query) hook that returns the prompt to send an LLM (string in, string out โ€” testable without an API key); (4) the labeled 5-query eval from the lab as a pytest that asserts reranked precision@3 โ‰ฅ stage-one precision@3. Commit with before/after numbers in the README.

Rubric โ€” check what you completed (0/6)

Common mistakes & misconceptions

  • Reranking to fix a recall problem. If the answer isn't in stage one's candidates, no reranker can surface it โ€” widen k, fix chunking, or add hybrid FIRST; rerankers only reorder.
  • Using a cross-encoder as the primary retriever. One forward pass per document per query does not scale past thousands of docs โ€” that's the whole reason two stages exist.
  • Confusing the two encoder types: bi-encoders embed separately (indexable, weaker); cross-encoders read the pair jointly (unindexable, stronger). Interviews ask exactly this.
  • Skipping query rewriting in multi-turn chat. "What about the second one?" embeds to mush; conversational RAG without rewrite fails on most follow-ups.
  • Expecting HyDE to add knowledge. It only fixes vocabulary mismatch by moving the query into document space; the hypothetical's wrong facts are never shown to the user.
  • Measuring reranker value by vibes. Precision@k on a labeled query set is 20 lines of code (you wrote them today); without it you cannot justify the added latency.
Knowledge check

Q1. Why can a cross-encoder outrank a bi-encoder on the same (query, document) pair?

Q2. Retrieval recall@20 is 55% โ€” the right chunk is usually absent from the top 20. Adding a reranker willโ€ฆ

Q3. What makes HyDE work despite the hypothetical document containing wrong facts?

Go deeper โ€” curated resources

articlePinecone โ€” rerankers & two-stage retrieval โ†—25 minpaperHyDE paper โ€” Precise Zero-Shot Dense Retrieval (Gao et al.) โ†—25 mindocsSentence-Transformers โ€” cross-encoder usage โ†—15 min
If you have a third hour
  • Lost-in-the-middle mitigation by ordering โ€” After reranking, place the best chunk first and second-best last (ends of the context) rather than strictly in order โ€” models attend to edges. Try it on Day 119.
Done means
  • Precision@3 lift measured and the depth experiment explained
  • All three transforms demonstrated, including the wrong-facts HyDE test
  • Economics memo written with latency math
  • retrieval.py extended; eval test green; lift recorded in README
  • Quiz โ‰ฅ 2/3
How this connects

โ† Back: Day 94's attention is literally why cross-encoders win โ€” joint attention over the pair. Day 116's RRF reappears as the fusion step before reranking, and Day 114's size dilemma just got its structural fix in small-to-big.

Forward โ†’: Day 118 chains these transforms into multi-hop and agentic retrieval. Your capstone v0 (Day 119) ships fuse-then-rerank, and Day 136 upgrades today's 5-query eval into a 40-case Ragas-style harness.

Unlocks: D118 Advanced RAG Patterns ยท D119 Week 17 Checkpoint: Capstone Kickoff โ€” Docs-QA v0 ยท D136 RAG Evaluation