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żka | Co dostajesz | Czego 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 skrzynka | Metryki wyszukiwania, sprawdzenia cytowań, sędziów ugruntowania, bramkowanie, porównanie | Kontrolowane interwencje: diagnose niczego ponownie nie wykonuje |
| Wyszukiwanie i generowanie, które możesz wywołać osobno | B, etapowa | Wszystko z A, cache dla każdego etapu oraz diagnose ze złotym kontekstem, top-k i rerankerem obok kontroli | Interwencje 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-ragKaż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
| Plik | Czym jest |
|---|---|
| app.py | support_api(question), zastępujące Twoją aplikację, oraz run(case), adapter |
| server.py | Ta sama aplikacja przez HTTP, dla wariantu HTTP poniżej |
| data/corpus.jsonl | Baza wiedzy z 14 fragmentów, którą przeszukuje aplikacja |
| data/support.jsonl | 15 przypadków: 13 z etykietami trafności i złotymi fragmentami, 2 bez żadnego z nich |
| oloproof.yaml | Zestaw: zbiór danych, system, ewaluatory, wycinki |
| oloproof.http.yaml | Ten sam zestaw względem serwera HTTP |
| release.yaml | Polityka wydań dla pojedynczego przebiegu |
| compare.yaml | Polityka 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"]}| Artefakt | Kształt | Czytany przez |
|---|---|---|
| retrieval/v1 | query, 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/v1 | items, które dotarły do modelu (doc_id, position, tokens, text), elementy dropped z reason równym top_k lub token_budget, oraz token_budget | citation_validity, groundedness_judge, citation_support_judge |
| citations/v1 | ids, każdy jako doc_id lub doc_id#chunk_id | citation_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.citationsserver.py serwuje dokładnie to. Uruchom go, a potem uruchom zestaw względem niego:
python server.py 8766
oloproof run --config oloproof.http.yamlWejś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: 0Reguł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 runRun 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 missJak 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 --failures4 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: failedoloproof 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_IDKaż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:
| Przypadek | Co pokazuje rekord | Sensowne następne działanie |
|---|---|---|
| money_back | Wyszukiwanie nic nie zwróciło: pytanie nie ma żadnego wspólnego słowa z fragmentem o zwrotach | Przepisywanie zapytań lub synonimy, mierzone przez hit_rate_at_2 |
| refund_review, security_review | hit_rate_at_2 przeszło, a jednak odpowiedź pochodziła z innego fragmentu | Przejrzyj context/v1: czy trafny fragment odrzucono z powodu budżetu? |
| seat_count | Wł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_correctSelected: 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:8809e100ab2ec1dad8ffeacc136cd510300081a0edf01ec11f881c543ed104bcKaż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 = TrueZmiana 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.yamlSam 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| Plik | Czym jest |
|---|---|
| app.py | SupportRag, klasa udekorowana @rag_system: retrieve(input, depth), generate(input, context), count_tokens(passage) |
| data/corpus.jsonl, data/support.jsonl | Baza wiedzy i 13 przypadków, każdy z relevant i gold_context |
| oloproof.yaml | system.rag wskazuje klasę i ustawia depth, top_k, token_budget, index_version |
| release.yaml, compare.yaml | Te 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 runGate: 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 missWiersz 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_correctSelected: 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_IDmoney_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 2Odczytywanie etykiet
| Etykieta | Co zaobserwowano | Czego to nie ustala |
|---|---|---|
| RETRIEVAL_MISS | Nie wyszukano żadnego trafnego fragmentu, a przypadek przeszedł ze złotym fragmentem | Że wyszukiwanie jest jedynym problemem ani że dana zmiana wyszukiwania to naprawi |
| RANKED_OUT | Trafny fragment wyszukano poniżej top_k, a przypadek przeszedł ze złotym fragmentem | Że poszerzenie top-k pomoże innym przypadkom |
| CONTEXT_ASSEMBLY_LOSS | Trafny fragment w obrębie top-k został odrzucony z kontekstu, a przypadek przeszedł ze złotym fragmentem | Jaki budżet byłby wystarczający |
| GENERATION_FAILURE | Przypadek nadal zawiódł, mając złoty fragment | Że winny jest model, a nie prompt czy oczekiwanie |
| UNRESOLVED | Nie 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ów | Czegokolwiek 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 contextWykluczone 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_correctRecovered 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 recoveredReranker 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_correctRecovered 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.yamlStages: retrieve 13 hit/0 miss; generate 7 hit/6 missKaż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
| Objaw | Przyczyna | Rozwiązanie |
|---|---|---|
| Configuration error: slice 'relevant_position' ... needs a staged system | Wycinek pozycji na systemie z funkcją wywoływalną lub HTTP | Usuń wycinek albo przejdź na ścieżkę B |
| Przebieg zatrzymuje się z kodem 2 i malformed retrieval/v1 artifact | Pole, na które schemat nie pozwala, lub więcej kandydatów niż depth | Odwzorowuj 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_observations | Adapter nie zapisał citations/v1 (ani context/v1); każdy taki przypadek jest brakujący, a nie zaliczony | Zapisuj 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 excluded | Przypadki bez expected.relevant | Oetykietuj je albo świadomie zaakceptuj mniejszy mianownik |
| diagnose mówi UNRESOLVED ... not staged | Ścieżka A | To oczekiwane; do interwencji użyj ścieżki B |
| diagnose odmawia z an intervention must re-execute the same system | Kod lub konfiguracja zmieniły się od czasu przebiegu | Diagnozuj przebieg bieżącej wersji albo przywróć wersję, która była uruchomiona |
| Diagnoza wybiera mniej przypadków, niż zawiodło | Nieudane przypadki bez expected.gold_context | Dodaj złote fragmenty; wykluczone przypadki są wymienione w wyniku |
| Wyszukiwania są używane ponownie po zmianie indeksu | index_version bez zmian | Zmieniaj 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ś.