AI Engineering Learning Hub

Top-K Retrieval

How to choose k in RAG retrieval, why top-5 beat top-3 for this site, and when thresholds, filters and reranking help.

What it is

Top-k retrieval returns the k best-scoring chunks for a query instead of only the single best one. If k is 5, the five most similar chunks are concatenated into the prompt. The idea is that the right answer is usually near the top of the ranking but not always exactly at the top, and that many questions need more than one chunk to answer.

k is a dial between recall and noise. Larger k means more chance the needed chunk is included, but also more irrelevant text in the prompt, higher token cost and more opportunity for the model to be distracted by a near-miss.

On this site the first endpoint used k = 3. When I built the chat endpoint I raised it to 5 because questions like 'what has he done with AWS?' touch several jobs at once, and three chunks kept missing one of them.

Why it's needed

A single chunk rarely contains the full answer to a multi-part question. 'Where has Abdur worked and what did he build there?' spans five employer paragraphs. At the same time, dumping the whole knowledge base into every prompt wastes tokens and buries the signal. Top-k is the practical middle: enough context to answer, little enough to stay focused.

Getting k right is also one of the cheapest quality improvements available. It is a one-line change that you can evaluate in minutes, unlike swapping the embedding model or re-chunking everything.

How it works

  • Score every chunk against the query (cosine similarity), sort descending and keep the first k.
  • Start with k between 3 and 5 for small corpora with clean chunks; go to 8 to 10 when chunks are small or questions are broad.
  • Make k depend on chunk size: five 500-word chunks is 2500 words of context, five 100-word chunks is 500.
  • Add a minimum-score cutoff only after inspecting real score distributions; a fixed threshold from a blog post will not match your model.
  • Filter before ranking when you have metadata: restrict to the right document, date range or tenant, then take top k inside that subset.
  • For larger corpora, retrieve a generous candidate set (k = 20) and rerank with a cross-encoder down to the 3 to 5 you actually send to the LLM.

Code example

import numpy as np

def top_k(index: np.ndarray, query_vec: np.ndarray, chunks: list[str],
          k: int = 5, min_score: float | None = None):
    """index: (N, d) unit vectors; query_vec: (d,) unit vector."""
    scores = index @ query_vec
    order = np.argsort(scores)[::-1][:k]
    results = []
    for i in order:
        if min_score is not None and scores[i] < min_score:
            break                      # ranking is sorted, so stop early
        results.append({"text": chunks[i], "score": float(scores[i])})
    return results

# Quick evaluation harness: does the expected chunk land in the top k?
def recall_at_k(index, encode, chunks, test_set, k):
    hits = 0
    for question, expected_substring in test_set:
        hits_for_q = top_k(index, encode(question), chunks, k)
        if any(expected_substring in r["text"] for r in hits_for_q):
            hits += 1
    return hits / len(test_set)

# Compare k values on the same questions before changing production:
# for k in (3, 5, 8): print(k, recall_at_k(index, enc, chunks, tests, k))

Where I used this

The portfolio chat retrieves the top 5 chunks per question; the simpler /ask endpoint uses top 3. Five was enough to cover multi-part questions like 'what has he built with AWS?' without stuffing the prompt with unrelated facts. Each chunk is one paragraph, so five chunks stay under a thousand tokens.

Use cases

  • Every RAG prompt assembly step
  • Search result pages that show the best N matches
  • Candidate generation before a reranking stage
  • Few-shot example selection: pick the k most similar labelled examples for the prompt

Common mistakes

  • Picking k once and never measuring it again after the knowledge base grows or the chunking changes.
  • Setting k so high that the prompt exceeds the model's useful attention. Models answer worse when the relevant chunk is buried in the middle of a long context.
  • Treating k as the only knob. Chunk quality and the embedding model matter more than k = 3 versus k = 4.
  • Returning top k even when every score is terrible, so the LLM confidently answers from unrelated text.
  • Sending the chunks in random order. Put the highest-scoring chunk first; models weight the start of the context more.

Interview questions

How do you choose k?
Measure recall at k on a test set of real questions: for each question, is the chunk that answers it inside the top k? Pick the smallest k where recall stops improving. For this site that was 5. Then sanity-check the token count of k chunks against the model's context and your cost budget.
What is the downside of a large k?
Token cost, latency and distraction. Irrelevant chunks give the model text to be wrong with, and long contexts suffer from the 'lost in the middle' effect where facts in the centre of the prompt are used less reliably than facts at the start or end.
Should you use a similarity threshold instead of a fixed k?
Usually both: top k with a floor. A pure threshold returns zero results for hard questions and fifty for easy ones. A pure k returns garbage when nothing matches. Set the floor from the score distribution of your own queries, not from a number you read somewhere.
What is reranking and when do you add it?
A second, more expensive model scores query and chunk together and reorders the candidates. You retrieve a wide set with cheap embeddings, say 20, then rerank down to 5. It is worth adding when the corpus is large or when the right chunk is often ranked 4th to 10th by embeddings alone.
How does metadata filtering interact with top k?
Filter first, rank second. If the user asks about 2024 work, restrict candidates to chunks tagged 2024, then take the top k of those. Ranking first and filtering after can leave you with fewer than k results or none at all.
Why did this site move from top-3 to top-5?
Multi-part questions about several employers or several technologies kept missing one relevant paragraph at k = 3. Five chunks of one paragraph each is under a thousand tokens, so the cost increase was negligible and the misses stopped.
Ask the AI assistant about this topic

Get new topics by email

One short, practical AI-engineering lesson whenever a new topic is published. No spam, unsubscribe any time.

Need this built for your product?

I build production RAG pipelines, LLM automations and voice agents. Open to freelance projects and full-time roles.