Master

A retrieval system you can run

The pieces are known; the system is the order of them plus the places a step can quietly return nothing. Build it as small functions with one job each, so a bad answer points at the function that caused it instead of at the whole.

What you will see

The count after filtering. Zero here is the case that must produce 'no documents match', not a guess.

About 1 min of reading

Try It

Run the stages separately.

1

Build stage

chunks = split_by_heading(doc) vecs = [embed(c) for c in chunks] print(len(chunks), len(vecs))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
Two equal counts. A mismatch means a chunk failed to embed, which is a bug that shows up later as a missing answer.
2

Run stage

hits = search(embed(q), vecs, k=20) hits = [h for h in hits if allowed(h)] print(len(hits))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
The count after filtering. Zero here is the case that must produce 'no documents match', not a guess.

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

Stages pass lists to each other.
1 Build: chunk, embed, store
↓
2 Run: embed the question
↓
3 Search, filter, rerank
↓
4 Prompt with the survivors and their ids
Line by line

Read the first example one line at a time. A line that prints shows what appears on screen; the rest set things up quietly.

chunks = split_by_heading(doc) sets nothing on screen
vecs = [embed(c) for c in chunks] sets nothing on screen
print(len(chunks), len(vecs)) Two equal counts. A mismatch means a chunk failed to embed, which is a bug that shows up later as a missing answer.
Why this works
Empty at every stage

Each stage can return nothing: no chunks, no filter survivors, no candidates above the threshold. Each needs its own message, because a blank answer tells the reader nothing about which stage failed.

Make the stages callable alone

A script that runs one stage on a saved input is what makes a bug findable. When the whole pipeline is one call, a wrong answer has seven possible causes and no way to narrow them.

Examples

One function per stage

Chunk, embed, index, search, filter, rerank, prompt. Each takes the previous output and returns a list. A stage that returns an empty list is a bug you can see, which a single long function cannot give you.

Return the trace, not only the answer

The function returns the answer plus the passages it used and their scores. That is the difference between a system someone can debug and a system someone can only complain about.

Build time versus run time

Chunking and embedding the documents happens once, at build. Only the question is embedded at run. Mixing them makes every question slow and makes the stored vectors stale.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Chunking strategies that hold up
Previous Lesson
Chunking strategies that hold up
Next Lesson
Evaluating a retrieval system
Evaluating a retrieval system →