0Pricing
AI Engineering Academy · Lezione

Misurare l'impatto del re-ranking

Esegua un benchmark prima e dopo, confrontando il retrieval a una fase con quello a due fasi e re-ranking, e misurando NDCG, MRR e la qualità delle risposte end-to-end.

Misurare l'impatto del re-ranking è una lezione AI Engineering Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento AI Engineering Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso AI Engineering Academy include 4 lezioni in totale.

Perché misurare l'impatto del riordinamento?

Il riordinamento aggiunge latenza e costi alla pipeline. Senza misurazioni, non è possibile stabilire se la complessità aggiuntiva valga la pena. Il benchmarking quantifica il miglioramento della qualità del recupero e della qualità delle risposte end-to-end, consentendo di prendere una decisione informata. Inoltre, rivela quali tipi di query traggono maggior beneficio, permettendo di applicare il riordinamento in modo selettivo anziché a ogni richiesta.

Creazione di un set di test di riferimento

Un benchmark affidabile richiede un set di test di riferimento: una raccolta di query associate agli ID dei documenti di cui è nota la rilevanza. Lo si crea campionando query reali degli utenti dai log dell'applicazione, identificando manualmente i documenti rilevanti o ricorrendo all'annotazione di esperti e organizzando i dati in un formato strutturato. Un set di test composto da 50-200 query è sufficiente per la maggior parte delle valutazioni RAG.

golden_test_set = [
    {
        'query': 'How does pgvector HNSW indexing improve search speed?',
        'relevant_doc_ids': ['doc_042', 'doc_107'],
    },
    {
        'query': 'What is the difference between BM25 and dense retrieval?',
        'relevant_doc_ids': ['doc_015'],
    },
    {
        'query': 'How to implement reciprocal rank fusion in Python?',
        'relevant_doc_ids': ['doc_093', 'doc_094'],
    },
    # ... 47 more entries
]

print(f'Test set size: {len(golden_test_set)} queries')
print(f'Avg relevant docs per query: {sum(len(e["relevant_doc_ids"]) for e in golden_test_set) / len(golden_test_set):.1f}')

Metriche del recupero: NDCG, MRR, hit rate

Utilizzi tre metriche complementari per valutare la qualità del recupero. Hit Rate a K misura se almeno un documento rilevante compare tra i primi K risultati. MRR (Mean Reciprocal Rank) misura il reciproco medio della posizione del primo documento rilevante. NDCG a K (Normalized Discounted Cumulative Gain) misura la qualità dell'ordinamento, assegnando un peso maggiore alle posizioni più alte rispetto a quelle più basse.

def compute_retrieval_metrics(results: list[str], relevant_ids: set, k: int = 5):
    results_at_k = results[:k]
    relevant_found = [r for r in results_at_k if r in relevant_ids]

    # Hit rate
    hit = 1 if relevant_found else 0

    # MRR
    rr = 0
    for i, doc_id in enumerate(results_at_k, start=1):
        if doc_id in relevant_ids:
            rr = 1.0 / i
            break

    # NDCG (binary relevance)
    import math
    dcg = sum(
        1.0 / math.log2(i + 1)
        for i, doc_id in enumerate(results_at_k, start=1)
        if doc_id in relevant_ids
    )
    ideal = sum(1.0 / math.log2(i + 1) for i in range(1, min(len(relevant_ids), k) + 1))
    ndcg = dcg / ideal if ideal > 0 else 0

    return {'hit': hit, 'rr': rr, 'ndcg': ndcg}

Baseline: recupero dense a singolo stadio

Prima di misurare l'impatto del riordinamento, stabilisca una baseline utilizzando il recupero dense a singolo stadio. Esegua ogni query del set di test tramite il retriever bi-encoder, raccolga gli ID dei documenti ordinati e calcoli la media di NDCG, MRR e hit rate. Questa baseline indica il punto di partenza del miglioramento: se la baseline è già pari a 0.95 NDCG@5, il riordinamento ha poco margine per migliorare.

def evaluate_pipeline(retriever_fn, test_set: list[dict], k: int = 5) -> dict:
    all_metrics = []

    for entry in test_set:
        query = entry['query']
        relevant = set(entry['relevant_doc_ids'])

        results = retriever_fn(query, top_k=k)
        result_ids = [r['id'] for r in results]

        metrics = compute_retrieval_metrics(result_ids, relevant, k)
        all_metrics.append(metrics)

    n = len(all_metrics)
    return {
        f'hit_rate@{k}': sum(m['hit'] for m in all_metrics) / n,
        f'mrr@{k}': sum(m['rr'] for m in all_metrics) / n,
        f'ndcg@{k}': sum(m['ndcg'] for m in all_metrics) / n,
    }

Esecuzione del benchmark prima e dopo

Esegua la stessa funzione di valutazione sia sul retriever a singolo stadio sia sul retriever a due stadi con riordinamento. Stampi i risultati affiancati, così da rendere immediatamente visibile il miglioramento, o la sua assenza. Tenga traccia della latenza per query insieme alle metriche di qualità: un incremento della qualità del recupero del 5 percento potrebbe non giustificare un aumento della latenza di 400 ms, a seconda dei requisiti SLA della sua applicazione.

import time

def evaluate_with_latency(retriever_fn, test_set, k=5):
    metrics_list = []
    latencies = []

    for entry in test_set:
        t0 = time.perf_counter()
        results = retriever_fn(entry['query'], top_k=k)
        latencies.append((time.perf_counter() - t0) * 1000)

        result_ids = [r['id'] for r in results]
        metrics_list.append(compute_retrieval_metrics(
            result_ids, set(entry['relevant_doc_ids']), k
        ))

    n = len(metrics_list)
    return {
        f'hit_rate@{k}': sum(m['hit'] for m in metrics_list) / n,
        f'ndcg@{k}': sum(m['ndcg'] for m in metrics_list) / n,
        'p50_latency_ms': sorted(latencies)[n // 2],
        'p99_latency_ms': sorted(latencies)[int(n * 0.99)],
    }

baseline = evaluate_with_latency(dense_retrieval_fn, golden_test_set)
two_stage = evaluate_with_latency(two_stage_fn, golden_test_set)
print('Baseline:', baseline)
print('Two-stage:', two_stage)

Interpretazione dei miglioramenti dell'NDCG

I miglioramenti tipici ottenuti aggiungendo il riordinamento con cross-encoder al recupero dense variano da 0.05 a 0.15 di NDCG@5 assoluto, equivalenti a circa 5-15 punti percentuali. Il miglioramento è maggiore quando: (1) le query sono diversificate e contengono molte parafrasi, (2) il corpus contiene molti blocchi quasi rilevanti oppure (3) il retriever di primo stadio è debole. Se osserva un miglioramento dell'NDCG inferiore a 0.02, il beneficio potrebbe non giustificare la complessità aggiuntiva.

# Interpreting benchmark results

example_results = {
    'baseline': {'hit_rate@5': 0.78, 'ndcg@5': 0.64, 'p99_latency_ms': 35},
    'two_stage': {'hit_rate@5': 0.89, 'ndcg@5': 0.77, 'p99_latency_ms': 287},
}

delta_ndcg = example_results['two_stage']['ndcg@5'] - example_results['baseline']['ndcg@5']
delta_latency = example_results['two_stage']['p99_latency_ms'] - example_results['baseline']['p99_latency_ms']

print(f'NDCG improvement: +{delta_ndcg:.2f} (+{delta_ndcg/example_results["baseline"]["ndcg@5"]*100:.0f}%)')
print(f'Latency increase: +{delta_latency}ms')
# NDCG improvement: +0.13 (+20%) — clearly worth the 252ms latency cost

Misurazione della qualità delle risposte end-to-end

Le metriche del recupero misurano se sono stati recuperati i documenti corretti, ma la misura definitiva è la qualità delle risposte end-to-end. Utilizzi un LLM come valutatore per verificare se le risposte generate a partire dal contesto riordinato sono più corrette e fedeli rispetto alle risposte generate dal contesto a singolo stadio. Assegni un punteggio da 1 a 5 per correttezza, fedeltà e rilevanza, quindi calcoli la media sull'intero set di test.

from openai import OpenAI

client = OpenAI()

JUDGE_PROMPT = '''
Rate the following answer on a scale of 1-5 for correctness and faithfulness to the context.

Question: {question}
Context: {context}
Answer: {answer}
Ground truth: {ground_truth}

Return a JSON with fields: {"correctness": int, "faithfulness": int, "explanation": str}
'''

def judge_answer(question, context, answer, ground_truth):
    prompt = JUDGE_PROMPT.format(
        question=question, context=context,
        answer=answer, ground_truth=ground_truth,
    )
    response = client.chat.completions.create(
        model='gpt-4o',
        messages=[{'role': 'user', 'content': prompt}],
        response_format={'type': 'json_object'},
    )
    import json
    return json.loads(response.choices[0].message.content)

Analisi stratificata per tipo di query

Le metriche medie nascondono differenze importanti tra i tipi di query. Suddivida il set di test in categorie — ricerche fattuali (chi, che cosa, quando), query procedurali (come fare), query concettuali (perché, spiegazioni) e query tecniche (codici di errore, nomi di API) — e calcoli le metriche separatamente per ogni gruppo. Il riordinamento è spesso più utile per le query concettuali e procedurali, dove la comprensione semantica conta più della corrispondenza delle parole chiave.

def stratified_eval(retriever_fn, test_set, k=5):
    groups = {'factual': [], 'procedural': [], 'conceptual': [], 'technical': []}

    for entry in test_set:
        q = entry['query'].lower()
        if any(w in q for w in ['how to', 'how do', 'steps to']):
            groups['procedural'].append(entry)
        elif any(w in q for w in ['why', 'explain', 'what is the reason']):
            groups['conceptual'].append(entry)
        elif any(c.isupper() for c in q.split()) or 'error' in q:
            groups['technical'].append(entry)
        else:
            groups['factual'].append(entry)

    for group_name, group_entries in groups.items():
        if group_entries:
            metrics = evaluate_pipeline(retriever_fn, group_entries, k)
            print(f'{group_name} ({len(group_entries)} queries): ndcg@{k}={metrics[f"ndcg@{k}"]:.3f}')

Test di regressione con integrazione CI

Esegua il benchmark del recupero come test di regressione nella CI. Imposti soglie minime accettabili per NDCG@5, MRR e hit rate. Qualsiasi modifica alla pipeline che faccia scendere le metriche al di sotto della soglia farà fallire la build CI, impedendo che regressioni nella qualità del recupero arrivino in produzione. Questo è particolarmente importante dopo aver modificato le dimensioni dei blocchi, i modelli di embedding o i modelli di riordinamento.

# pytest integration for retrieval quality gates
import pytest

MIN_NDCG_5 = 0.70
MIN_HIT_RATE_5 = 0.85

def test_retrieval_quality_meets_threshold():
    metrics = evaluate_pipeline(production_retriever_fn, golden_test_set, k=5)
    assert metrics['ndcg@5'] >= MIN_NDCG_5, (
        f'NDCG@5 {metrics["ndcg@5"]:.3f} below threshold {MIN_NDCG_5}'
    )
    assert metrics['hit_rate@5'] >= MIN_HIT_RATE_5, (
        f'Hit rate {metrics["hit_rate@5"]:.3f} below threshold {MIN_HIT_RATE_5}'
    )

# Run with: pytest tests/test_retrieval.py -v

Visualizzazione delle metriche del recupero

I numeri grezzi sono difficili da interpretare quando si confrontano più esperimenti. Crei una semplice tabella comparativa o un grafico a barre che mostri affiancati NDCG, MRR, hit rate e latenza per le pipeline baseline, solo ibride e ibride con riordinamento. Monitorare queste metriche nel tempo, man mano che apporta miglioramenti, crea uno storico dei miglioramenti del recupero che orienta le future decisioni di ottimizzazione.

def print_comparison_table(results: dict[str, dict]):
    headers = ['Pipeline', 'NDCG@5', 'MRR@5', 'Hit@5', 'P99 ms']
    print('|'.join(f'{h:20}' for h in headers))
    print('-' * (len(headers) * 21))
    for pipeline_name, metrics in results.items():
        row = [
            pipeline_name,
            f'{metrics.get("ndcg@5", 0):.3f}',
            f'{metrics.get("mrr@5", 0):.3f}',
            f'{metrics.get("hit_rate@5", 0):.3f}',
            f'{metrics.get("p99_latency_ms", 0):.0f}',
        ]
        print('|'.join(f'{v:20}' for v in row))

results = {
    'Dense only': {'ndcg@5': 0.64, 'mrr@5': 0.68, 'hit_rate@5': 0.78, 'p99_latency_ms': 35},
    'Hybrid RRF': {'ndcg@5': 0.71, 'mrr@5': 0.74, 'hit_rate@5': 0.84, 'p99_latency_ms': 55},
    'Hybrid + Rerank': {'ndcg@5': 0.77, 'mrr@5': 0.81, 'hit_rate@5': 0.89, 'p99_latency_ms': 287},
}
print_comparison_table(results)

Agire sui risultati del benchmark

Dopo aver eseguito i benchmark, utilizzi i risultati per prendere decisioni concrete. Se il riordinamento migliora l'NDCG di meno di 0.03, lo eviti e si concentri sul miglioramento del primo stadio. Se l'hit rate è basso, il primo stadio non sta recuperando documenti rilevanti: aumenti la dimensione dell'insieme dei candidati oppure passi al recupero ibrido. Se la qualità delle risposte end-to-end migliora significativamente nonostante guadagni modesti nel recupero, il riordinatore potrebbe portare in cima frasi altamente rilevanti che l'LLM utilizza efficacemente, anche se la posizione nell'ordinamento non cambia.

Verifica rapida

Verifichi la sua comprensione della misurazione dell'impatto del recupero e del riordinamento trattata in questa lezione.

Riepilogo della lezione

In questa lezione ha imparato che creare un set di test di riferimento con documenti rilevanti noti è essenziale prima di misurare la qualità del recupero, che NDCG, MRR e hit rate sono le tre metriche fondamentali del recupero e, insieme, misurano in modo completo la qualità dell'ordinamento e che la qualità delle risposte end-to-end valutata da un LLM costituisce la misura definitiva del miglioramento della pipeline. Esegua sempre i benchmark del recupero come test di regressione nella CI. Ora esploreremo lo streaming degli LLM per visualizzare i token man mano che vengono generati.

Domande Frequenti

La lezione «Misurare l'impatto del re-ranking» è gratuita?

Sì — il testo completo di «Misurare l'impatto del re-ranking» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso AI Engineering Academy, passa a CoddyKit PRO. Il corso AI Engineering Academy include 4 lezioni in totale.

Cosa imparerò in «Misurare l'impatto del re-ranking»?

Esegua un benchmark prima e dopo, confrontando il retrieval a una fase con quello a due fasi e re-ranking, e misurando NDCG, MRR e la qualità delle risposte end-to-end. Eserciti AI Engineering Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare AI Engineering Academy?

Non è richiesta alcuna esperienza precedente. AI Engineering Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «Misurare l'impatto del re-ranking»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione AI Engineering Academy?

Sì. Ogni lezione AI Engineering Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Perché il retrieval a due fasi funziona
  2. Riordinamento con cross-encoder: Cohere e BGE
  3. Compressione contestuale e filtro della rilevanza
  4. Misurare l'impatto del re-ranking
← Torna a AI Engineering Academy