Przejdź do treści

Przewodniki

Samouczek: ewaluacja aplikacji RAG

Praktyczny przewodnik do uruchomienia dla aplikacji z generowaniem wspomaganym wyszukiwaniem, w dwóch ścieżkach: istniejąca aplikacja jako czarna skrzynka, której wyszukiwanie, kontekst i cytowania zapisujesz z zewnątrz, oraz aplikacja etapowa, którą Oloproof uruchamia etap po etapie, aby oloproof diagnose mógł ponownie wykonać nieudane przypadki przy kontrolowanych zmianach. Obie działają lokalnie, bez poświadczeń dostawcy.

Pojęcia stojące za każdym krokiem (etapy, etykiety trafności, złoty kontekst, cztery etykiety niepowodzeń) są na stronie Ewaluacja RAG; terminy przypadek, ewaluator, metryka, przedział i bramka są w Podstawowych pojęciach. Ta strona to praktyczna droga przez nie.

Która ścieżka jest Twoja

Twoja aplikacjaŚcieżkaCo dostajeszCzego nie dostajesz
Jedno wywołanie na wejściu, jedna odpowiedź na wyjściu (usługa, punkt końcowy HTTP, łańcuch frameworka, którego nie chcesz dzielić)A, czarna skrzynkaMetryki wyszukiwania, sprawdzenia cytowań, sędziów ugruntowania, bramkowanie, porównanieKontrolowane interwencje: diagnose niczego ponownie nie wykonuje
Wyszukiwanie i generowanie, które możesz wywołać osobnoB, etapowaWszystko z A, cache dla każdego etapu oraz diagnose ze złotym kontekstem, top-k i rerankerem obok kontroliInterwencje inne niż te trzy

Jeśli nie masz pewności, zacznij od A. Nie wymaga żadnej zmiany w aplikacji, a późniejsze przejście na B zachowuje zbiór danych, ewaluatory i politykę.

Wymagania wstępne

  • Python 3.11 lub nowszy oraz zainstalowany Oloproof (pip install oloproof).
  • Przykładowe projekty, dostarczane z pakietem: blackbox_rag dla ścieżki A i support_rag dla ścieżki B. Skopiuj jeden do nowego katalogu i pracuj tam:
oloproof init --example blackbox_rag my-rag
cd my-rag

Każde polecenie poniżej uruchamia się z wnętrza skopiowanego katalogu. Przebiegi, oceny i diagnozy są przechowywane tam w .oloproof/.

Ścieżka A: istniejąca aplikacja jako czarna skrzynka

Pliki

PlikCzym jest
app.pysupport_api(question), zastępujące Twoją aplikację, oraz run(case), adapter
server.pyTa sama aplikacja przez HTTP, dla wariantu HTTP poniżej
data/corpus.jsonlBaza wiedzy z 14 fragmentów, którą przeszukuje aplikacja
data/support.jsonl15 przypadków: 13 z etykietami trafności i złotymi fragmentami, 2 bez żadnego z nich
oloproof.yamlZestaw: zbiór danych, system, ewaluatory, wycinki
oloproof.http.yamlTen sam zestaw względem serwera HTTP
release.yamlPolityka wydań dla pojedynczego przebiegu
compare.yamlPolityka porównywania przebiegu kandydata z punktem odniesienia

Co zwraca aplikacja

support_api zachowuje się jak aplikacja, którą już masz: wyszukuje, buduje prompt z najlepszych źródeł mieszczących się w budżecie słów, odpowiada i cytuje. Jej odpowiedź już niesie to, co zrobiła:

{
  "answer": "Team plans include five seats.",
  "cited": ["kb-03"],
  "sources": [{"id": "kb-03", "score": 3.0, "text": "Team plans include five seats. ..."}],
  "prompt_sources": [{"id": "kb-03", "score": 3.0, "text": "...", "rank": 1, "tokens": 17}],
  "skipped": [{"id": "kb-05", "rank": 3, "why": "top_k"}]
}

Nazwy pól w Twojej aplikacji będą inne. Liczy się to, że potrafi podać, dla każdego pytania, uszeregowane źródła, które wyszukała, te, które dotarły do modelu, i te, które zacytowała. Jeśli nie potrafi, najpierw dodaj je do jej odpowiedzi lub logów: Oloproof mierzy to, co zapisane, i nigdy nie wnioskuje wyszukiwania z odpowiedzi.

Adapter

run wywołuje aplikację bez zmian i odwzorowuje odpowiedź na trzy typowane artefakty, rekordy czytane przez ewaluatory wyszukiwania i cytowań:

@system(
    name="support-rag-blackbox",
    version="tutorial",
    records=("retrieval/v1", "context/v1", "citations/v1"),
)
def run(case):
    response = support_api(str(case["question"]))
    recorder = current_case()
    recorder.retrieval(
        Retrieval(
            query=case["question"],
            depth=SEARCH_DEPTH,
            candidates=tuple(
                Passage(doc_id=s["id"], score=s["score"], text=s["text"])
                for s in response["sources"]
            ),
        )
    )
    recorder.context(
        Context(
            items=tuple(
                ContextItem(doc_id=i["id"], position=i["rank"], tokens=i["tokens"], text=i["text"])
                for i in response["prompt_sources"]
            ),
            dropped=tuple(
                DroppedItem(doc_id=i["id"], position=i["rank"], reason=i["why"])
                for i in response["skipped"]
            ),
            token_budget=PROMPT_WORD_BUDGET,
        )
    )
    recorder.citations(response["cited"])
    return {"answer": response["answer"], "citations": response["cited"]}
ArtefaktKształtCzytany przez
retrieval/v1query, depth oraz candidates w kolejności zwróconej przez Twój retriever, każdy jako Passage(doc_id, chunk_id, score, text)hit_rate, recall, mrr, ndcg
context/v1items, które dotarły do modelu (doc_id, position, tokens, text), elementy dropped z reason równym top_k lub token_budget, oraz token_budgetcitation_validity, groundedness_judge, citation_support_judge
citations/v1ids, każdy jako doc_id lub doc_id#chunk_idcitation_validity, citation_support_judge

Oloproof zapisuje pozycje tak, jak je podano, i nigdy nie zmienia kolejności. Błędnie zbudowany artefakt zatrzymuje przebieg z kodem wyjścia 2, zamiast zostać zapisanym. case to obiekt input przypadku, więc case["question"] to pytanie ze zbioru danych.

Aby użyć własnej aplikacji, zastąp treść support_api wywołaniem jej (wywołaniem SDK, żądaniem HTTP) i zachowaj run. Skieruj na nią system.callable w oloproof.yaml jako module:function.

Wariant HTTP

System HTTP nie może wywołać rejestratora, więc zamiast tego dowody niesie jego odpowiedź, już w trzech powyższych kształtach, a konfiguracja wskazuje, gdzie:

system:
  name: support-rag-http
  version: tutorial
  http:
    url: http://127.0.0.1:8766/answer
    output_path: result
    artifacts:
      retrieval/v1: evidence.retrieval
      context/v1: evidence.context
      citations/v1: evidence.citations

server.py serwuje dokładnie to. Uruchom go, a potem uruchom zestaw względem niego:

python server.py 8766
oloproof run --config oloproof.http.yaml

Wejście przypadku jest wysyłane jako treść JSON. output_path wybiera wynik z odpowiedzi, a każdy wpis artifacts zapisuje ścieżkę z kropkami jako ten rodzaj; brakujące lub błędnie zbudowane pole zatrzymuje przebieg z kodem wyjścia 2. Wyniki są identyczne jak w ścieżce z funkcją wywoływalną poniżej. W Twojej własnej usłudze obiekt dowodów to zwykle pole diagnostyczne, które włączasz dla ruchu ewaluacyjnego.

Co deklaruje przypadek

{"id":"seat_count","input":{"question":"How many seats does a team plan include?"},"expected":{"answer":"5 seats","relevant":[{"doc_id":"kb-03"}],"gold_context":[{"doc_id":"kb-03","text":"Team plans include five seats. ..."}]},"metadata":{"topic":"billing"}}
{"id":"office_hours","input":{"question":"What are the support office hours?"},"expected":{"answer":"09:00"},"metadata":{"topic":"account"}}
  • expected.relevant wymienia fragmenty, które odpowiadają na pytanie. Czytają je metryki wyszukiwania. Przypadek bez niego, jak office_hours, jest z nich wykluczany z no_relevance_labels: opuszcza mianownik, zamiast liczyć się jako zaliczenie lub niepowodzenie.
  • expected.gold_context to sam tekst fragmentu. Ścieżka A nigdy go nie używa; ścieżka B podstawia go w miejsce wyszukanego kontekstu podczas diagnozy.

Przypadki bez etykiet są w praktyce normalne, bo etykietowanie trafności wymaga pracy. Nadal liczą się w sprawdzeniach odpowiedzi i cytowań.

Wybór ewaluatorów

evaluators:
  - {type: contains, criterion: answer_correct, field: answer, expected_field: answer}
  - {type: hit_rate, k: 2}
  - {type: recall, k: 2}
  - {type: citation_validity, require_citations: true}
slices: [metadata.topic]
min_slice_support: 4
  • contains sprawdza, czy odpowiedź zawiera oczekiwany tekst. To sprawdzenie zadania: czy użytkownik dostał właściwą odpowiedź. Gdy sformułowania się różnią, użyj zamiast tego dokładnego dopasowania lub sędziego z rubryką.
  • hit_rate i recall przy k: 2 mierzą wyszukiwanie na głębokości, którą aplikacja faktycznie umieszcza w prompcie. Metryka wyszukiwania na głębokości, której model nigdy nie widzi, opisuje indeks, a nie aplikację.
  • citation_validity sprawdza, czy każdy cytowany identyfikator wskazuje fragment, który dotarł do modelu; require_citations: true oblewa też odpowiedź, która niczego nie cytuje.
  • groundedness_judge i citation_support_judge (opcjonalne) pytają model, czy odpowiedź jest poparta kontekstem. Wymagają dostawcy, modelu i poświadczeń w zmiennej środowiskowej oraz kosztują pieniądze za każdy przypadek; zob. Sędziowie, co musi spełnić sędzia, zanim będzie mógł bramkować.

Wycinki relevant_position i context_truncated nie są tu dostępne: porównują pozycje z top-k aplikacji, które deklaruje tylko system etapowy. Zażądanie ich zatrzymuje przebieg z slice 'relevant_position' compares relevant positions with top_k, so it needs a staged system.

Polityka wydań

version: 1
confidence_level: 0.95
block_on: [FAIL, INSUFFICIENT_EVIDENCE, MANUAL_REVIEW]
rules:
  - id: answer-floor
    metric: answer_correct
    min: 0.70
  - id: retrieval-floor
    metric: hit_rate_at_2
    min: 0.80
  - id: citations-valid
    metric: citations_valid
    kind: observed_count
    max_failures: 0

Reguła min przechodzi tylko wtedy, gdy cały przedział przekracza próg, zawodzi, gdy cały przedział leży poniżej niego, a w przeciwnym razie ma stan INSUFFICIENT_EVIDENCE. Reguła observed_count rozstrzyga na faktycznie uruchomionych przypadkach, bez przedziału: "żadnego nieprawidłowego cytowania w tym zestawie". Zob. Bramkowanie.

Uruchom

oloproof run
Run run_01M4FCBPE0G550CKCVGXCNEM2P [DECIDED/COMPLETE]
Gate: BLOCK (exit 1)
│ answer-floor    │ answer_correct  │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold    │
│ retrieval-floor │ hit_rate_at_2   │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold    │
│ citations-valid │ citations_valid │ FAIL                  │ observed_failures_exceed_limit │

│ answer_correct  │ 73.3%    │ [44.8%, 92.3%] │ 11 / 15 observed · 0 missing · 0 excluded │
│ hit_rate_at_2   │ 92.3%    │ [63.9%, 99.9%] │ 12 / 13 observed · 0 missing · 2 excluded │
│ recall_at_2     │ 92.3%    │ [63.9%, 99.9%] │ 12 / 13 observed · 0 missing · 2 excluded │
│ citations_valid │ 93.3%    │ [68.0%, 99.9%] │ 14 / 15 observed · 0 missing · 0 excluded │
Cache: execution 0 hit/15 miss; judgment 0 hit/56 miss

Jak go czytać:

  • Gate: BLOCK (exit 1): reguła miała wynik FAIL. Kod 1 oznacza FAIL; kod 3 oznacza, że bramka zablokowała bez FAIL (tutaj byłby to INSUFFICIENT_EVIDENCE); kod 0 oznacza, że nie wystąpiło nic, na czym polityka blokuje. [DECIDED/COMPLETE] to stan wykonania: każdy przypadek został uruchomiony.
  • citations-valid ma wynik FAIL: jedna odpowiedź niczego nie cytowała, a require_citations liczy to jako nieprawidłowe.
  • answer-floor ma stan INSUFFICIENT_EVIDENCE, a nie PASS, choć 73,3% to więcej niż 70%: przy 15 przypadkach przedział sięga w dół do 44,8%, więc dowody nie mogą wykazać, że próg jest spełniony.
  • hit_rate_at_2 pokazuje 2 excluded: to dwa przypadki bez etykiet. Jego mianownik to 13, a nie 15.
  • Następująca dalej tabela Slices jest eksploracyjna i nigdy nie bramkuje; wycinek poniżej min_slice_support nie pokazuje przedziału.

Przejrzyj niepowodzenia

Identyfikator przebiegu jest w pierwszym wierszu wyniku przebiegu.

oloproof inspect RUN_ID --failures
4 of 15 cases failed, errored or did not finish

refund_review
  output: {"answer": "Every refund request on an annual plan is logged in the audit trail, and the same request is listed again on the day it was reviewed and approved."…
  answer_correct: failed

money_back
  output: {"answer": "I could not find that in the knowledge base.", "citations": []}
  answer_correct: failed
  hit_rate_at_2: failed
  recall_at_2: failed
  citations_valid: failed

security_review
  output: {"answer": "Security reviews during Enterprise onboarding include an access review and a written summary for the customer, and every review is scheduled with t…
  answer_correct: failed

seat_count
  output: {"answer": "Team plans include five seats.", "citations": ["kb-03"]}
  answer_correct: failed

oloproof inspect RUN_ID --case refund_review wypisuje wejście jednego przypadku, oczekiwane wartości, wynik i każdą ocenę. Zapisane artefakty są w wyeksportowanym pakiecie:

oloproof export RUN_ID

Każdy wiersz .oloproof/bundles/RUN_ID/cases.jsonl to rekord jednego przypadku; jego pole artifacts zawiera to, co zapisano. Dla money_back to pole brzmi:

{"retrieval/v1": [{"candidates": [], "depth": 6, "query": "Where do I claim money back on a yearly subscription?"}], "context/v1": [{"dropped": [], "items": [], "source": "retrieval", "token_budget": 40}], "citations/v1": [{"ids": []}]}

Odczytanie czterech niepowodzeń wyłącznie z zapisanych dowodów:

PrzypadekCo pokazuje rekordSensowne następne działanie
money_backWyszukiwanie nic nie zwróciło: pytanie nie ma żadnego wspólnego słowa z fragmentem o zwrotachPrzepisywanie zapytań lub synonimy, mierzone przez hit_rate_at_2
refund_review, security_reviewhit_rate_at_2 przeszło, a jednak odpowiedź pochodziła z innego fragmentuPrzejrzyj context/v1: czy trafny fragment odrzucono z powodu budżetu?
seat_countWłaściwy fragment został wyszukany, zachowany i zacytowany; odpowiedź mówi "five", przypadek oczekuje "5"Popraw oczekiwanie lub format odpowiedzi, a nie wyszukiwanie

Ta tabela to Twoja interpretacja rekordu. To powiązanie między niepowodzeniem a etapem, a nie udowodniona przyczyna: nic nie wykonało ponownie przypadku ze zmienionym etapem.

Co diagnose robi na czarnej skrzynce

oloproof diagnose RUN_ID --intervention gold-context --criterion answer_correct
Selected: 4 failed cases with gold context (observed; no population claim)
UNRESOLVED: 4 of 4, the system is not staged, so no case was re-executed
Diagnosis sha256:8809e100ab2ec1dad8ffeacc136cd510300081a0edf01ec11f881c543ed104bc
Cases: oloproof inspect sha256:8809e100ab2ec1dad8ffeacc136cd510300081a0edf01ec11f881c543ed104bc

Każdy przypadek ma stan UNRESOLVED z przyczyną intervention_unsupported. Oloproof nie może podać czarnej skrzynce złotego fragmentu w miejsce jej własnego wyszukiwania, więc nie udaje, że to robi. Kontrolowane interwencje wymagają ścieżki B.

Wprowadź zmianę kandydującą i porównaj

Rekord mówi, że money_back zawiódł na wyszukiwaniu. Zmiana kandydująca rozszerza pytanie o synonimy przed wyszukiwaniem. W app.py:

EXPAND_QUERY = True

Zmiana kodu zmienia wersję systemu zapisaną dla przebiegu. Uruchom ponownie, a potem porównaj kandydata z punktem odniesienia:

oloproof run
oloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy compare.yaml

Sam przebieg kandydata: citations-valid ma teraz wynik PASS, hit_rate_at_2 pokazuje 100.0% [75.2%, 100.0%], a bramka nadal blokuje z kodem 3, ponieważ answer-floor i retrieval-floor pozostają INSUFFICIENT_EVIDENCE. Porównanie:

Comparison sha256:2feb024c… of run_01M4FCCJYCVVYA8NB4XZDV6YMB against run_01M4FCCHVBG9WHDP7G5HFX7RDT · 15 paired cases
answer_correct: +6.7 points [-26.5, +40.8] · 15 paired · 0 missing · 0 excluded
hit_rate_at_2: +7.7 points [-29.8, +45.5] · 13 paired · 0 missing · 2 excluded
  excluded 2: no_relevance_labels
recall_at_2: +7.7 points [-29.8, +45.5] · 13 paired · 0 missing · 2 excluded
  excluded 2: no_relevance_labels
citations_valid: +6.7 points [-26.5, +40.8] · 15 paired · 0 missing · 0 excluded
20 exploratory slice differences not shown; add --slices to list them
Decisions
  answers-not-worse  answer_correct  non-inferiority, margin 5.0 points  INSUFFICIENT_EVIDENCE  interval_overlaps_margin
    about 38 more paired cases would decide it, if the difference holds (53 in total at 7% discordance)
  citations-not-worse  citations_valid  non-inferiority, margin 2.0 points  INSUFFICIENT_EVIDENCE  interval_overlaps_margin
    about 68 more paired cases would decide it, if the difference holds (83 in total at 7% discordance)
Gate: BLOCK (exit 3)

Zmiana naprawiła przypadek, w który celowała (o jedną odpowiedź więcej, +6,7 punktu na 15 sparowanych przypadkach). Porównanie nadal nie może ustalić, że kandydat nie jest gorszy od punktu odniesienia o więcej niż margines: 15 sparowanych przypadków zostawia przedział szeroki na około 67 punktów. Wiersz planowania mówi, ile więcej sparowanych przypadków by to rozstrzygnęło, gdyby różnica się utrzymała. Następnym działaniem jest większy zestaw, a nie inny margines. Zob. Porównywanie dwóch przebiegów i Reguły porównań.

Ścieżka B: aplikacja etapowa z diagnozą

Pliki etapowe

Ścieżka B uruchamia przykład support_rag, opisany na stronie Ewaluacja RAG. Skopiuj go:

oloproof init --example support_rag my-staged-rag
cd my-staged-rag
PlikCzym jest
app.pySupportRag, klasa udekorowana @rag_system: retrieve(input, depth), generate(input, context), count_tokens(passage)
data/corpus.jsonl, data/support.jsonlBaza wiedzy i 13 przypadków, każdy z relevant i gold_context
oloproof.yamlsystem.rag wskazuje klasę i ustawia depth, top_k, token_budget, index_version
release.yaml, compare.yamlTe same polityki co w ścieżce A

Różnica względem ścieżki A polega na tym, kto składa kontekst. Tutaj Oloproof wywołuje retrieve, zachowuje pierwszych top_k kandydatów, odrzuca fragmenty poza token_budget i przekazuje resztę do generate. Ponieważ trzyma etapy osobno, może je osobno cache'ować i ponownie wykonać generowanie z innym kontekstem. Aby dostosować własną aplikację, zastąp treść retrieve (wywołaj swój indeks, zwróć Retrieval(candidates=[Passage(...)]) w kolejności swojego retrievera) i generate (wywołaj swój model z podanymi fragmentami). Ustaw index_version na coś, co zmienia się, gdy zmienia się Twój indeks: jest częścią tożsamości wyszukiwania, a nieaktualna wartość ponownie używa zapisanych w cache wyszukiwań względem indeksu, który już ich nie zwraca.

Ta sama konfiguracja pozwala też na wycinki relevant_position i context_truncated oraz na ewaluator ndcg na pełnej głębokości wyszukiwania.

Uruchom zestaw etapowy

oloproof run
Gate: BLOCK (exit 3)
│ answer-floor    │ answer_correct  │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold    │
│ retrieval-floor │ hit_rate_at_2   │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold    │
│ citations-valid │ citations_valid │ PASS                  │ observed_failures_within_limit │
│ answer_correct  │ 69.2%    │ [38.5%, 91.0%]  │ 9 / 13 observed · 0 missing · 0 excluded     │
│ hit_rate_at_2   │ 92.3%    │ [63.9%, 99.9%]  │ 12 / 13 observed · 0 missing · 0 excluded    │
│ recall_at_2     │ 92.3%    │ [63.9%, 99.9%]  │ 12 / 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    │
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łasny cache systemu etapowego. Kod 3: nic nie miało wyniku FAIL, ale dwóm regułom brakuje dowodów, by mieć wynik PASS.

Diagnoza ze złotym kontekstem, obok kontroli

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:50a6124f…
Child runs: gold context run_…, control run_…
Cases: oloproof inspect sha256:50a6124f…

Z nieudanych przypadków powstają dwa przebiegi potomne: jeden z gold_context przypadku w miejsce wyszukanego kontekstu i kontrola, która wykonuje je ponownie bez zmian. To kontrola czyni interpretację bezpieczną: przypadek, który przechodzi przy zwykłym ponownym uruchomieniu, był niestabilny, a nie zdiagnozowany. diagnose kończy się kodem 0 niezależnie od tego, co znajdzie; nie rozstrzyga niczego o wydaniu.

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

Odczytywanie etykiet

EtykietaCo zaobserwowanoCzego to nie ustala
RETRIEVAL_MISSNie wyszukano żadnego trafnego fragmentu, a przypadek przeszedł ze złotym fragmentemŻe wyszukiwanie jest jedynym problemem ani że dana zmiana wyszukiwania to naprawi
RANKED_OUTTrafny fragment wyszukano poniżej top_k, a przypadek przeszedł ze złotym fragmentemŻe poszerzenie top-k pomoże innym przypadkom
CONTEXT_ASSEMBLY_LOSSTrafny fragment w obrębie top-k został odrzucony z kontekstu, a przypadek przeszedł ze złotym fragmentemJaki budżet byłby wystarczający
GENERATION_FAILUREPrzypadek nadal zawiódł, mając złoty fragmentŻe winny jest model, a nie prompt czy oczekiwanie
UNRESOLVEDNie dało się niczego wywnioskować: system nie jest etapowy (intervention_unsupported), przypadek przeszedł w kontroli (unstable_under_control), nie ma etykiet trafności (no_relevance_labels) albo brakuje dowodówCzegokolwiek o przypadku

Każda etykieta to powiązanie między niepowodzeniem a etapem przy jednej interwencji na tych przypadkach. Nie jest to udowodniona przyczyna: "Implicated" i "Candidate experiment" to najmocniejsze słowa, jakich używa wynik, a liczności opisują tylko wybrane przypadki ("no population claim"). seat_count to dobre przypomnienie: zawodzi z właściwym fragmentem, ponieważ baza wiedzy mówi "five", a przypadek oczekuje "5", czego żadna zmiana wyszukiwania nie naprawi.

Przypadki ze złotymi fragmentami i bez nich

Ponownie wykonać można tylko nieudane przypadki, które deklarują expected.gold_context. Usuń złoty fragment z seat_count i money_back (oraz etykietę trafności z money_back), a to samo polecenie zgłosi:

Selected: 2 failed cases with gold context (observed; no population claim)
Excluded: 2 failed cases, no_gold_context - declare the passages that would have answered the case in its `expected.gold_context`, as a list of `{doc_id, text}` objects; an intervention needs them to tell a retrieval failure from a generation one
Control: 0 of 2 passed when re-executed without the intervention
Recovered under gold context: 2 of 2
CONTEXT_ASSEMBLY_LOSS: 2 of 2, recovered; relevant evidence within top-k was left out of the context

Wykluczone przypadki są wymienione, a nie po cichu pominięte. Zwróć też uwagę, co usunięcie etykiety trafności robi z samym przebiegiem: hit_rate_at_2 wzrosło do 100.0% (12 / 12 observed, 1 excluded), ponieważ jedyny przypadek, który wyszukiwanie przeoczyło, nie jest już mierzony. Przypadki bez etykiet opuszczają mianownik; nie liczą się jako zaliczenia, a metryka na mniejszej liczbie przypadków może wyglądać lepiej, niż jest aplikacja. Najpierw etykietuj trudne przypadki.

Przetestuj poprawkę, zanim ją wprowadzisz: top-k i reranker

Dwie kolejne interwencje odtwarzają zapisane wyszukiwanie z innym ustawieniem, więc retriever nie jest wywoływany ponownie:

oloproof diagnose RUN_ID --intervention top-k --top-k 4 --criterion answer_correct
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:50a6124f…): 3 of 4 recovered

Reranker to funkcja (input, candidates) -> candidates, którą piszesz. Zapisz ją jako rerank.py obok app.py:

"""A candidate reranker: shorter passages first, so more of them fit the token budget."""

from oloproof import Passage


def shortest_first(input: dict, candidates: list[Passage]) -> list[Passage]:
    return sorted(candidates, key=lambda passage: len((passage.text or "").split()))
oloproof diagnose RUN_ID --intervention reranker --reranker rerank:shortest_first --criterion answer_correct
Recovered under reranker rerank:shortest_first: 0 of 4
Confirmed under reranker rerank:shortest_first: 0 of 0 RANKED_OUT cases also recovered

Żadna nic nie odzyskuje, co przewidziały etykiety ze złotego kontekstu: żadne niepowodzenie tutaj nie było fragmentem uszeregowanym tuż poniżej odcięcia. Każde odtworzenie przenosi etykiety ze złotego kontekstu dalej, więc diagnozy czyta się razem.

Przeprowadź eksperyment wskazany przez diagnozę i porównaj

Podnieś token_budget do 120 w oloproof.yaml, a następnie:

oloproof run
oloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy compare.yaml
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 leżą poza tożsamością wyszukiwania; ponownie wygenerowano tylko sześć przypadków, których kontekst się zmienił.

answer_correct: +0.0 points [-33.6, +33.6] · 13 paired · 0 missing · 0 excluded
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 przypadek nie zmienił werdyktu, więc hipoteza zaproponowana przez diagnozę nie znajduje potwierdzenia dla tych przypadków. To użyteczny wynik. Następnym eksperymentem są mniejsze fragmenty albo prompty dwóch przypadków składania kontekstu; seat_count wymaga poprawienia oczekiwania.

Rozwiązywanie problemów

ObjawPrzyczynaRozwiązanie
Configuration error: slice 'relevant_position' ... needs a staged systemWycinek pozycji na systemie z funkcją wywoływalną lub HTTPUsuń wycinek albo przejdź na ścieżkę B
Przebieg zatrzymuje się z kodem 2 i malformed retrieval/v1 artifactPole, na które schemat nie pozwala, lub więcej kandydatów niż depthOdwzorowuj tylko udokumentowane pola; ustaw depth na co najmniej liczbę zwróconych
citations_valid pokazuje 0 / 0 observed · 15 missing, a jego reguła to INSUFFICIENT_EVIDENCE z no_observationsAdapter nie zapisał citations/v1 (ani context/v1); każdy taki przypadek jest brakujący, a nie zaliczonyZapisuj oba na każdej ścieżce przez adapter, także przy "brak odpowiedzi"; oloproof inspect RUN_ID --failures pokazuje błąd dla każdego przypadku
Metryka wyszukiwania pokazuje wiele excludedPrzypadki bez expected.relevantOetykietuj je albo świadomie zaakceptuj mniejszy mianownik
diagnose mówi UNRESOLVED ... not stagedŚcieżka ATo oczekiwane; do interwencji użyj ścieżki B
diagnose odmawia z an intervention must re-execute the same systemKod lub konfiguracja zmieniły się od czasu przebieguDiagnozuj przebieg bieżącej wersji albo przywróć wersję, która była uruchomiona
Diagnoza wybiera mniej przypadków, niż zawiodłoNieudane przypadki bez expected.gold_contextDodaj złote fragmenty; wykluczone przypadki są wymienione w wyniku
Wyszukiwania są używane ponownie po zmianie indeksuindex_version bez zmianZmieniaj index_version, gdy zmienia się indeks

Ograniczenia

  • Oloproof wywołuje Twoją aplikację; nie hostuje jej, nie izoluje ani nie resetuje. Jej indeks, cache i każdy stan, który przechowuje, należą do Ciebie.
  • Na czarnej skrzynce interwencje nie są dostępne: diagnose oznacza każdy przypadek jako UNRESOLVED i niczego ponownie nie wykonuje.
  • Interwencje to złoty kontekst, top-k i reranker. Nie ma interwencji dotyczących dzielenia na fragmenty, embeddingów ani promptu.
  • Etykiety diagnozy opisują wybrane nieudane przypadki przy jednej interwencji obok kontroli. Wiążą niepowodzenie z etapem; nie dowodzą przyczyny i nie twierdzą niczego o przypadkach, których nie wybrano.
  • Metryki wyszukiwania wymagają etykiet trafności, a diagnoza złotych fragmentów; Oloproof nie tworzy ani jednych, ani drugich.
  • Deterministyczne przykłady zastępują prawdziwy retriever i model. Prawdziwy model w generate lub ewaluator-sędzia wywołuje dostawcę, wymaga poświadczeń i kosztuje pieniądze za każdy przypadek.
  • Co działa gdzie, SDK w porównaniu z YAML i przeglądarką, opisuje Co działa dziś.