AI Engineering Academy · Lekcja

Dlaczego ewaluacja ma znaczenie w RAG

Uczestnicy poznają dwa niezależne tryby błędów w systemach RAG: błąd pobierania i błąd generowania, oraz dowiedzą się, dlaczego do diagnozowania każdego z nich potrzebne są osobne metryki.

Lekcja 1 z 413 kroki

Dlaczego ewaluacja ma znaczenie w RAG to bezpłatna lekcja AI Engineering Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Engineering Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Engineering Academy zawiera 4 lekcji w sumie.

Nie można poprawić tego, czego się nie mierzy

System RAG może sprawiać wrażenie działającego, ponieważ zwraca płynne odpowiedzi brzmiące wiarygodnie. Jednak bez pomiarów nie wiadomo, czy rzeczywiście pobiera właściwe fragmenty ani czy generuje wierne odpowiedzi. Zespoły pomijające ewaluację często przez wiele miesięcy zmieniają strategie dzielenia tekstu i formaty promptów na podstawie intuicji, aby dopiero później odkryć, że pogorszyły sytuację. Rygorystyczna ewaluacja zmienia rozwój RAG z zgadywania w inżynierię.

Dwa niezależne tryby awarii

RAG ma dwa odrębne etapy, które mogą zawodzić niezależnie: wyszukiwanie i generowanie. Wyszukiwanie zawodzi, gdy istotne fragmenty nie trafiają do wyników Top-K — LLM nie może wygenerować dobrej odpowiedzi, jeśli właściwe informacje nigdy nie zostały pobrane. Generowanie zawodzi, gdy poprawne fragmenty zostały pobrane, ale LLM je zignorował, błędnie odczytał lub dodał zmyślone informacje. Do wskazania komponentu powodującego problem potrzebne są osobne metryki dla każdego etapu.

Niebezpieczeństwo wyłącznie kompleksowej ewaluacji

Mierzenie wyłącznie jakości końcowej odpowiedzi ukrywa źródło błędów. Załóżmy, że system udziela błędnych odpowiedzi w 30% przypadków. Czy dzieje się tak dlatego, że wyszukiwanie nie znajduje właściwych fragmentów, czy dlatego, że LLM ignoruje dobre fragmenty? Jeśli znany jest tylko końcowy współczynnik błędów, nie można stwierdzić, który komponent należy naprawić. Instrumentuj oba etapy niezależnie: mierz jakość wyszukiwania za pomocą zbiorów danych wzorcowych, a jakość generowania za pomocą wyników wierności.

# Diagnosis example: which stage is failing?

# Test 1: Is retrieval finding the right chunks?
retrieval_hit_rate = evaluate_retrieval(questions, ground_truth_chunks)
print(f'Retrieval hit rate@5: {retrieval_hit_rate:.1%}')
# If this is low (< 80%), fix chunking and embedding first

# Test 2: Given perfect context, does LLM generate correct answers?
generation_faithfulness = evaluate_generation(questions, perfect_context)
print(f'Generation faithfulness: {generation_faithfulness:.1%}')
# If retrieval is fine but this is low, fix your prompts

Budowanie zbioru danych wzorcowych

Ewaluacja wymaga zbioru danych wzorcowych: zestawu par pytanie–odpowiedź, dla których znana jest poprawna odpowiedź, a najlepiej również dokument i fragment, z którego ta odpowiedź pochodzi. W minimalnym użytecznym zbiorze ewaluacyjnym należy zgromadzić 50–100 pytań reprezentatywnych dla rzeczywistych zapytań użytkowników. Odpowiedzi przygotuj ręcznie lub na podstawie lektury dokumentów źródłowych. Uwzględnij różne typy pytań: wyszukiwanie faktów, porównania, wnioskowanie wieloetapowe oraz pytania spoza dziedziny, na które system powinien odmówić odpowiedzi.

# Golden dataset format
golden_dataset = [
    {
        'question': 'How many vacation days do employees receive in their first year?',
        'answer': '15 days',
        'relevant_chunks': ['employee_handbook_p24', 'benefits_summary_p3'],
        'source_doc': 'employee_handbook_2025.pdf'
    },
    {
        'question': 'What is the parental leave duration for primary caregivers?',
        'answer': '16 weeks fully paid',
        'relevant_chunks': ['parental_leave_policy_p1'],
        'source_doc': 'parental_leave_policy.pdf'
    }
]

Generowanie złotych zbiorów danych za pomocą LLM

Ręczne tworzenie 100 pytań jest żmudne. Można przyspieszyć ten proces za pomocą LLM do generowania danych: należy przekazać każdy fragment dokumentu do GPT-4o i poprosić o wygenerowanie 3–5 różnorodnych pytań, na które można znaleźć odpowiedzi w tym fragmencie, a także o podanie oczekiwanego tekstu odpowiedzi. Warto ręcznie sprawdzić próbkę, aby wykryć problemy z jakością. To podejście pozwala szybko skalować proces do tysięcy pytań, choć może pomijać przypadki brzegowe, o które zapytaliby wyłącznie prawdziwi użytkownicy.

def generate_qa_pairs_for_chunk(chunk_text, llm_client):
    prompt = (
        'Given the following document excerpt, generate 3 diverse questions '
        'that can be answered using ONLY this text. '
        'For each question, provide the exact answer from the text.\n\n'
        f'Text:\n{chunk_text}\n\n'
        'Format each as JSON: {"question": ..., "answer": ...}'
    )
    response = llm_client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}]
    )
    return response.choices[0].message.content

Ocena wyszukiwania: współczynnik trafień

Współczynnik trafień@K to odsetek pytań, dla których co najmniej jeden powiązany fragment pojawia się wśród K najważniejszych wyników wyszukiwania. Jest to najprostsza i najbardziej intuicyjna metryka wyszukiwania. Współczynnik trafień@5 równy 85% oznacza, że w przypadku 85 ze 100 pytań powiązany fragment znalazł się wśród 5 najważniejszych wyników. Należy śledzić współczynnik trafień osobno dla różnych typów dokumentów, długości zapytań i kategorii tematycznych, aby ustalić, z którymi przypadkami mechanizm wyszukiwania radzi sobie najsłabiej.

def compute_hit_rate(golden_dataset, retriever, top_k=5):
    hits = 0
    for item in golden_dataset:
        results = retriever.retrieve(item['question'], top_k=top_k)
        retrieved_ids = {r['id'] for r in results}
        relevant_ids = set(item['relevant_chunks'])
        if retrieved_ids & relevant_ids:  # intersection not empty
            hits += 1
    hit_rate = hits / len(golden_dataset)
    print(f'Hit rate@{top_k}: {hit_rate:.1%} ({hits}/{len(golden_dataset)})')
    return hit_rate

Ocena generowania: wierność

Wierność mierzy, czy wygenerowana odpowiedź zawiera wyłącznie informacje, które można zweryfikować w wyszukanym kontekście. Niewierna odpowiedź dodaje fakty, których kontekst nie potwierdza — jest to halucynacja. Wierność można ocenić, prosząc LLM pełniący rolę sędziego (lub człowieka oceniającego) o sprawdzenie każdego zdania odpowiedzi względem kontekstu i oznaczenie twierdzeń, których nie potwierdzają wyszukane fragmenty. Docelowy poziom wierności dla systemów produkcyjnych to co najmniej 95%.

def evaluate_faithfulness(answer, context, llm_client):
    prompt = (
        'Given this context and answer, evaluate faithfulness.\n\n'
        f'Context: {context}\n\n'
        f'Answer: {answer}\n\n'
        'For each sentence in the answer, determine if it is '
        'supported by the context (FAITHFUL) or not (HALLUCINATED). '
        'Return a JSON: {"score": 0.0-1.0, "issues": ["sentence..."]}.'
    )
    response = llm_client.chat.completions.create(
        model='gpt-4o',
        messages=[{'role': 'user', 'content': prompt}]
    )
    return response.choices[0].message.content

Ocena generowania: trafność odpowiedzi

Trafność odpowiedzi mierzy, czy wygenerowana odpowiedź rzeczywiście odnosi się do pytania użytkownika. Odpowiedź o wysokiej wierności może nadal mijać się z tematem, odpowiadając na pytanie powiązane, ale inne. Trafność należy mierzyć niezależnie od wierności. Można użyć LLM pełniącego rolę sędziego do oceny, czy odpowiedź bezpośrednio odnosi się do pytania, w skali od 1 do 5. Niska trafność odpowiedzi często wskazuje na problem ze strukturą promptu albo na to, że wyszukany kontekst nie zawiera faktycznej odpowiedzi.

def evaluate_answer_relevance(question, answer, llm_client):
    prompt = (
        f'Question: {question}\n\n'
        f'Answer: {answer}\n\n'
        'Rate how well this answer addresses the question on a 1-5 scale:\n'
        '5 = fully answers the question\n'
        '3 = partially answers but misses key aspects\n'
        '1 = does not address the question at all\n\n'
        'Return JSON: {"score": 1-5, "reason": "brief explanation"}'
    )
    response = llm_client.chat.completions.create(
        model='gpt-4o',
        messages=[{'role': 'user', 'content': prompt}]
    )
    return response.choices[0].message.content

Śledzenie metryk w czasie

Ocena jest najbardziej wartościowa, gdy śledzą Państwo metryki w czasie, w miarę wprowadzania zmian. Wyniki ocen należy przechowywać w bazie danych lub arkuszu kalkulacyjnym wraz ze znacznikami czasu i etykietami wersji (np. chunk_size=500, embed=3-small, k=5). Po wypróbowaniu nowej strategii dzielenia na fragmenty lub modelu osadzania należy przeprowadzić tę samą ocenę i porównać wyniki. Zapobiega to regresji — mogą Państwo poprawić wierność, ale przypadkowo obniżyć współczynnik trafień. Przed scaleniem zmian z wersją produkcyjną należy zawsze przeprowadzić pełną ocenę.

import json
from datetime import datetime

def save_evaluation_results(metrics, config, output_file='eval_history.jsonl'):
    record = {
        'timestamp': datetime.utcnow().isoformat(),
        'config': config,
        'metrics': metrics
    }
    with open(output_file, 'a') as f:
        f.write(json.dumps(record) + '\n')
    print(f'Saved eval result: hit_rate={metrics["hit_rate"]:.1%}, '
          f'faithfulness={metrics["faithfulness"]:.1%}')

Podejście do oceny

Oprócz konkretnych metryk ocena wymaga zmiany sposobu myślenia: należy traktować RAG jak system uczenia maszynowego o mierzalnej skuteczności, a nie jak chatbota ocenianego subiektywnie na podstawie rozmowy. Kryteria sukcesu należy określić z góry (np. hit rate@5 > 85%, faithfulness > 95%). Należy utworzyć zbiór testowy, który pozostaje zamrożony i nigdy nie jest używany do podejmowania decyzji dotyczących rozwoju. Do iteracji należy przeznaczyć osobny zbiór deweloperski. Ta dyscyplina odróżnia zespoły dostarczające niezawodne systemy RAG od tych, które dostarczają efektowne demonstracje zawodzące na produkcji.

Zbiór testowy a zbiór deweloperski

Kluczową zasadą uczenia maszynowego, mającą zastosowanie również do oceny RAG, jest podział na zbiory treningowy, deweloperski i testowy. Zbiór testowy powinien być całkowicie zamrożony — nigdy nie należy używać go do podejmowania decyzji dotyczących rozwoju. Do eksperymentowania ze strategiami dzielenia na fragmenty, zmianami promptów i modelami osadzania należy używać osobnego zbioru deweloperskiego. Zbiór testowy należy uruchamiać dopiero wtedy, gdy uznają Państwo zmianę za gotową do wdrożenia na produkcji. Taki podział zapobiega nadmiernemu dopasowaniu potoku RAG do zbioru testowego i gwarantuje, że końcowe raportowane metryki odzwierciedlają rzeczywistą zdolność uogólniania.

import json
from sklearn.model_selection import train_test_split

def split_golden_dataset(all_questions, test_ratio=0.3, seed=42):
    dev_set, test_set = train_test_split(
        all_questions,
        test_size=test_ratio,
        random_state=seed
    )
    print(f'Dev set: {len(dev_set)} questions')
    print(f'Test set: {len(test_set)} questions (FROZEN)')
    with open('eval/dev_set.json', 'w') as f:
        json.dump(dev_set, f, indent=2)
    with open('eval/test_set.json', 'w') as f:
        json.dump(test_set, f, indent=2)
    return dev_set, test_set

Szybkie sprawdzenie

Sprawdź swoją wiedzę na temat koncepcji inżynierii AI z tej lekcji.

Podsumowanie lekcji

W tej lekcji poznali Państwo: dwa niezależne tryby awarii wyszukiwania i generowania, które wymagają osobnych metryk, sposób budowania złotego zbioru danych zawierającego trójki pytanie–odpowiedź–fragment do obiektywnej oceny, współczynnik trafień jako podstawową metrykę wyszukiwania oraz wierność i trafność odpowiedzi jako podstawowe metryki generowania, a także znaczenie śledzenia metryk w czasie w celu zapobiegania regresjom. W następnej części zaimplementujemy konkretne metryki wyszukiwania, w tym MRR i NDCG.

Bezpłatny start

Ucz się Python dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
30
Lekcje
120

Często zadawane pytania

Czy lekcja „Dlaczego ewaluacja ma znaczenie w RAG” jest bezpłatna?

Tak — pełny tekst „Dlaczego ewaluacja ma znaczenie w RAG” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Engineering Academy, przejdź na CoddyKit PRO. Kurs AI Engineering Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Dlaczego ewaluacja ma znaczenie w RAG”?

Uczestnicy poznają dwa niezależne tryby błędów w systemach RAG: błąd pobierania i błąd generowania, oraz dowiedzą się, dlaczego do diagnozowania każdego z nich potrzebne są osobne metryki. Ćwiczysz AI Engineering Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć AI Engineering Academy?

Nie wymagamy żadnego doświadczenia. AI Engineering Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.

Ile czasu zajmuje lekcja „Dlaczego ewaluacja ma znaczenie w RAG”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji AI Engineering Academy?

Tak. Każda lekcja AI Engineering Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Dlaczego ewaluacja ma znaczenie w RAG
  2. Metryki pobierania: hit rate, MRR i NDCG
  3. Metryki generowania: wierność i trafność odpowiedzi
  4. Tworzenie automatycznego środowiska ewaluacyjnego
← Powrót do AI Engineering Academy