Podręcznik uczestnika z objaśnieniami, przykładami i ćwiczeniami do samodzielnej nauki do Modułu 6
4. R3. Ranking i metryki wyszukiwania
4.1. Zapis pełnego rankingu i wykonanie R3
ENHANCER+ · Moduł 6 · Ewaluacja RAG · Podrozdział
Wynik jest użytecznym dowodem, gdy zachowuje dane pozwalające odtworzyć ocenę. Lista samych nazw źródeł nie pokazuje kolejności, score ani fragmentów odrzuconych przez filtr. Zapisuj więc ranking przed progiem i kontekst po jego zastosowaniu.
Cztery identyfikatory
test_id identyfikuje pytanie lub scenariusz, turn_id turę, run_id wykonanie serii, a result_id konkretny wynik. Dwa wykonania tego samego testu mają wspólny test_id, lecz inne result_id. contract_hash identyfikuje treść kontraktu danej tury, dzięki czemu zmiana oczekiwań nie może zostać niezauważona podczas łączenia ocen.
Wiersz retrieval_runs.jsonl zawiera pełny tekst i metadane wyników. Zajmuje więcej miejsca, ale nie wymaga zgadywania, jaki fragment miał model. deepcopy chroni zapis w pamięci przed późniejszą modyfikacją listy rankingu. Nie chroni pliku przed ręczną edycją, dlatego surowe wyniki zachowuj bez zmian.
R3 · Do pliku kod/moj_m6.py · zastąp całą definicję
def build_retrieval_record(test_case, ranking, context, config, run_id,
*, origin='isolated_retrieval', question=None):
expected = {
cid for g in test_case['expected_sources']
for cid in g['required_chunk_ids'] + g.get('alternative_chunk_ids', [])
}
rank = next((i for i, r in enumerate(ranking, 1)
if r['chunk_id'] in expected), None)
return {
'schema_version': 'm6.1', 'result_id': uuid4().hex,
'run_id': run_id, 'created_at': datetime.now(timezone.utc).isoformat(),
'test_id': test_case['test_id'], 'turn_id': test_case['turn_id'],
'test_set_version': test_case['test_set_version'],
'contract_hash': fingerprint(test_case),
'origin': origin, 'mode': config['mode'], 'config': deepcopy(config),
'search_question': question or prepare_search_question(test_case),
'ranking': deepcopy(ranking), 'context': deepcopy(context),
'metrics': source_metrics(test_case, ranking, context),
'hit_at_1': hit_at_k(test_case, ranking, 1, config['top_k']),
'hit_at_k': hit_at_k(test_case, ranking, config['top_k'], config['top_k']),
'metric_k': config['top_k'], 'expected_rank': rank,
'metric_reason': None if expected else 'no_expected_chunk',
'status': 'completed',
}
Funkcja zachowuje schemat pakietu i dopisuje hit_at_1, hit_at_k, metric_k, expected_rank oraz przyczynę nieoceniania metryki. Nazwy metrics.ranking.any_group i all_groups odpowiadają znaczeniu retrieval_any_hit i retrieval_all_hit na slajdach. To jawne mapowanie schematu, nie dwie różne miary.
Próg i filtr struktury
Filtr score odrzuca wyniki poniżej progu. Wartość None wyłącza ten filtr, ale nie wyłącza sprawdzania pustego tekstu, metadanych i powtórzonych fragmentów. prepare_context_results nadal wybiera użyteczne strukturalnie rekordy. Oddziel brak wyników (no_results), odrzucenie wszystkich przez próg (below_threshold) i brak rekordów użytecznych strukturalnie (no_usable_results).
R3 · Do pliku kod/moj_m6.py · zastąp całą definicję
def evaluate_retrieval_turn(test_case, config, run_id):
check_config(config)
effective = dict(config, **test_case.get('config_overrides', {}))
question = prepare_search_question(test_case)
if question is None:
return None
try:
ranking = rag_backend.retrieve(question, top_k=effective['top_k'])
context, reason = rag_backend.select_context_results(
ranking, effective['similarity_threshold'])
record = build_retrieval_record(test_case, ranking, context, effective, run_id)
record['context_reason'] = reason
if test_case['test_id'] == 'M6-T106' and any(r['score'] >= 1 for r in ranking):
record.update(status='precondition_failed', error='T106 wymaga score < 1.')
return record
except Exception as exc:
record = build_retrieval_record(test_case, [], [], effective, run_id)
record.update(status='execution_error', error=str(exc), metrics=None,
hit_at_1=None, hit_at_k=None, expected_rank=None,
metric_reason='execution_error')
return record
Wyjątek techniczny tworzy rekord execution_error, a metryki stają się nieoceniane. Gdyby pozostawić puste listy i zwykłe zero Hit@k, uszkodzony checkpoint wyglądałby jak poprawnie wykonane, lecz nietrafne wyszukiwanie. Zapis precondition_failed w T106 sygnalizuje inną sytuację: nie zaszło założenie wymagane do tej kontrolowanej próby.
Uruchomienie serii i odczyt wyniku
Gotowa pętla run_retrieval z dodatku nadaje jeden run_id serii, wywołuje Twoje evaluate_retrieval_turn i natychmiast dopisuje rekordy. Tury z retrieval_question=None pomija. Poniższy kod uruchamia sprawdzony podzbiór offline.
Notebook warsztatu · przykład wywołania
ids = (ref.read_json(ROOT / 'dane/przypadki/checkpoint_subset.json')
if MODE == 'checkpoint' else None)
retrieval_results = w.run_retrieval(cases, config, E, test_ids=ids)
for row in retrieval_results:
print(row['test_id'], row['turn_id'], row['status'],
row['hit_at_1'], row['hit_at_k'], row['metrics'])
ref.save_json(E / 'R3_selected_result_ids.json',
[r['result_id'] for r in retrieval_results])
Nie uruchamiaj całego zestawu z założeniem, że każdy tekst ma checkpoint. Gdy tworzysz własne pytania, wybierz świadomie Ollama i rozpocznij osobną serię. Zachowaj listę planowanych przypadków, wykonanych rekordów, pominiętych tur oraz błędów technicznych.
Rzeczywisty przykład T004
Pytanie o nieudane uruchomienie wymaga fragmentu DOC-INSTR-dd6055d675-0003. W dostarczonym pilocie R3 przy top_k=3 pojawiają się fragment restartu, testu po zmianie oraz kontroli znaków. Brakuje procedury przywrócenia kopii. Mimo podobieństwa tematycznego pokrycie wymaganej grupy wynosi 0. Przy top_k=5 grupa pojawia się w zapisanym rankingu i kontekście.
Ten wynik pochodzi z odtworzenia danych dostarczonego indeksu. Nie przenoś go na T101 tylko dlatego, że oba pytania wspominają niepowodzenie. Nie dowodzi również, że wygenerowana odpowiedź po zmianie top_k będzie kompletna. To osobna próba R4.
Kontrola R3: potrafisz otworzyć jeden wiersz JSONL i wskazać konkretne wejście, ranking, filtr, kontekst, konfigurację i kontrakt. Liczby wynikają z tych danych, a nie z opisu słownego eksperymentu.
Lokalne chatboty, agenci i systemy RAG z własną bazą wiedzy · Moduł 6 · Wydanie 29.09.2026