Where we left off

This course assumes you've either done naive_rag or otherwise know what dense retrieval is: embed the query, embed every chunk, rank by cosine similarity, take the top k. If either of those last two sentences was new information, do naive_rag's Beginner tier first, this lesson compresses nine of its lessons into one script and moves fast.

Lesson 1 showed dense retrieval's blind spot on an ID-heavy question. This lesson shows the opposite: a question dense retrieval is built for, so the rest of the course has a clear baseline for "when dense alone is enough" before Lesson 3 starts building the thing that covers what it isn't enough for.

The code, piece by piece

QUESTION = "Why does my espresso taste weak and sour lately?"

Notice what's missing: no "descale," no "Puly Caff," no "boiler," none of the words the actual document uses. This is a paraphrase, in meaning only, exactly the shape of question dense retrieval handles well.

def build_store() -> list[dict]: ...
def retrieve(query_vector, store, k=2) -> list[dict]: ...
def generate(question, chunks) -> str: ...

The same three functions from naive_rag Lessons 5-7, unchanged: embed and store, rank and take top-k, stuff into a prompt. This course builds a second, independent retriever alongside this one starting Lesson 3, then spends the rest of Beginner and Intermediate combining the two, this function shape is the "dense half" of that combination.

Checkpoint

  • Dense retrieval: embed, rank by cosine similarity, take top k - unchanged from naive_rag, this course's "dense half."
  • Paraphrased, meaning-based questions are dense retrieval's strength, confirmed by comparing this lesson's margin against Lesson 1's.
  • Starting Lesson 3, a second retriever gets built from scratch to cover the gap Lesson 1 demonstrated, then the two get fused.

If anything here still feels unclear, ask before moving to Lesson 3.