Handleidingen
Tutorial: een RAG-applicatie evalueren
Een uitvoerbare doorloop voor een retrieval-augmented applicatie, langs twee paden: een bestaande black-box-applicatie waarvan je retrieval, context en citaties van buitenaf vastlegt, en een gefaseerde applicatie die Oloproof fase voor fase draait zodat oloproof diagnose mislukte cases opnieuw kan uitvoeren onder gecontroleerde wijzigingen. Beide draaien lokaal zonder inloggegevens van een provider.
De begrippen achter elke stap (fasen, relevantielabels, gouden context, de vier mislukkingslabels) staan op de pagina RAG-evaluatie; de termen case, evaluator, metriek, interval en gate staan in Kernbegrippen. Deze pagina is de praktische route erdoorheen.
Welk pad het jouwe is
| Jouw applicatie | Pad | Wat je krijgt | Wat je niet krijgt |
|---|---|---|---|
| Eén aanroep erin, één antwoord eruit (een dienst, een HTTP-endpoint, een frameworkketen die je niet wilt opsplitsen) | A, black box | Retrievalmetrieken, citatiecontroles, grounding-judges, gating, vergelijking | Gecontroleerde interventies: diagnose voert niets opnieuw uit |
| Retrieval en generatie die je apart kunt aanroepen | B, gefaseerd | Alles uit A, caching per fase, en diagnose met gouden context, top-k en een reranker naast een controle | Andere interventies dan die drie |
Begin met A als je twijfelt. Het vraagt geen wijziging aan de applicatie, en later overstappen naar B behoudt de dataset, evaluators en policy.
Vereisten
- Python 3.11 of nieuwer, en Oloproof geïnstalleerd (pip install oloproof).
- De voorbeeldprojecten, die met het pakket meekomen: blackbox_rag voor pad A en support_rag voor pad B. Kopieer er een naar een nieuwe map en werk daar:
oloproof init --example blackbox_rag my-rag
cd my-ragElk commando hieronder draait vanuit de gekopieerde map. Runs, oordelen en diagnoses worden daar opgeslagen in .oloproof/.
Pad A: een bestaande applicatie als black box
De bestanden
| Bestand | Wat het is |
|---|---|
| app.py | support_api(question), dat voor je applicatie instaat, en run(case), de adapter |
| server.py | Dezelfde applicatie via HTTP, voor de HTTP-variant hieronder |
| data/corpus.jsonl | De kennisbank van 14 passages die de applicatie doorzoekt |
| data/support.jsonl | 15 cases: 13 met relevantielabels en gouden passages, 2 zonder beide |
| oloproof.yaml | De suite: dataset, systeem, evaluators, slices |
| oloproof.http.yaml | Dezelfde suite tegen de HTTP-server |
| release.yaml | De releasepolicy voor één run |
| compare.yaml | De policy om een kandidaatrun met een baseline te vergelijken |
Wat de applicatie teruggeeft
support_api gedraagt zich als een applicatie die je al hebt: hij zoekt, bouwt een prompt uit de beste bronnen die in een woordbudget passen, antwoordt en citeert. Zijn antwoord draagt al wat hij deed:
{
"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"}]
}De veldnamen van je applicatie zullen anders zijn. Waar het om gaat is dat ze je per vraag kan vertellen welke gerangschikte bronnen ze ophaalde, welke het model bereikten en welke ze citeerde. Kan ze dat niet, voeg die dan eerst toe aan haar antwoord of haar logs: Oloproof meet wat is vastgelegd en leidt retrieval nooit af uit een antwoord.
De adapter
run roept de applicatie ongewijzigd aan en zet het antwoord om in drie getypeerde artefacten, de records die de retrieval- en citatie-evaluators lezen:
@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"]}| Artefact | Vorm | Gelezen door |
|---|---|---|
| retrieval/v1 | query, depth, en candidates in de volgorde waarin je retriever ze teruggaf, elk een Passage(doc_id, chunk_id, score, text) | hit_rate, recall, mrr, ndcg |
| context/v1 | items die het model bereikten (doc_id, position, tokens, text), dropped items met een reason van top_k of token_budget, en token_budget | citation_validity, groundedness_judge, citation_support_judge |
| citations/v1 | ids, elk een doc_id of doc_id#chunk_id | citation_validity, citation_support_judge |
Oloproof legt posities vast zoals ze gegeven zijn en herrangschikt nooit. Een misvormd artefact stopt de run met exitcode 2 in plaats van opgeslagen te worden. case is het input-object van de case, dus case["question"] is de vraag uit de dataset.
Om je eigen applicatie te gebruiken, vervang je de body van support_api door een aanroep ervan (een SDK-aanroep, een HTTP-verzoek) en houd je run. Richt system.callable in oloproof.yaml erop als module:function.
De HTTP-variant
Een HTTP-systeem kan de recorder niet aanroepen, dus zijn antwoord draagt het bewijs, al in de drie vormen hierboven, en de configuratie noemt waar:
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 levert precies dat. Start hem en draai er dan tegen:
python server.py 8766
oloproof run --config oloproof.http.yamlDe input van de case wordt als JSON-body gepost. output_path haalt de uitvoer uit het antwoord, en elke artifacts-regel legt een pad met punten vast als die soort; een ontbrekend of misvormd veld stopt de run met exitcode 2. De resultaten zijn gelijk aan die van het callable-pad hieronder. In je eigen dienst is het bewijsobject meestal een debugveld dat je aanzet voor evaluatieverkeer.
Wat een case declareert
{"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 noemt de passages die de vraag beantwoorden. Retrievalmetrieken lezen het. Een case zonder, zoals office_hours, wordt ervan uitgesloten met no_relevance_labels: ze verlaat de noemer in plaats van als geslaagd of mislukt te tellen.
- expected.gold_context is de tekst van de passage zelf. Pad A gebruikt het nooit; pad B zet het tijdens de diagnose in de plaats van de opgehaalde context.
Cases zonder labels zijn in de praktijk normaal, omdat relevantie labelen werk kost. Ze tellen nog steeds mee voor de antwoord- en citatiecontroles.
Evaluators kiezen
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 controleert of het antwoord de verwachte tekst bevat. Het is de taakcontrole: kreeg de gebruiker het juiste antwoord. Gebruik een exacte of rubric-judge als de formulering varieert.
- hit_rate en recall bij k: 2 meten retrieval op de diepte die de applicatie werkelijk in de prompt zet. Een retrievalmetriek op een diepte die het model nooit ziet, beschrijft de index, niet de applicatie.
- citation_validity controleert of elk geciteerd id een passage noemt die het model bereikte; require_citations: true laat ook een antwoord dat niets citeert mislukken.
- groundedness_judge en citation_support_judge (optioneel) vragen een model of het antwoord door de context wordt gedragen. Ze hebben een provider, een model en inloggegevens in een omgevingsvariabele nodig, en kosten geld per case; zie Judges voor wat een judge moet halen voordat hij mag gaten.
De slices relevant_position en context_truncated zijn hier niet beschikbaar: ze vergelijken posities met de top-k van de applicatie, die alleen een gefaseerd systeem declareert. Erom vragen stopt de run met slice 'relevant_position' compares relevant positions with top_k, so it needs a staged system.
De releasepolicy
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: 0Een min-regel slaagt alleen als het hele interval de ondergrens haalt, faalt als het hele interval eronder ligt, en is anders INSUFFICIENT_EVIDENCE. Een observed_count-regel beslist op de cases die werkelijk draaiden, zonder interval: "geen ongeldige citatie in deze suite". Zie CI gaten.
Draaien
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 missZo lees je het:
- Gate: BLOCK (exit 1): een regel gaf FAIL. Exit 1 betekent een FAIL; exit 3 betekent dat de gate blokkeerde zonder FAIL (hier zou dat INSUFFICIENT_EVIDENCE zijn); exit 0 betekent niets waarop de policy blokkeert. [DECIDED/COMPLETE] is de uitvoeringstoestand: elke case draaide.
- citations-valid geeft FAIL: één antwoord citeerde niets, en require_citations telt dat als ongeldig.
- answer-floor is INSUFFICIENT_EVIDENCE, geen PASS, hoewel 73.3% boven 70% ligt: met 15 cases reikt het interval tot 44.8%, dus het bewijs kan niet aantonen dat de ondergrens gehaald wordt.
- hit_rate_at_2 toont 2 excluded: de twee cases zonder labels. De noemer is 13, niet 15.
- De tabel Slices die volgt is verkennend en wordt nooit gegate; een slice onder min_slice_support toont geen interval.
De mislukkingen bekijken
Het run-id staat op de eerste regel van de uitvoer van de run.
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 print de input, verwachte waarden, uitvoer en elk oordeel van één case. De vastgelegde artefacten staan in de geëxporteerde bundel:
oloproof export RUN_IDElke regel van .oloproof/bundles/RUN_ID/cases.jsonl is het record van één case; het veld artifacts bevat wat werd vastgelegd. Voor money_back luidt dat veld:
{"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": []}]}De vier mislukkingen gelezen uit alleen het vastgelegde bewijs:
| Case | Wat het record toont | Een zinvolle volgende stap |
|---|---|---|
| money_back | Retrieval gaf niets terug: de vraag deelt geen woord met de refundpassage | Query herschrijven of synoniemen, gemeten met hit_rate_at_2 |
| refund_review, security_review | hit_rate_at_2 slaagde, toch kwam het antwoord uit een andere passage | Bekijk context/v1: viel de relevante passage weg door het budget? |
| seat_count | De juiste passage werd opgehaald, behouden en geciteerd; het antwoord zegt "five", de case verwacht "5" | Herstel de verwachting of het antwoordformaat, niet de retrieval |
Die tabel is jouw lezing van het record. Het is een verband tussen een mislukking en een fase, geen bewezen oorzaak: niets voerde de case opnieuw uit met de fase gewijzigd.
Wat diagnose doet bij een black box
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:8809e100ab2ec1dad8ffeacc136cd510300081a0edf01ec11f881c543ed104bcElke case is UNRESOLVED met de reden intervention_unsupported. Oloproof kan een black box de gouden passage niet geven in plaats van zijn eigen retrieval, dus doet het ook niet alsof. Gecontroleerde interventies hebben pad B nodig.
Een kandidaatwijziging maken en vergelijken
Het record zegt dat money_back bij de retrieval mislukte. De kandidaatwijziging breidt de vraag uit met synoniemen vóór het zoeken. In app.py:
EXPAND_QUERY = TrueDe code wijzigen verandert de systeemversie die voor de run wordt vastgelegd. Draai opnieuw en vergelijk daarna de kandidaat met de baseline:
oloproof run
oloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy compare.yamlDe kandidaatrun alleen: citations-valid geeft nu PASS, hit_rate_at_2 toont 100.0% [75.2%, 100.0%], en de gate blokkeert nog steeds met exit 3 omdat answer-floor en retrieval-floor INSUFFICIENT_EVIDENCE blijven. De vergelijking:
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)De wijziging repareerde de case waarop ze mikte (één antwoord meer, +6.7 punten over 15 gepaarde cases). De vergelijking kan nog steeds niet vaststellen dat de kandidaat niet meer dan de marge slechter is dan de baseline: 15 gepaarde cases laten een interval van ongeveer 67 punten breed over. De planningsregel zegt hoeveel gepaarde cases meer het zouden beslissen als het verschil standhield. Een grotere suite, geen andere marge, is de volgende stap. Zie Een kandidaat met een baseline vergelijken en Vergelijkingsregels.
Pad B: een gefaseerde applicatie met diagnose
De gefaseerde bestanden
Pad B draait het voorbeeld support_rag, beschreven op de pagina RAG-evaluatie. Kopieer het:
oloproof init --example support_rag my-staged-rag
cd my-staged-rag| Bestand | Wat het is |
|---|---|
| app.py | SupportRag, een klasse met de decorator @rag_system: retrieve(input, depth), generate(input, context), count_tokens(passage) |
| data/corpus.jsonl, data/support.jsonl | De kennisbank, en 13 cases, elk met relevant en gold_context |
| oloproof.yaml | system.rag wijst naar de klasse en zet depth, top_k, token_budget, index_version |
| release.yaml, compare.yaml | Dezelfde policies als pad A |
Het verschil met pad A is wie de context samenstelt. Hier roept Oloproof retrieve aan, houdt de eerste top_k kandidaten, laat passages voorbij token_budget vallen en geeft de rest aan generate. Omdat het de fasen gescheiden houdt, kan het ze apart cachen en generatie opnieuw uitvoeren met een andere context. Om je eigen applicatie aan te passen, vervang je de bodies van retrieve (roep je index aan, geef Retrieval(candidates=[Passage(...)]) terug in de volgorde van je retriever) en generate (roep je model aan met de gegeven passages). Zet index_version op iets dat verandert wanneer je index verandert: het is deel van de identiteit van de retrieval, en een verouderde waarde hergebruikt gecachete retrievals tegen een index die ze niet meer teruggeeft.
Dezelfde configuratie staat ook de slices relevant_position en context_truncated toe, en een ndcg-evaluator over de volledige retrievaldiepte.
De gefaseerde suite draaien
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 missDe regel Stages is de eigen cache van het gefaseerde systeem. Exit 3: niets gaf FAIL, maar twee regels missen het bewijs om te slagen.
Diagnose met gouden context, naast een controle
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…Uit de mislukte cases worden twee kindruns gemaakt: één met de gold_context van de case in plaats van de opgehaalde context, en een controle die ze ongewijzigd opnieuw uitvoert. De controle maakt de lezing veilig: een case die slaagt bij een gewone herhaling was instabiel, niet gediagnosticeerd. diagnose eindigt met 0 wat het ook vindt; het beslist niets over de release.
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 2De labels lezen
| Label | Wat werd waargenomen | Wat het niet vaststelt |
|---|---|---|
| RETRIEVAL_MISS | Er werd geen relevante passage opgehaald, en de case slaagde met de gouden passage | Dat retrieval het enige is dat fout zit, of dat een bepaalde retrievalwijziging het oplost |
| RANKED_OUT | Een relevante passage werd onder top_k opgehaald, en de case slaagde met de gouden passage | Dat een bredere top-k andere cases helpt |
| CONTEXT_ASSEMBLY_LOSS | Een relevante passage binnen top-k viel uit de context, en de case slaagde met de gouden passage | Welk budget genoeg zou zijn |
| GENERATION_FAILURE | De case mislukte nog steeds met de gouden passage in handen | Dat het model, en niet de prompt of de verwachting, schuld heeft |
| UNRESOLVED | Er kon niets worden geconcludeerd: het systeem is niet gefaseerd (intervention_unsupported), de case herstelde onder de controle (unstable_under_control), ze heeft geen relevantielabels (no_relevance_labels), of er ontbreekt bewijs | Wat dan ook over de case |
Elk label is een verband tussen een mislukking en een fase onder één interventie op deze cases. Het is geen bewezen oorzaak: "Implicated" en "Candidate experiment" zijn de sterkste woorden die de uitvoer gebruikt, en de aantallen beschrijven alleen de geselecteerde cases ("no population claim"). seat_count is een goede herinnering: het mislukt met de juiste passage omdat de kennisbank "five" zegt en de case "5" verwacht, wat geen retrievalwijziging kan oplossen.
Cases met en zonder gouden passages
Alleen mislukte cases die expected.gold_context declareren kunnen opnieuw worden uitgevoerd. Verwijder de gouden passage uit seat_count en money_back (en het relevantielabel uit money_back) en hetzelfde commando meldt:
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 contextDe uitgesloten cases worden genoemd, niet stilzwijgend weggelaten. Let ook op wat het verwijderen van een relevantielabel met de run zelf doet: hit_rate_at_2 steeg naar 100.0% (12 / 12 observed, 1 excluded), omdat de ene case die retrieval miste niet meer gemeten wordt. Cases zonder labels verlaten de noemer; ze tellen niet als geslaagd, en een metriek over minder cases kan er beter uitzien dan de applicatie is. Label de moeilijke cases eerst.
Een oplossing testen voordat je hem maakt: top-k en een reranker
Twee andere interventies spelen de vastgelegde retrieval opnieuw af met een andere instelling, zodat de retriever niet opnieuw wordt aangeroepen:
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 recoveredEen reranker is een functie (input, candidates) -> candidates die je zelf schrijft. Sla hem op als rerank.py naast 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 recoveredGeen van beide herstelt iets, wat de labels van de gouden context voorspelden: geen mislukking hier was een passage die net onder de grens stond. Elke herhaling neemt de labels van de gouden context mee, zodat de diagnoses samen te lezen zijn.
Het experiment draaien dat de diagnose noemde, en vergelijken
Verhoog token_budget naar 120 in oloproof.yaml, en dan:
oloproof run
oloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy compare.yamlStages: retrieve 13 hit/0 miss; generate 7 hit/6 missElke retrieval werd hergebruikt, omdat top_k en het budget buiten de identiteit van de retrieval vallen; alleen de zes cases waarvan de context veranderde werden opnieuw gegenereerd.
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)Het experiment hielp niet: geen enkele case veranderde van oordeel, dus de hypothese die de diagnose bood wordt voor deze cases niet ondersteund. Dat is een nuttig resultaat. Het volgende experiment is kleinere chunks, of de prompts van de twee cases met contextsamenstelling; seat_count heeft een herstelde verwachting nodig.
Problemen oplossen
| Symptoom | Oorzaak | Oplossing |
|---|---|---|
| Configuration error: slice 'relevant_position' ... needs a staged system | Een positieslice op een callable- of HTTP-systeem | Laat de slice weg, of stap over naar pad B |
| De run stopt met exit 2 en malformed retrieval/v1 artifact | Een veld dat het schema niet toestaat, of meer kandidaten dan depth | Zet alleen de gedocumenteerde velden om; zet depth op minstens het aantal teruggegeven |
| citations_valid toont 0 / 0 observed · 15 missing en de regel is INSUFFICIENT_EVIDENCE met no_observations | De adapter legde citations/v1 (of context/v1) niet vast; elke zulke case ontbreekt, en is niet geslaagd | Leg beide vast op elk pad door de adapter, ook bij "geen antwoord"; oloproof inspect RUN_ID --failures toont de fout per case |
| Een retrievalmetriek toont veel excluded | Cases zonder expected.relevant | Label ze, of accepteer bewust de kleinere noemer |
| diagnose zegt UNRESOLVED ... not staged | Pad A | Verwacht; gebruik pad B voor interventies |
| diagnose weigert met an intervention must re-execute the same system | De code of configuratie veranderde sinds de run | Diagnosticeer een run van de huidige versie, of herstel de versie die draaide |
| Diagnose selecteert minder cases dan er mislukten | Mislukte cases zonder expected.gold_context | Voeg de gouden passages toe; de uitgesloten cases staan in de uitvoer |
| Retrievals worden hergebruikt nadat de index veranderde | index_version ongewijzigd | Wijzig index_version wanneer de index verandert |
Beperkingen
- Oloproof roept je applicatie aan; het host, sandboxt of reset haar niet. Haar index, caches en elke toestand die ze bewaart zijn van jou.
- Bij een black box zijn interventies niet beschikbaar: diagnose labelt elke case UNRESOLVED en voert niets opnieuw uit.
- De interventies zijn gouden context, top-k en een reranker. Er is geen interventie voor chunking, embeddings of prompts.
- Diagnoselabels beschrijven de geselecteerde mislukte cases onder één interventie naast een controle. Ze verbinden een mislukking met een fase; ze bewijzen geen oorzaak, en ze doen geen uitspraak over niet-geselecteerde cases.
- Retrievalmetrieken hebben relevantielabels nodig, en de diagnose heeft gouden passages nodig; Oloproof maakt geen van beide.
- De deterministische voorbeelden staan in voor een echte retriever en een echt model. Een live model in generate of een judge-evaluator roept een provider aan, heeft inloggegevens nodig en kost geld per case.
- Wat waar werkt, SDK tegenover YAML tegenover browser, staat op Wat vandaag werkt.