Skip to content

Przewodniki

Ewaluacja RAG

Angielska wersja tej strony zmieniła się od czasu tłumaczenia. Aktualna jest strona angielska. Przeczytaj po angielsku

Odpowiedź wspomagana wyszukiwaniem może być błędna z czterech różnych powodów: właściwy fragment nigdy nie został wyszukany, został wyszukany, ale umieszczony w rankingu zbyt nisko, znalazł się wystarczająco wysoko, a potem wypadł z kontekstu, albo dotarł do modelu, a model i tak się pomylił. Pojedyncza liczba dokładności nie potrafi ich rozróżnić. Oloproof uruchamia system RAG jako dwa widoczne dla siebie etapy, mierzy każdy z nich i ponownie wykonuje nieudane przypadki przy kontrolowanych zmianach, aby ustalić, który powód ma zastosowanie.

examples/support_rag/ to projekt, który uruchamia ta strona. Nie wymaga poświadczeń żadnego dostawcy.

System etapowy

System to klasa z etapem wyszukiwania i etapem generowania, opatrzona dekoratorem @rag_system:

from oloproof import Passage, Retrieval, rag_system


@rag_system(
    name="support-rag",
    version="slice-b-example",
    depth=6,
    top_k=2,
    token_budget=40,
    index_version="kb-2026-09-16",
)
class SupportRag:
    def retrieve(self, input, depth):
        ...
        return Retrieval(query=input["question"], depth=depth, candidates=tuple(passages))

    def generate(self, input, context):
        ...
        return {"answer": answer, "citations": [best.doc_id]}

    def count_tokens(self, passage):
        return len((passage.text or "").split())

retrieve(input, depth) zwraca do depth kandydatów, jako Passage(doc_id=..., score=..., text=...), w kolejności, w jakiej wygenerował je Twój mechanizm wyszukiwania. Oloproof zapisuje pozycje i nigdy nie zmienia rankingu. Następnie zachowuje pierwsze top_k, odrzuca fragmenty przekraczające token_budget i przekazuje resztę do generate(input, context). count_tokens(passage) jest potrzebne tylko przy token_budget; Oloproof nigdy nie szacuje tokenów.

oloproof.yaml wskazuje na klasę i może nadpisać dowolne z jej ustawień:

system:
  name: support-rag
  version: slice-b-example
  rag:
    object: app:SupportRag
    depth: 6
    top_k: 2
    token_budget: 40
    index_version: kb-2026-09-16

index_version jest częścią tożsamości wyszukiwania. Zmień go, gdy zmienia się indeks, w przeciwnym razie zbuforowane wyniki wyszukiwania zostaną ponownie użyte względem indeksu, który już ich nie zwraca.

Co deklaruje przypadek

Przypadek RAG zawiera pod expected dwa pola, których nie potrzebuje żaden inny rodzaj przypadku:

{"id":"refund_annual","input":{"question":"How long do refunds take for annual plans?"},"expected":{"answer":"14 days","relevant":[{"doc_id":"kb-01"}],"gold_context":[{"doc_id":"kb-01","text":"Refunds for annual plans are issued within 14 days of an approved request. Support reviews each request on the same business day."}]},"metadata":{"topic":"billing"}}
  • expected.relevant wymienia dokumenty, które odpowiadają na pytanie. Czytają je metryki

wyszukiwania, a przypadek bez tego pola jest z nich wykluczany z no_relevance_labels.

  • expected.gold_context to sam tekst fragmentu. Diagnoza podstawia go w miejsce wyszukanego

kontekstu, a nieudanego przypadku bez niego nie da się zdiagnozować.

Ewaluatory

evaluators:
  - {type: contains, criterion: answer_correct, field: answer, expected_field: answer}
  - {type: hit_rate, k: 2}
  - {type: recall, k: 2}
  - {type: ndcg, k: 6}
  - {type: citation_validity}
slices: [metadata.topic, relevant_position, context_truncated]
min_slice_support: 4

hit_rate, recall, mrr i ndcg przyjmują k i na jego podstawie nazywają własne kryterium: hit_rate_at_2. Wpis w expected.relevant może też zawierać chunk_id oraz grade, którego wartość domyślna to 1; relevance_unit: chunk liczy wtedy każdy fragment jako osobną jednostkę zamiast całych dokumentów. citation_validity sprawdza, czy każdy identyfikator cytowany w odpowiedzi wskazuje fragment w kontekście, który otrzymała, a przy require_citations: true odpowiedź, która niczego nie cytuje, kończy się niepowodzeniem. groundedness_judge i citation_support_judge to sędziowie LLM, którzy czytają złożony kontekst i przyjmują provider oraz model jak każdy inny sędzia.

oloproof run

Trzy wiersze tabeli metryk:

│ answer_correct  │ 69.2%    │ [38.5%, 91.0%]  │ 9 / 13 observed · 0 missing · 0 excluded     │
│ ndcg_at_6       │ 0.866    │ [0.506, 0.990]  │ mean of 13 observed · 0 missing · 0 excluded │
│ citations_valid │ 100.0%   │ [75.2%, 100.0%] │ 13 / 13 observed · 0 missing · 0 excluded    │

Pomiędzy nimi zarówno hit_rate_at_2, jak i recall_at_2 wskazują 92.3%, 12 z 13 obserwowanych, z dolną granicą 63.9%: odpowiedni fragment dla jednego pytania nigdy nie został wyszukany.

Cache: execution 0 hit/13 miss; judgment 0 hit/65 miss
Stages: retrieve 0 hit/13 miss; generate 0 hit/13 miss

Wiersz Stages to własna pamięć podręczna systemu etapowego. Wyszukiwanie i generowanie są buforowane osobno, więc zmiana w generowaniu nigdy nie uruchamia ponownie wyszukiwania.

Ustalanie przyczyny

Cztery pytania zakończyły się niepowodzeniem. diagnose wykonuje je ponownie ze złotym fragmentem w miejsce wyszukanego kontekstu, obok próby kontrolnej, która wykonuje je ponownie bez zmian:

oloproof diagnose RUN_ID --intervention gold-context --criterion answer_correct
Selected: 4 failed cases with gold context (observed; no population claim)
Control: 0 of 4 passed when re-executed without the intervention
Recovered under gold context: 3 of 4
RETRIEVAL_MISS: 1 of 4, recovered; no relevant evidence was retrieved
CONTEXT_ASSEMBLY_LOSS: 2 of 4, recovered; relevant evidence within top-k was left out of the context
GENERATION_FAILURE: 1 of 4, still failed with the gold context
Implicated: context budget, in 2 of the 3 recovered failures.
Candidate experiment: a larger token budget. This is a hypothesis to test, not an established cause.
Candidate experiment: smaller chunks. This is a hypothesis to test, not an established cause.
Diagnosis sha256:b2846cbe04099225bda4bf21beb1738f54d6cc0e9a7ce210bb3eb467619cbd69
Child runs: gold context run_01M3C3REAAZDF9FD8N2C8BG17P, control run_01M3C3REAFVXK2VM4MYAQYH6KE
Cases: oloproof inspect sha256:b2846cbe04099225bda4bf21beb1738f54d6cc0e9a7ce210bb3eb467619cbd69

Przypadek, który przechodzi ze złotym fragmentem i nie przechodzi bez niego, zawiódł przed modelem. Przypadek, który nie przechodzi, mając złoty fragment, obciąża model. To próba kontrolna sprawia, że taka interpretacja jest bezpieczna: przypadek, który odzyskuje się przy zwykłym ponownym uruchomieniu, był niestabilny, a nie zdiagnozowany.

Identyfikator diagnozy wymienia przypadek stojący za każdą liczbą:

oloproof inspect DIAGNOSIS_ID
money_back: RETRIEVAL_MISS, relevant_not_retrieved, strength intervention_recovery, best relevant position none
refund_review: CONTEXT_ASSEMBLY_LOSS, relevant_dropped_from_context, strength intervention_recovery, best relevant position 2
seat_count: GENERATION_FAILURE, fails_with_gold_context, strength intervention_non_recovery, best relevant position 1
security_review: CONTEXT_ASSEMBLY_LOSS, relevant_dropped_from_context, strength intervention_recovery, best relevant position 2

Wskazuje czynnik, nigdy przyczynę. „Implicated” i „candidate experiment” to najmocniejsze słowa, jakich używa, ponieważ cztery przypadki odzyskane pod jedną interwencją nie ustalają, dlaczego zawiodły.

Testowanie poprawki przed jej wprowadzeniem

Dwie inne interwencje odtwarzają zapisane wyszukiwanie z innym ustawieniem, więc nie jest wykonywane żadne wywołanie mechanizmu wyszukiwania. top-k poszerza odcięcie:

oloproof diagnose RUN_ID --intervention top-k --top-k 4 --criterion answer_correct
Selected: 4 failed cases with gold context (observed; no population claim)
Control: 0 of 4 passed when re-executed without the intervention
Recovered under top-k 4: 0 of 4
Confirmed under top-k 4: 0 of 0 RANKED_OUT cases also recovered
Labels from gold context (diagnosis sha256:b2846cbe04099225bda4bf21beb1738f54d6cc0e9a7ce210bb3eb467619cbd69): 3 of 4 recovered
RETRIEVAL_MISS: 1 of 4, recovered; no relevant evidence was retrieved
CONTEXT_ASSEMBLY_LOSS: 2 of 4, recovered; relevant evidence within top-k was left out of the context
GENERATION_FAILURE: 1 of 4, still failed with the gold context
Diagnosis sha256:668084c3e99df84f7b63f138792aa96f48e5cb8251fee3acae8e1cc0500ba085
Child runs: gold context run_01M3C3REAAZDF9FD8N2C8BG17P, control run_01M3C3REAFVXK2VM4MYAQYH6KE, top-k 4 run_01M3C3RKHTGGV37079V11JJ78M, replay control run_01M3C3RKJ076K7MSVQ94J4ZE2P
Cases: oloproof inspect sha256:668084c3e99df84f7b63f138792aa96f48e5cb8251fee3acae8e1cc0500ba085

Nic się nie odzyskało, co przewidziały etykiety: żadne niepowodzenie tutaj nie było fragmentem umieszczonym tuż poniżej odcięcia. Odtworzenie przenosi etykiety ze złotego kontekstu, więc obie diagnozy czyta się razem. reranker przyjmuje --reranker z module:function i zamiast tego odtwarza wyszukiwanie przez Twój reranker.

Przeprowadzanie eksperymentu

Diagnoza wskazała większy budżet tokenów. Zwiększ token_budget do 120 i uruchom ponownie:

Cache: execution 0 hit/13 miss; judgment 0 hit/65 miss
Stages: retrieve 13 hit/0 miss; generate 7 hit/6 miss

Każde wyszukiwanie zostało użyte ponownie, ponieważ top_k i budżet tokenów leżą poza tożsamością wyszukiwania; ponownie wygenerowano tylko sześć przypadków, których kontekst się zmienił. Następnie porównaj, z polityką porównania z przykładu:

oloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy compare.yaml
Comparison sha256:d801ed897f1fa1b196ca1e3f73a1ef4ffe6845d6ee8bddaea8a44da94d27a75b of run_01M3C3RYJZ4PAJ8P4P9NT71360 against run_01M3C3R5Y9D18WGSZQFA7N4XRT · 13 paired cases
answer_correct: +0.0 points [-33.6, +33.6] · 13 paired · 0 missing · 0 excluded
hit_rate_at_2: +0.0 points [-33.6, +33.6] · 13 paired · 0 missing · 0 excluded
recall_at_2: +0.0 points [-33.6, +33.6] · 13 paired · 0 missing · 0 excluded
ndcg_at_6: +0.0 points [-33.6, +33.6] · 13 paired · 0 missing · 0 excluded
citations_valid: +0.0 points [-33.6, +33.6] · 13 paired · 0 missing · 0 excluded

Dla każdego wycinka i metryki następuje jeden wiersz eksploracyjny, a potem decyzje:

Decisions
  answers-not-worse  answer_correct  non-inferiority, margin 5.0 points  INSUFFICIENT_EVIDENCE  interval_overlaps_margin
  citations-not-worse  citations_valid  non-inferiority, margin 2.0 points  INSUFFICIENT_EVIDENCE  interval_overlaps_margin
Gate: BLOCK (exit 3)

Eksperyment nie pomógł: żaden z trzynastu nie zmienił werdyktu. A trzynaście sparowanych przypadków nie mogło wykazać zmiany o jakiejkolwiek wielkości istotnej dla wydania, co jest drugą rzeczą, którą mówi przedział.

Co dalej

krok.

  • Sędziowie omawia, co sędzia ugruntowania musi spełnić, zanim będzie mógł

bramkować.