Guide
Tutorial: valutare un'applicazione RAG
Un percorso eseguibile per un'applicazione con generazione aumentata dal recupero, in due varianti: un'applicazione esistente a scatola nera di cui registri dall'esterno recupero, contesto e citazioni, e un'applicazione a stadi che Oloproof esegue stadio per stadio, così che oloproof diagnose possa rieseguire i casi falliti con modifiche controllate. Entrambe girano in locale senza credenziali di un provider.
I concetti dietro ogni passo (stadi, etichette di rilevanza, contesto gold, le quattro etichette di fallimento) sono nella pagina Valutazione RAG; i termini caso, valutatore, metrica, intervallo e gate sono in Concetti fondamentali. Questa pagina è il percorso pratico attraverso di essi.
Qual è il tuo percorso
| La tua applicazione | Percorso | Che cosa ottieni | Che cosa non ottieni |
|---|---|---|---|
| Una chiamata in ingresso, una risposta in uscita (un servizio, un endpoint HTTP, una catena di un framework che non vuoi dividere) | A, scatola nera | Metriche di recupero, controlli sulle citazioni, giudici di aderenza, gate, confronto | Interventi controllati: diagnose non riesegue nulla |
| Recupero e generazione che puoi chiamare separatamente | B, a stadi | Tutto ciò che offre A, cache per stadio, e diagnose con contesto gold, top-k e un reranker accanto a un controllo | Interventi diversi da quei tre |
Se hai dubbi, parti da A. Non richiede alcuna modifica all'applicazione, e passare a B in seguito conserva dataset, valutatori e policy.
Prerequisiti
- Python 3.11 o successivo, e Oloproof installato (pip install oloproof).
- I progetti di esempio, distribuiti con il pacchetto: blackbox_rag per il percorso A e support_rag per il percorso B. Copiane uno in una nuova directory e lavora lì:
oloproof init --example blackbox_rag my-rag
cd my-ragOgni comando qui sotto si esegue dall'interno della directory copiata. Esecuzioni, giudizi e diagnosi vengono memorizzati lì, in .oloproof/.
Percorso A: un'applicazione esistente come scatola nera
I file
| File | Che cos'è |
|---|---|
| app.py | support_api(question), che fa le veci della tua applicazione, e run(case), l'adattatore |
| server.py | La stessa applicazione via HTTP, per la variante HTTP qui sotto |
| data/corpus.jsonl | La base di conoscenza di 14 passaggi in cui l'applicazione cerca |
| data/support.jsonl | 15 casi: 13 con etichette di rilevanza e passaggi gold, 2 senza né le une né gli altri |
| oloproof.yaml | La suite: dataset, sistema, valutatori, slice |
| oloproof.http.yaml | La stessa suite contro il server HTTP |
| release.yaml | La policy di rilascio per una singola esecuzione |
| compare.yaml | La policy per confrontare un'esecuzione candidata con una baseline |
Che cosa restituisce l'applicazione
support_api si comporta come un'applicazione che hai già: cerca, costruisce un prompt dalle fonti migliori che rientrano in un budget di parole, risponde e cita. La sua risposta contiene già ciò che ha fatto:
{
"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"}]
}I nomi dei campi della tua applicazione saranno diversi. Ciò che conta è che possa dirti, per ogni domanda, le fonti ordinate che ha recuperato, quelle che hanno raggiunto il modello e quelle che ha citato. Se non può, aggiungile prima alla sua risposta o ai suoi log: Oloproof misura ciò che è registrato e non deduce mai il recupero da una risposta.
L'adattatore
run chiama l'applicazione senza modificarla e mappa la risposta su tre artefatti tipizzati, i record letti dai valutatori di recupero e di citazione:
@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"]}| Artefatto | Forma | Letto da |
|---|---|---|
| retrieval/v1 | query, depth e candidates nell'ordine in cui il tuo retriever li ha restituiti, ciascuno un Passage(doc_id, chunk_id, score, text) | hit_rate, recall, mrr, ndcg |
| context/v1 | Gli items che hanno raggiunto il modello (doc_id, position, tokens, text), gli elementi dropped con un reason pari a top_k o token_budget, e token_budget | citation_validity, groundedness_judge, citation_support_judge |
| citations/v1 | ids, ciascuno un doc_id o un doc_id#chunk_id | citation_validity, citation_support_judge |
Oloproof registra le posizioni così come sono date e non riordina mai. Un artefatto malformato ferma l'esecuzione con codice di uscita 2 invece di essere memorizzato. case è l'oggetto input del caso, quindi case["question"] è la domanda presa dal dataset.
Per usare la tua applicazione, sostituisci il corpo di support_api con una chiamata a essa (una chiamata SDK, una richiesta HTTP) e conserva run. Fai puntare system.callable in oloproof.yaml a essa come module:function.
La variante HTTP
Un sistema HTTP non può chiamare il recorder, quindi è la sua risposta a portare l'evidenza, già nelle tre forme qui sopra, e la configurazione indica dove:
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 serve esattamente questo. Avvialo, poi esegui contro di esso:
python server.py 8766
oloproof run --config oloproof.http.yamlL'input del caso viene inviato come corpo JSON. output_path estrae l'output dalla risposta, e ogni voce di artifacts registra un percorso puntato come quel tipo; un campo mancante o malformato ferma l'esecuzione con codice di uscita 2. I risultati sono identici a quelli del percorso callable qui sotto. Nel tuo servizio, l'oggetto di evidenza è di solito un campo di debug che abiliti per il traffico di valutazione.
Che cosa dichiara un caso
{"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 elenca i passaggi che rispondono alla domanda. Le metriche di recupero lo leggono. Un caso che non lo ha, come office_hours, ne è escluso con no_relevance_labels: esce dal denominatore invece di contare come successo o come fallimento.
- expected.gold_context è il testo stesso del passaggio. Il percorso A non lo usa mai; il percorso B lo sostituisce al contesto recuperato durante la diagnosi.
I casi senza etichette sono normali nella pratica, perché etichettare la rilevanza richiede lavoro. Contano comunque per i controlli sulla risposta e sulle citazioni.
Scegliere i valutatori
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 verifica che la risposta contenga il testo atteso. È il controllo del compito: l'utente ha ricevuto la risposta giusta? Usa invece un giudice esatto o a rubrica quando la formulazione varia.
- hit_rate e recall con k: 2 misurano il recupero alla profondità che l'applicazione mette davvero nel prompt. Una metrica di recupero a una profondità che il modello non vede mai descrive l'indice, non l'applicazione.
- citation_validity verifica che ogni id citato nomini un passaggio che ha raggiunto il modello; require_citations: true fa fallire anche una risposta che non cita nulla.
- groundedness_judge e citation_support_judge (facoltativi) chiedono a un modello se la risposta è supportata dal contesto. Richiedono un provider, un modello e credenziali in una variabile d'ambiente, e costano denaro per caso; vedi Giudici per ciò che un giudice deve superare prima di poter fare da gate.
Le slice relevant_position e context_truncated non sono disponibili qui: confrontano le posizioni con il top-k dell'applicazione, che solo un sistema a stadi dichiara. Richiederle ferma l'esecuzione con slice 'relevant_position' compares relevant positions with top_k, so it needs a staged system.
La policy di rilascio
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: 0Una regola min passa solo quando l'intero intervallo supera la soglia minima, fallisce quando l'intero intervallo sta sotto di essa, ed è INSUFFICIENT_EVIDENCE altrimenti. Una regola observed_count decide sui casi effettivamente eseguiti, senza intervallo: "nessuna citazione non valida in questa suite". Vedi Gate.
Eseguila
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 missCome leggerlo:
- Gate: BLOCK (exit 1): una regola è in FAIL. L'uscita 1 indica un FAIL; l'uscita 3 indica che il gate ha bloccato senza un FAIL (qui sarebbe INSUFFICIENT_EVIDENCE); l'uscita 0 indica che non c'è nulla su cui la policy blocca. [DECIDED/COMPLETE] è lo stato di esecuzione: ogni caso è stato eseguito.
- citations-valid è in FAIL: una risposta non ha citato nulla, e require_citations lo conta come non valido.
- answer-floor è INSUFFICIENT_EVIDENCE, non PASS, anche se 73.3% è sopra 70%: con 15 casi l'intervallo scende fino a 44.8%, quindi l'evidenza non può mostrare che la soglia è rispettata.
- hit_rate_at_2 riporta 2 excluded: i due casi senza etichette. Il suo denominatore è 13, non 15.
- La tabella Slices che segue è esplorativa e non fa mai da gate; una slice sotto min_slice_support non mostra alcun intervallo.
Esamina i fallimenti
L'id dell'esecuzione è sulla prima riga dell'output dell'esecuzione.
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 stampa l'input di un caso, i valori attesi, l'output e ogni giudizio. Gli artefatti registrati sono nel bundle esportato:
oloproof export RUN_IDOgni riga di .oloproof/bundles/RUN_ID/cases.jsonl è il record di un caso; il suo campo artifacts contiene ciò che è stato registrato. Per money_back, quel campo riporta:
{"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": []}]}Leggere i quattro fallimenti dalla sola evidenza registrata:
| Caso | Che cosa mostra il record | Una prossima azione sensata |
|---|---|---|
| money_back | Il recupero non ha restituito nulla: la domanda non condivide alcuna parola con il passaggio sui rimborsi | Riscrittura della query o sinonimi, misurati da hit_rate_at_2 |
| refund_review, security_review | hit_rate_at_2 è passato, eppure la risposta proveniva da un altro passaggio | Esamina context/v1: il passaggio rilevante è stato scartato per il budget? |
| seat_count | Il passaggio giusto è stato recuperato, conservato e citato; la risposta dice "five", il caso si aspetta "5" | Correggi l'aspettativa o il formato della risposta, non il recupero |
Quella tabella è la tua lettura del record. È un'associazione tra un fallimento e uno stadio, non una causa dimostrata: nulla ha rieseguito il caso con lo stadio modificato.
Che cosa fa diagnose su una scatola nera
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:8809e100ab2ec1dad8ffeacc136cd510300081a0edf01ec11f881c543ed104bcOgni caso è UNRESOLVED con il motivo intervention_unsupported. Oloproof non può consegnare a una scatola nera il passaggio gold al posto del suo recupero, quindi non finge di farlo. Gli interventi controllati richiedono il percorso B.
Fai una modifica candidata e confronta
Il record dice che money_back è fallito nel recupero. La modifica candidata espande la domanda con sinonimi prima della ricerca. In app.py:
EXPAND_QUERY = TrueModificare il codice cambia la versione del sistema registrata per l'esecuzione. Esegui di nuovo, poi confronta il candidato con la baseline:
oloproof run
oloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy compare.yamlL'esecuzione candidata da sola: citations-valid ora è in PASS, hit_rate_at_2 riporta 100.0% [75.2%, 100.0%], e il gate blocca ancora con uscita 3 perché answer-floor e retrieval-floor restano INSUFFICIENT_EVIDENCE. Il confronto:
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)La modifica ha corretto il caso a cui mirava (una risposta in più, +6.7 punti su 15 casi appaiati). Il confronto non riesce ancora a stabilire che il candidato non sia peggiore della baseline di più del margine: 15 casi appaiati lasciano un intervallo largo circa 67 punti. La riga di pianificazione dice quanti altri casi appaiati lo deciderebbero se la differenza reggesse. La prossima azione è una suite più grande, non un margine diverso. Vedi Confrontare due esecuzioni e Regole di confronto.
Percorso B: un'applicazione a stadi con diagnosi
I file a stadi
Il percorso B esegue l'esempio support_rag, descritto nella pagina Valutazione RAG. Copialo:
oloproof init --example support_rag my-staged-rag
cd my-staged-rag| File | Che cos'è |
|---|---|
| app.py | SupportRag, una classe decorata con @rag_system: retrieve(input, depth), generate(input, context), count_tokens(passage) |
| data/corpus.jsonl, data/support.jsonl | La base di conoscenza, e 13 casi, ciascuno con relevant e gold_context |
| oloproof.yaml | system.rag punta alla classe e imposta depth, top_k, token_budget, index_version |
| release.yaml, compare.yaml | Le stesse policy del percorso A |
La differenza rispetto al percorso A è chi assembla il contesto. Qui Oloproof chiama retrieve, conserva i primi top_k candidati, scarta i passaggi oltre token_budget e passa il resto a generate. Poiché tiene separati gli stadi, può metterli in cache separatamente e rieseguire la generazione con un contesto diverso. Per adattare la tua applicazione, sostituisci i corpi di retrieve (chiama il tuo indice, restituisci Retrieval(candidates=[Passage(...)]) nell'ordine del tuo retriever) e di generate (chiama il tuo modello con i passaggi forniti). Imposta index_version su qualcosa che cambia quando cambia il tuo indice: fa parte dell'identità del recupero, e un valore non aggiornato riusa recuperi in cache contro un indice che non li restituisce più.
La stessa configurazione consente anche le slice relevant_position e context_truncated, e un valutatore ndcg sull'intera profondità di recupero.
Esegui la suite a stadi
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 missLa riga Stages è la cache propria del sistema a stadi. Uscita 3: nulla è in FAIL, ma a due regole manca l'evidenza per il PASS.
Diagnosi con contesto gold, accanto a un controllo
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…Dai casi falliti si creano due esecuzioni figlie: una con il gold_context del caso al posto del contesto recuperato, e un controllo che li riesegue senza modifiche. Il controllo è ciò che rende sicura la lettura: un caso che passa con una semplice riesecuzione era instabile, non diagnosticato. diagnose esce con 0 qualunque cosa trovi; non decide nulla sul rilascio.
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 2Leggere le etichette
| Etichetta | Che cosa è stato osservato | Che cosa non stabilisce |
|---|---|---|
| RETRIEVAL_MISS | Nessun passaggio rilevante è stato recuperato, e il caso è passato con il passaggio gold | Che il recupero sia l'unica cosa sbagliata, o che una data modifica al recupero lo correggerà |
| RANKED_OUT | Un passaggio rilevante è stato recuperato sotto top_k, e il caso è passato con il passaggio gold | Che allargare il top-k aiuterà altri casi |
| CONTEXT_ASSEMBLY_LOSS | Un passaggio rilevante entro il top-k è stato scartato dal contesto, e il caso è passato con il passaggio gold | Quale budget basterebbe |
| GENERATION_FAILURE | Il caso è fallito anche con il passaggio gold a disposizione | Che la colpa sia del modello, e non del prompt o dell'aspettativa |
| UNRESOLVED | Non si è potuto concludere nulla: il sistema non è a stadi (intervention_unsupported), il caso si è ripreso sotto il controllo (unstable_under_control), non ha etichette di rilevanza (no_relevance_labels), oppure manca evidenza | Qualunque cosa riguardo al caso |
Ogni etichetta è un'associazione tra un fallimento e uno stadio sotto un intervento su questi casi. Non è una causa dimostrata: "Implicated" e "Candidate experiment" sono le parole più forti che l'output usa, e i conteggi descrivono solo i casi selezionati ("no population claim"). seat_count è un buon promemoria: fallisce con il passaggio giusto perché la base di conoscenza dice "five" e il caso si aspetta "5", cosa che nessuna modifica al recupero può correggere.
Casi con e senza passaggi gold
Si possono rieseguire solo i casi falliti che dichiarano expected.gold_context. Rimuovi il passaggio gold da seat_count e money_back (e l'etichetta di rilevanza da money_back) e lo stesso comando riporta:
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 contextI casi esclusi vengono elencati, non scartati in silenzio. Nota anche che cosa fa all'esecuzione stessa la rimozione di un'etichetta di rilevanza: hit_rate_at_2 è salito a 100.0% (12 / 12 osservati, 1 escluso), perché l'unico caso mancato dal recupero non viene più misurato. I casi senza etichette escono dal denominatore; non contano come successi, e una metrica su meno casi può sembrare migliore di quanto sia l'applicazione. Etichetta prima i casi difficili.
Prova una correzione prima di farla: top-k e un reranker
Altri due interventi rigiocano il recupero registrato con un'impostazione diversa, quindi il retriever non viene chiamato di nuovo:
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 recoveredUn reranker è una funzione (input, candidates) -> candidates che scrivi tu. Salvala come rerank.py accanto a 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 recoveredNessuno dei due recupera nulla, ed è ciò che le etichette del contesto gold prevedevano: nessun fallimento qui era un passaggio classificato appena sotto il taglio. Ogni riesecuzione porta avanti le etichette del contesto gold, così le diagnosi si leggono insieme.
Esegui l'esperimento indicato dalla diagnosi, e confronta
Porta token_budget a 120 in oloproof.yaml, poi:
oloproof run
oloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy compare.yamlStages: retrieve 13 hit/0 miss; generate 7 hit/6 missOgni recupero è stato riusato, perché top_k e il budget sono fuori dall'identità del recupero; sono stati generati di nuovo solo i sei casi il cui contesto è cambiato.
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)L'esperimento non ha aiutato: nemmeno un caso ha cambiato verdetto, quindi l'ipotesi offerta dalla diagnosi non è supportata per questi casi. È un risultato utile. Il prossimo esperimento sono chunk più piccoli, oppure i prompt dei due casi di assemblaggio del contesto; seat_count ha bisogno che la sua aspettativa venga corretta.
Risoluzione dei problemi
| Sintomo | Causa | Soluzione |
|---|---|---|
| Configuration error: slice 'relevant_position' ... needs a staged system | Una slice di posizione su un sistema callable o HTTP | Rimuovi la slice, o passa al percorso B |
| L'esecuzione si ferma con uscita 2 e malformed retrieval/v1 artifact | Un campo che lo schema non consente, o più candidati di depth | Mappa solo i campi documentati; imposta depth almeno al numero restituito |
| citations_valid riporta 0 / 0 observed · 15 missing e la sua regola è INSUFFICIENT_EVIDENCE con no_observations | L'adattatore non ha registrato citations/v1 (o context/v1); ogni caso di questo tipo è mancante, non passato | Registra entrambi su ogni percorso dell'adattatore, compreso "nessuna risposta"; oloproof inspect RUN_ID --failures mostra l'errore per caso |
| Una metrica di recupero mostra molti excluded | Casi senza expected.relevant | Etichettali, o accetta consapevolmente il denominatore più piccolo |
| diagnose dice UNRESOLVED ... not staged | Percorso A | Previsto; usa il percorso B per gli interventi |
| diagnose rifiuta con an intervention must re-execute the same system | Il codice o la configurazione sono cambiati dopo l'esecuzione | Diagnostica un'esecuzione della versione attuale, o ripristina la versione che è stata eseguita |
| La diagnosi seleziona meno casi di quelli falliti | Casi falliti senza expected.gold_context | Aggiungi i passaggi gold; i casi esclusi sono nominati nell'output |
| I recuperi vengono riusati dopo che l'indice è cambiato | index_version non modificato | Cambia index_version quando cambia l'indice |
Limitazioni
- Oloproof chiama la tua applicazione; non la ospita, non la isola in una sandbox e non la reimposta. Il suo indice, le sue cache e qualsiasi stato conservi sono tuoi.
- Su una scatola nera gli interventi non sono disponibili: diagnose etichetta ogni caso come UNRESOLVED e non riesegue nulla.
- Gli interventi sono contesto gold, top-k e un reranker. Non esiste alcun intervento su chunking, embedding o prompt.
- Le etichette di diagnosi descrivono i casi falliti selezionati sotto un intervento accanto a un controllo. Associano un fallimento a uno stadio; non dimostrano una causa, e non affermano nulla sui casi non selezionati.
- Le metriche di recupero richiedono etichette di rilevanza, e la diagnosi richiede passaggi gold; Oloproof non crea né le une né gli altri.
- Gli esempi deterministici fanno le veci di un retriever e di un modello reali. Un modello reale in generate o un valutatore giudice chiama un provider, richiede credenziali e costa denaro per caso.
- Che cosa funziona dove, SDK rispetto a YAML rispetto a browser, è in Che cosa funziona oggi.