RAGEngineering Hub
Chapter 10 · concept 3 of 6 · show all
  1. 1What RAG is, and why
    1. 1.1Why models need outside knowledge, and what hallucination means
    2. 1.2What RAG is: anatomy of a request
    3. 1.3RAG vs fine tuning vs long context and prompt caching
    4. 1.4Use cases and the quality, latency and cost triangle
    5. Chapter overview
  2. 2Tokens, cost and your first RAG
    1. 2.1Tokens and context windows for RAG
    2. 2.2The RAG lifecycle and your first RAG in miniature
    3. Chapter overview
  3. 3Getting documents in
    1. 3.1Content sources and file formats
    2. 3.2Parsing, layout and OCR
    3. 3.3Tables, images and mixed content
    4. 3.4Cleaning, normalization and quality gates
    5. 3.5Metadata, document identity and versioning
    6. 3.6Updates, deletes, reindexing and ingestion pipelines
    7. Chapter overview
  4. 4Chunking
    1. 4.1Why we chunk, and the main chunking strategies
    2. 4.2Structure aware chunking and tables
    3. 4.3Chunk size, overlap and token based sizing
    4. 4.4Contextual chunking and late chunking
    5. 4.5Parent child and multi representation indexing
    6. 4.6Chunk metadata, provenance and the chunking debugging playbook
    7. Chapter overview
  5. 5Embeddings
    1. 5.1Embeddings and similarity from first principles
    2. 5.2What embeddings cannot do
    3. 5.3Choosing an embedding model: size, cost, language
    4. 5.4Embedding model migration and index rebuilds
    5. Chapter overview
  6. 6Vector stores and scores
    1. 6.1Vector databases, ANN indexes and choosing a store
    2. 6.2Score calibration and thresholds
    3. 6.3Late interaction and multivector retrieval
    4. Chapter overview
  7. 7Finding the right chunks
    1. 7.1Query understanding, rewriting and expansion
    2. 7.2Dense retrieval and keyword search with BM25
    3. 7.3Hybrid retrieval and rank fusion
    4. 7.4topK, no good match, and metadata filtering
    5. 7.5Routing, diversity, deduplication and caching
    6. 7.6Reranking: two stage, cross encoder and LLM rerankers
    7. Chapter overview
  8. 8When retrieval fails
    1. 8.1Retrieval failure analysis playbook
    2. Chapter overview
  9. 9Building the answer
    1. 9.1Context selection, packing and citations
    2. 9.2Grounding prompts and abstention
    3. 9.3Lost in the middle and context management
    4. 9.4Conflicts, staleness and freshness rules
    5. 9.5Hallucination checks and answer verification
    6. 9.6Conversational RAG, answer UX and RAG APIs
    7. Chapter overview
  10. 10Measuring
    1. 10.1Why measure, and what to measure
    2. 10.2Building a golden dataset
    3. 10.3Retrieval metrics: precision, recall, MRR, nDCG
    4. 10.4Faithfulness and answer correctness
    5. 10.5LLM as judge, and judging the judge
    6. 10.6Offline and online evals, regression tests and slices
    7. Chapter overview
  11. 11Safety and operations
    1. 11.1Prompt injection and poisoned documents
    2. 11.2Access control, privacy and governance
    3. 11.3Index lifecycle operations
    4. 11.4Observability and tracing
    5. 11.5Latency, cost, caching and model routing
    6. 11.6Reliability, degraded modes and launch readiness
    7. Chapter overview
  12. 12Scale and advanced RAG
    1. 12.1Scaling, multi tenancy and enterprise architecture
    2. 12.2Choosing an architecture: naive, advanced, agentic, graph
    3. 12.3Agentic RAG and RAG as an MCP tool
    4. 12.4GraphRAG, structured data and multimodal RAG
    5. Chapter overview

Retrieval metrics: precision, recall, MRR, nDCG

Four numbers for “did search find it”, what each one counts, and all four computed for vector, BM25 and hybrid search on our 47 questions, including why precision@3 can never pass 0.33 here.

A real question

Search returned 3 chunks and one holds the answer. Is that 33% or 100%?

Both, depending on the question you ask. Precision asks how much of what was shown is relevant; recall asks whether the relevant thing was found. MRR and nDCG ask how high it was. Each number answers one question.

The problem

Why this matters

Precision@3 is 0.34, so search is mostly wrong.
The belief

Precision@3 is 0.34, so search is mostly wrong.

46 of our 47 questions have exactly one chunk holding the evidence. Three results can then hold at most one hit, so precision@3 tops out near 0.33. BM25's 0.34 is close to perfect.
What really happens

46 of our 47 questions have exactly one chunk holding the evidence. Three results can then hold at most one hit, so precision@3 tops out near 0.33. BM25's 0.34 is close to perfect.

Why not the simpler way

Retrieval metrics come from web search, where many pages can be relevant. In RAG, usually one or two chunks hold the answer. Reading the classic numbers without that context leads to wrong conclusions, such as thinking a precision of 0.34 is poor.

The idea

The idea in plain words

For one question with a ranked list and a set of relevant items:

  • Recall@k = relevant items in the top k / all relevant items. Averaged over questions, it is our "evidence recall@3".
  • Precision@k = relevant items in the top k / k.
  • Reciprocal rank = 1 / rank of the first relevant item; MRR is its mean.
  • nDCG@k = DCG / ideal DCG, where DCG sums gain / log2(rank + 1).

A treasure hunt: recall asks whether you found the treasure, MRR how quickly, precision how many empty boxes you opened on the way.

How it works

Step by step

  1. The share of relevant chunks found in the top k. With one relevant chunk per question, as here, that is the share of questions whose evidence is in the top k (also called hit rate). The main number for RAG: the model cannot use what it never sees.
    1

    Recall@k: found at all?

    The share of relevant chunks found in the top k. With one relevant chunk per question, as here, that is the share of questions whose evidence is in the top k (also called hit rate). The main number for RAG: the model cannot use what it never sees.

  2. 1 divided by the rank of the first relevant chunk, averaged. Rank 1 scores 1, rank 2 scores 0.5, rank 4 scores 0.25.
    2

    MRR: how high?

    1 divided by the rank of the first relevant chunk, averaged. Rank 1 scores 1, rank 2 scores 0.5, rank 4 scores 0.25.

  3. Adds up relevant hits with a discount for lower ranks, divided by the best possible. Handles several relevant chunks and grades of relevance.
    3

    nDCG: graded and position-weighted

    Adds up relevant hits with a discount for lower ranks, divided by the best possible. Handles several relevant chunks and grades of relevance.

In detail

Relevance labels. We mark a chunk relevant if it contains the golden evidence string; this is automatic and strict. Graded labels (2 = answers fully, 1 = partly) need human or model judgement.

Which k. Use the k you actually pass to the model (RAG-29). Recall@10 only matters if a reranker reads the top 10.

Averages hide. Report per slice (RAG-44) and keep per-question ranks for diffs (RAG-39).

Our code. src/lib/rag/metrics.ts implements recallAtK, precisionAtK, reciprocalRank, mrr and ndcgAtK, and is unit tested.

The code

Try it in Python

import math

def recall_at_k(ranked, relevant, k):    return len(set(ranked[:k]) & set(relevant)) / len(relevant)
def precision_at_k(ranked, relevant, k): return len(set(ranked[:k]) & set(relevant)) / k
def reciprocal_rank(ranked, relevant):
    return next((1 / (i + 1) for i, x in enumerate(ranked) if x in relevant), 0.0)

def ndcg_at_k(ranked, gains: dict[str, float], k):
    dcg = sum(gains.get(x, 0) / math.log2(i + 2) for i, x in enumerate(ranked[:k]))
    ideal = sum(g / math.log2(i + 2) for i, g in enumerate(sorted(gains.values(), reverse=True)[:k]))
    return dcg / ideal if ideal else 0.0

See it

What we measured

Measured · retrieval metrics on 47 golden questions

Polder corpus, 34 recursive 512 token chunks. Relevant = chunk contains the evidence string (46 questions have one relevant chunk, 1 has more). Vector: bge-small. Hybrid: RRF of the top 10 from each.

Recall@3vector 0.936BM25 1.000 · hybrid 1.000
Recall@1vector 0.638BM25 0.745 · hybrid 0.702
Precision@3vector 0.319BM25 0.340 · hybrid 0.340
MRRvector 0.784BM25 0.862 · hybrid 0.840
nDCG@5vector 0.831BM25 0.897 · hybrid 0.882

Measured 2026-11-04 with corpus/scripts/measure-parts-4-7.mts, using src/lib/rag/metrics.ts.

Try it on a real example

All four metrics, three retrievers, 47 questions

Retriever

bge-small

recall@1 0.638 · recall@3 0.936 · precision@3 0.319 · MRR 0.784 · nDCG@5 0.831

Finds most answers, often not first.

Choosing

Use it when, avoid it when

Use it when
  • Recall@k at your real k as the main retrieval number
  • MRR or nDCG to see ranking gains
  • Per-slice reports
Avoid it when
  • Judging precision without its ceiling
  • Comparing metrics across different golden sets or relevance rules

What it costs · Free once the golden set has evidence strings: a few lines of code per metric.

In production

Put recall@k and MRR on the dashboard for every index build and retrieval change. Add nDCG once you have graded labels. Never compare numbers across different golden sets or relevance rules; a stricter rule lowers every metric without anything getting worse.

Watch out

Common mistakes

  • Low precision means bad search. With one relevant chunk, 0.33 at k = 3 is the maximum.
  • Recall@10 is what matters. Only the chunks that reach the model matter.
  • One metric is enough. Reranking showed up in MRR and rank 1, not in recall@3.

Check yourself

Remember this

Remember these

  • Recall@k: is the evidence in the top k? The first number for RAG.
  • Precision@k: share of the top k that is relevant; mind the ceiling.
  • MRR: how high the first relevant chunk is.
  • nDCG: position-weighted, handles several relevant chunks and grades.

Say it in an interview

  1. 01Recall@k is my main retrieval number, at the k I really pass to the model.
  2. 02On my corpus BM25 and hybrid reached recall@3 of 1.000; vector 0.936.
  3. 03Precision@3 of 0.34 is near its ceiling, because most questions have one relevant chunk.
  4. 04I use MRR and nDCG to see ranking gains that recall cannot show.
  5. 05Relevance is automatic: a chunk is relevant if it contains the golden evidence string.
Try it yourself: Metrics LabRecall, precision, MRR and nDCG for each retriever over all 47 golden questions.

Quick quiz

Three questions

Question 1

Q1

Precision@3 was 0.34 for BM25. Is BM25 bad?

Question 2

Q2

What does MRR reward that recall@3 does not?

Question 3

Q3 · from RAG-40

What must every golden item store for these metrics to be automatic?

Saved on this device. No account needed.