Metrikker for hentning: Hit rate, MRR og NDCG
Opbyg et golden dataset med forespørgsler og relevante dokumenter, og beregn derefter hit rate, mean reciprocal rank og NDCG for at måle, hvor ofte Deres retriever finder de rigtige bidder.
Metrikker for hentning: Hit rate, MRR og NDCG er en gratis AI Engineering Academy-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i AI Engineering Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. AI Engineering Academy-kurset indeholder 4 lektioner i alt.
Hvorfor forskellige mål for hentning?
Træfraten fortæller dig, om et relevant tekststykke optrådte et eller andet sted blandt de K øverste resultater, men ikke hvor i rangordningen det optrådte. Et system, der altid placerer det bedste tekststykke som nummer 5, er dårligere end et, der konsekvent placerer det som nummer 1, selv om begge har samme træfrate. Mere nuancerede mål som MRR og NDCG indfanger kvaliteten af rangordningen og belønner systemer, der placerer de mest relevante tekststykker øverst, hvor LLM'en og brugerne med størst sandsynlighed vil bruge dem.
Træfrate @K: Gennemgang og implementering
Træfrate@K er det enkleste mål: For hvor stor en andel af forespørgslerne optræder mindst ét relevant tekststykke blandt de K øverste resultater? Det giver et binært signal for hver forespørgsel og er let at fortolke. Beregn det ved at kontrollere snittet mellem de hentede id'er og de kendte relevante id'er. Brug K=5 som standard, eftersom de fleste RAG-systemer henter 5 tekststykker. Sammenlign træfrate@1, @3 og @5 for at forstå, hvordan følsomheden ændrer sig, når du udvider hentningsvinduet.
def hit_rate_at_k(golden_dataset, retriever, k=5):
hits = 0
for item in golden_dataset:
retrieved = retriever.retrieve(item['question'], top_k=k)
retrieved_ids = [r['id'] for r in retrieved[:k]]
relevant_ids = set(item['relevant_chunk_ids'])
if any(rid in relevant_ids for rid in retrieved_ids):
hits += 1
return hits / len(golden_dataset)
for k in [1, 3, 5, 10]:
hr = hit_rate_at_k(golden_dataset, retriever, k=k)
print(f'Hit rate@{k}: {hr:.1%}')Gennemsnitlig reciprok rang (MRR)
MRR (Mean Reciprocal Rank) måler det gennemsnitlige reciprokke tal for den rang, hvor det første relevante tekststykke optræder. Hvis det relevante tekststykke ligger på rang 1, er den reciprokke rang 1/1 = 1,0. På rang 2 er den 0,5, og på rang 5 er den 0,2. MRR beregnes som gennemsnittet over alle forespørgsler. En højere MRR betyder, at hentningskomponenten konsekvent placerer relevante tekststykker tæt på toppen, hvilket er vigtigt, fordi LLM'en lægger større vægt på kontekst, der står tidligt i prompten.
def mean_reciprocal_rank(golden_dataset, retriever, top_k=10):
reciprocal_ranks = []
for item in golden_dataset:
retrieved = retriever.retrieve(item['question'], top_k=top_k)
retrieved_ids = [r['id'] for r in retrieved]
relevant_ids = set(item['relevant_chunk_ids'])
rr = 0.0
for rank, rid in enumerate(retrieved_ids, start=1):
if rid in relevant_ids:
rr = 1.0 / rank
break # only the first relevant result counts
reciprocal_ranks.append(rr)
mrr = sum(reciprocal_ranks) / len(reciprocal_ranks)
print(f'MRR@{top_k}: {mrr:.3f}')
return mrrFortolkning af MRR-scorer
MRR-scorer har intuitive fortolkninger: MRR = 1,0 betyder, at det første relevante tekststykke altid ligger på rang 1 (perfekt). MRR = 0,5 betyder, at det typisk ligger på rang 2. MRR = 0,25 betyder, at det typisk ligger på rang 4 – de relevante oplysninger står så langt nede, at de muligvis afkortes fra konteksten. For RAG bør du sigte efter MRR > 0,7 for at sikre, at dit mest relevante tekststykke konsekvent befinder sig blandt de to første placeringer.
# MRR interpretation table
mrr_interpretations = {
1.0: 'Perfect — relevant chunk always at rank 1',
0.5: 'Good — typically at rank 2',
0.33: 'Acceptable — typically at rank 3',
0.25: 'Weak — typically at rank 4',
0.1: 'Poor — relevant chunk rarely near the top'
}
for score, description in mrr_interpretations.items():
print(f'MRR {score:.2f}: {description}')Præcision @K
Præcision@K måler, hvor stor en andel af de K hentede tekststykker der faktisk er relevante. I modsætning til træfraten, som er binær, måler præcision@K forholdet mellem signal og støj i dine hentningsresultater. Lav præcision betyder, at LLM'en modtager irrelevant kontekst sammen med relevante tekststykker, hvilket øger risikoen for forvirring eller promptinjektion. For RAG er præcision@5 > 0,6 et godt mål.
def precision_at_k(golden_dataset, retriever, k=5):
precisions = []
for item in golden_dataset:
retrieved = retriever.retrieve(item['question'], top_k=k)
retrieved_ids = [r['id'] for r in retrieved[:k]]
relevant_ids = set(item['relevant_chunk_ids'])
relevant_retrieved = sum(
1 for rid in retrieved_ids if rid in relevant_ids
)
precision = relevant_retrieved / k
precisions.append(precision)
mean_precision = sum(precisions) / len(precisions)
print(f'Precision@{k}: {mean_precision:.3f}')
return mean_precisionDiskonteret kumulativ gevinst (DCG)
DCG er et mål til evaluering af rangerede lister, som belønner, at du placerer flere relevante tekststykker højt. Det summerer relevansscorerne for de hentede tekststykker, men diskonterer dem logaritmisk efter placering: rang 1 får fuld værdi, rang 2 får en log(2)-diskontering og så videre. Tekststykker med højere relevans øverst giver en højere DCG. Den normaliserede version (NDCG) dividerer med den ideelle DCG (den bedst mulige rangordning) for at give en score mellem 0 og 1.
import math
def dcg_at_k(relevances, k):
'''relevances[i] = 1 if chunk at rank i+1 is relevant, else 0'''
dcg = 0.0
for i, rel in enumerate(relevances[:k]):
# rank is i+1, discount is log2(rank + 1)
dcg += rel / math.log2(i + 2)
return dcg
def ndcg_at_k(retrieved_ids, relevant_ids, k):
relevances = [1 if rid in relevant_ids else 0
for rid in retrieved_ids[:k]]
actual_dcg = dcg_at_k(relevances, k)
ideal_dcg = dcg_at_k([1] * min(len(relevant_ids), k), k)
return actual_dcg / ideal_dcg if ideal_dcg > 0 else 0.0Beregning af NDCG på tværs af datasættet
NDCG@K er guldstandardmålet for hentning i søgesystemer. Det indfanger samtidig både relevans og rangplacering. En NDCG@5 på 0,85 betyder, at din hentningskomponent i gennemsnit yder 85 % af den teoretisk bedste rangordning. NDCG håndterer tilfælde, hvor der er flere relevante tekststykker pr. forespørgsel (hver får en relevansscore), og straffer systemer, der finder de relevante tekststykker, men rangerer dem for langt nede.
def mean_ndcg_at_k(golden_dataset, retriever, k=5):
ndcg_scores = []
for item in golden_dataset:
retrieved = retriever.retrieve(item['question'], top_k=k)
retrieved_ids = [r['id'] for r in retrieved[:k]]
relevant_ids = set(item['relevant_chunk_ids'])
score = ndcg_at_k(retrieved_ids, relevant_ids, k)
ndcg_scores.append(score)
mean = sum(ndcg_scores) / len(ndcg_scores)
print(f'NDCG@{k}: {mean:.4f}')
return mean
# Compute all retrieval metrics together
hit_rate = hit_rate_at_k(golden_dataset, retriever, k=5)
mrr = mean_reciprocal_rank(golden_dataset, retriever, top_k=5)
ndcg = mean_ndcg_at_k(golden_dataset, retriever, k=5)Brug af RAGAS til automatiserede mål
Biblioteket RAGAS leverer et evalueringssystem til RAG-systemer, der er klar til produktion. Det implementerer mål for kontekstpræcision, kontekstdækning, troskab og svarrelevans ved hjælp af en tilgang, hvor en LLM fungerer som bedømmer. Giv dine spørgsmål, svar, hentede kontekster og facitsvar til RAGAS, og modtag en fuld evalueringsrapport med scorer for hvert mål. Det er den hurtigste måde at opsætte en omfattende evalueringspipeline for RAG på.
from ragas import evaluate
from ragas.metrics import (
context_precision,
context_recall,
faithfulness,
answer_relevancy
)
from datasets import Dataset
eval_data = Dataset.from_list([
{
'question': item['question'],
'answer': item['generated_answer'],
'contexts': item['retrieved_texts'],
'ground_truth': item['expected_answer']
}
for item in golden_dataset_with_answers
])
results = evaluate(
eval_data,
metrics=[context_precision, context_recall, faithfulness, answer_relevancy]
)
print(results)Opdeling af mål efter forespørgselskategori
Samlede gennemsnitlige mål skjuler vigtige mønstre. Opdel dit guldstandarddatasæt i kategorier – faktuelle opslag, sammenligninger, proceduremæssige hvordan-gør-man-spørgsmål og spørgsmål uden for anvendelsesområdet – og beregn mål separat for hver kategori. Du kan opdage, at træfraten er 95 % for faktuelle opslag, men kun 60 % for sammenligninger, der kræver flere hentningstrin. Mål på kategoriniveau afslører de konkrete fejltilstande, som samlede scorer skjuler.
from collections import defaultdict
def evaluate_by_category(golden_dataset, retriever):
by_category = defaultdict(list)
for item in golden_dataset:
category = item.get('category', 'unknown')
retrieved = retriever.retrieve(item['question'], top_k=5)
retrieved_ids = {r['id'] for r in retrieved}
hit = bool(retrieved_ids & set(item['relevant_chunk_ids']))
by_category[category].append(hit)
print('Hit rate by category:')
for cat, hits in sorted(by_category.items()):
hr = sum(hits) / len(hits)
print(f' {cat}: {hr:.1%} ({sum(hits)}/{len(hits)})')Når mål er uenige
Nogle gange sender målene modstridende signaler. Du kan f.eks. forbedre NDCG (bedre rangordning), mens træfraten forbliver uændret (samme antal fejl). Det sker, når en optimering flytter relevante tekststykker fra rang 6 til rang 2 uden at få tidligere oversete forespørgsler ind blandt de 5 øverste. I sådanne tilfælde skal du kontrollere, om optimeringen hjalp på de forespørgsler, der allerede lykkedes, men forsømte dem, der mislykkedes. Undersøg altid individuelle fejleksempler sammen med de samlede mål.
def analyze_failures(golden_dataset, retriever, top_k=5):
failures = []
for item in golden_dataset:
retrieved = retriever.retrieve(item['question'], top_k=top_k)
retrieved_ids = {r['id'] for r in retrieved}
relevant_ids = set(item['relevant_chunk_ids'])
if not (retrieved_ids & relevant_ids):
failures.append({
'question': item['question'],
'expected_chunks': list(relevant_ids),
'retrieved_chunks': [r['id'] for r in retrieved],
'top_score': retrieved[0]['score'] if retrieved else None
})
print(f'Failures: {len(failures)}/{len(golden_dataset)}')
return failuresDækning @K: Fuldstændighed af hentningen
Dækning@K måler, hvor stor en andel af alle relevante tekststykker der blev hentet blandt de K øverste resultater. Hvis et spørgsmål har 3 relevante tekststykker i indekset, og din hentningskomponent returnerer 2 af dem blandt de 5 øverste, er dækning@5 = 2/3 = 0,67. Høj dækning er vigtig, når LLM'en har brug for flere stykker evidens for at danne et fuldstændigt svar – manglen på blot ét centralt tekststykke kan gøre svaret ufuldstændigt. Afbalancér præcision og dækning ved at justere K: Et større K forbedrer dækningen, men reducerer præcisionen.
def recall_at_k(golden_dataset, retriever, k=5):
recalls = []
for item in golden_dataset:
retrieved = retriever.retrieve(item['question'], top_k=k)
retrieved_ids = set(r['id'] for r in retrieved[:k])
relevant_ids = set(item['relevant_chunk_ids'])
if not relevant_ids:
continue # skip items with no annotated relevant chunks
retrieved_relevant = retrieved_ids & relevant_ids
recall = len(retrieved_relevant) / len(relevant_ids)
recalls.append(recall)
mean_recall = sum(recalls) / len(recalls)
print(f'Recall@{k}: {mean_recall:.3f}')
return mean_recallHurtigt tjek
Test din forståelse af begreberne inden for AI Engineering fra denne lektion.
Opsummering af lektionen
I denne lektion lærte du om: træfrate@K som målet for binær tilstedeværelse, MRR til måling af den gennemsnitlige placering for det første relevante tekststykke, præcision@K som forholdet mellem signal og støj ved hentning, NDCG@K som det førende mål for rangerede resultater, og RAGAS-biblioteket til automatisering af RAG-evaluering med kontekstpræcision, kontekstdækning, troskab og svarrelevans. Dernæst går vi i dybden med mål for generering og måling af troskab.
Lær Python med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 30
- Lektioner
- 120
Ofte stillede spørgsmål
Er lektionen “Metrikker for hentning: Hit rate, MRR og NDCG” gratis?
Ja — hele teksten til “Metrikker for hentning: Hit rate, MRR og NDCG” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af AI Engineering Academy-kurset, skal du opgradere til CoddyKit PRO. AI Engineering Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Metrikker for hentning: Hit rate, MRR og NDCG”?
Opbyg et golden dataset med forespørgsler og relevante dokumenter, og beregn derefter hit rate, mean reciprocal rank og NDCG for at måle, hvor ofte Deres retriever finder de rigtige bidder. Du øver dig i AI Engineering Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på AI Engineering Academy?
Der kræves ingen tidligere erfaring. AI Engineering Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 2 af 4.
Hvor lang tid tager lektionen “Metrikker for hentning: Hit rate, MRR og NDCG”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne AI Engineering Academy-lektion?
Ja. Alle AI Engineering Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- Hvorfor evaluering er vigtig i RAG
- Metrikker for hentning: Hit rate, MRR og NDCG
- Metrikker for generering: Troværdighed og svarrelevans
- Opbygning af et automatiseret evalueringssystem