Independent teaching notes. Not affiliated with xAI or Grok.

Practice page · Week 3

Reciprocal rank fusion

Keyword search and vector search fail differently. Reciprocal rank fusion (RRF) combines their rankings with one small formula, so a result near the top of both lists wins and neither leg has to be trusted alone.

Extracted from Week 3: Search and retrieval. Northline and Mill City Permits are fictional practice. Portfolio policy.

Why hybrid

Keyword match misses "time off for a new parent" when the page says "parental leave." Vector match can miss an exact identifier: a SKU, an order id, a statute number. Hybrid search runs both over the same filtered candidates and fuses the ranks.

The formula

Each list contributes 1 / (k + rank) for every chunk it ranks, and the contributions are added. Rank 1 adds 1/61 when k = 60. k is commonly 60. It is a parameter, not a law. The lab names it RRF_K, and test_rrf_constant_is_the_usual_default pins it. Do not retune it on three documents.

for rank, row in enumerate(by_vec, start=1):
    scores[row["chunk_id"]] = scores.get(row["chunk_id"], 0.0) + 1.0 / (RRF_K + rank)
for rank, row in enumerate(by_kw, start=1):
    scores[row["chunk_id"]] = scores.get(row["chunk_id"], 0.0) + 1.0 / (RRF_K + rank)
ordered = sorted(scores, key=lambda cid: (-scores[cid], cid))[:k]

The arithmetic

Two live chunks, an employee query, k = 60. Vector order: leave-2 rank 1, leave-other rank 2. Keyword order: leave-other rank 1, leave-2 rank 2.

Fusion did not break the tie. RRF does not invent a winner when the two lists are reverses of each other. So the lab sorts by score descending, then chunk_id ascending, and two deploys agree. test_equal_rrf_scores_break_on_chunk_id forces the two legs into opposite orders so the fused scores match, then checks that a-chunk comes before b-chunk. Relying on dict insertion order instead would prefer whichever chunk the vector leg happened to rank first.

What the lab is not doing

Where it sits

Fusion runs inside the candidate set, after access control and tombstones. A better rank never makes a forbidden chunk allowed. A cross-encoder reranker on the top 20 is useful once a labeled set shows the first-stage rank is wrong. It is not the first thing to build.

In a case

Mill City Permits answers from a named corpus. Whatever the rank, a question about fees gets "outside this corpus," not an amount, because the fee pages were never in the store. Rank decides order among allowed pages. It does not decide scope.

Go to Week 3: Search

Last technically reviewed: October 2026. Tested with: Python 3, stdlib, SQLite, stand-in model. Not a live provider.