Ga naar de inhoud

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 applicatiePadWat je krijgtWat je niet krijgt
Eén aanroep erin, één antwoord eruit (een dienst, een HTTP-endpoint, een frameworkketen die je niet wilt opsplitsen)A, black boxRetrievalmetrieken, citatiecontroles, grounding-judges, gating, vergelijkingGecontroleerde interventies: diagnose voert niets opnieuw uit
Retrieval en generatie die je apart kunt aanroepenB, gefaseerdAlles uit A, caching per fase, en diagnose met gouden context, top-k en een reranker naast een controleAndere 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-rag

Elk 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

BestandWat het is
app.pysupport_api(question), dat voor je applicatie instaat, en run(case), de adapter
server.pyDezelfde applicatie via HTTP, voor de HTTP-variant hieronder
data/corpus.jsonlDe kennisbank van 14 passages die de applicatie doorzoekt
data/support.jsonl15 cases: 13 met relevantielabels en gouden passages, 2 zonder beide
oloproof.yamlDe suite: dataset, systeem, evaluators, slices
oloproof.http.yamlDezelfde suite tegen de HTTP-server
release.yamlDe releasepolicy voor één run
compare.yamlDe 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"]}
ArtefactVormGelezen door
retrieval/v1query, 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/v1items die het model bereikten (doc_id, position, tokens, text), dropped items met een reason van top_k of token_budget, en token_budgetcitation_validity, groundedness_judge, citation_support_judge
citations/v1ids, elk een doc_id of doc_id#chunk_idcitation_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.citations

server.py levert precies dat. Start hem en draai er dan tegen:

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

De 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: 0

Een 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 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

Zo 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 --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 print de input, verwachte waarden, uitvoer en elk oordeel van één case. De vastgelegde artefacten staan in de geëxporteerde bundel:

oloproof export RUN_ID

Elke 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:

CaseWat het record toontEen zinvolle volgende stap
money_backRetrieval gaf niets terug: de vraag deelt geen woord met de refundpassageQuery herschrijven of synoniemen, gemeten met hit_rate_at_2
refund_review, security_reviewhit_rate_at_2 slaagde, toch kwam het antwoord uit een andere passageBekijk context/v1: viel de relevante passage weg door het budget?
seat_countDe 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_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

Elke 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 = True

De 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.yaml

De 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
BestandWat het is
app.pySupportRag, een klasse met de decorator @rag_system: retrieve(input, depth), generate(input, context), count_tokens(passage)
data/corpus.jsonl, data/support.jsonlDe kennisbank, en 13 cases, elk met relevant en gold_context
oloproof.yamlsystem.rag wijst naar de klasse en zet depth, top_k, token_budget, index_version
release.yaml, compare.yamlDezelfde 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 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

De 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_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…

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_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

De labels lezen

LabelWat werd waargenomenWat het niet vaststelt
RETRIEVAL_MISSEr werd geen relevante passage opgehaald, en de case slaagde met de gouden passageDat retrieval het enige is dat fout zit, of dat een bepaalde retrievalwijziging het oplost
RANKED_OUTEen relevante passage werd onder top_k opgehaald, en de case slaagde met de gouden passageDat een bredere top-k andere cases helpt
CONTEXT_ASSEMBLY_LOSSEen relevante passage binnen top-k viel uit de context, en de case slaagde met de gouden passageWelk budget genoeg zou zijn
GENERATION_FAILUREDe case mislukte nog steeds met de gouden passage in handenDat het model, en niet de prompt of de verwachting, schuld heeft
UNRESOLVEDEr 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 bewijsWat 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 context

De 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_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

Een 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_correct
Recovered under reranker rerank:shortest_first: 0 of 4
Confirmed under reranker rerank:shortest_first: 0 of 0 RANKED_OUT cases also recovered

Geen 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.yaml
Stages: retrieve 13 hit/0 miss; generate 7 hit/6 miss

Elke 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

SymptoomOorzaakOplossing
Configuration error: slice 'relevant_position' ... needs a staged systemEen positieslice op een callable- of HTTP-systeemLaat de slice weg, of stap over naar pad B
De run stopt met exit 2 en malformed retrieval/v1 artifactEen veld dat het schema niet toestaat, of meer kandidaten dan depthZet 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_observationsDe adapter legde citations/v1 (of context/v1) niet vast; elke zulke case ontbreekt, en is niet geslaagdLeg 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 excludedCases zonder expected.relevantLabel ze, of accepteer bewust de kleinere noemer
diagnose zegt UNRESOLVED ... not stagedPad AVerwacht; gebruik pad B voor interventies
diagnose weigert met an intervention must re-execute the same systemDe code of configuratie veranderde sinds de runDiagnosticeer een run van de huidige versie, of herstel de versie die draaide
Diagnose selecteert minder cases dan er misluktenMislukte cases zonder expected.gold_contextVoeg de gouden passages toe; de uitgesloten cases staan in de uitvoer
Retrievals worden hergebruikt nadat de index veranderdeindex_version ongewijzigdWijzig 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.