Guides
Tutoriel : évaluer une application RAG
Un parcours exécutable pour une application augmentée par la recherche, selon deux chemins : une application boîte noire existante dont vous enregistrez de l'extérieur la récupération, le contexte et les citations, et une application en étapes qu'Oloproof exécute étape par étape pour que oloproof diagnose puisse réexécuter les cas en échec sous des modifications contrôlées. Les deux s'exécutent en local sans identifiants de fournisseur.
Les concepts derrière chaque étape (étapes, étiquettes de pertinence, contexte de référence, les quatre étiquettes d'échec) se trouvent sur la page Évaluation RAG ; les termes cas, évaluateur, métrique, intervalle et porte sont dans Concepts fondamentaux. Cette page est le parcours pratique à travers eux.
Quel chemin est le vôtre
| Votre application | Chemin | Ce que vous obtenez | Ce que vous n'obtenez pas |
|---|---|---|---|
| Un appel en entrée, une réponse en sortie (un service, un point de terminaison HTTP, une chaîne de framework que vous ne voulez pas découper) | A, boîte noire | Métriques de récupération, vérifications de citations, juges d'ancrage, porte, comparaison | Interventions contrôlées : diagnose ne réexécute rien |
| Une récupération et une génération que vous pouvez appeler séparément | B, en étapes | Tout ce qu'offre A, un cache par étape, et diagnose avec le contexte de référence, le top-k et un reclasseur à côté d'un témoin | D'autres interventions que ces trois-là |
Commencez par A en cas de doute. Il ne nécessite aucune modification de l'application, et passer à B plus tard conserve le jeu de données, les évaluateurs et la politique.
Prérequis
- Python 3.11 ou ultérieur, et Oloproof installé (pip install oloproof).
- Les projets d'exemple, livrés avec le paquet : blackbox_rag pour le chemin A et support_rag pour le chemin B. Copiez-en un dans un nouveau répertoire et travaillez-y :
oloproof init --example blackbox_rag my-rag
cd my-ragChaque commande ci-dessous s'exécute depuis le répertoire copié. Les exécutions, jugements et diagnostics sont stockés dans son .oloproof/.
Chemin A : une application existante comme boîte noire
Les fichiers
| Fichier | Ce que c'est |
|---|---|
| app.py | support_api(question), qui tient lieu de votre application, et run(case), l'adaptateur |
| server.py | La même application en HTTP, pour la variante HTTP ci-dessous |
| data/corpus.jsonl | La base de connaissances de 14 passages dans laquelle l'application cherche |
| data/support.jsonl | 15 cas : 13 avec étiquettes de pertinence et passages de référence, 2 sans l'un ni l'autre |
| oloproof.yaml | La suite : jeu de données, système, évaluateurs, segments |
| oloproof.http.yaml | La même suite contre le serveur HTTP |
| release.yaml | La politique de publication pour une seule exécution |
| compare.yaml | La politique pour comparer une exécution candidate à une référence |
Ce que renvoie l'application
support_api se comporte comme une application que vous avez déjà : elle cherche, construit un prompt à partir des meilleures sources qui tiennent dans un budget de mots, répond et cite. Sa réponse porte déjà ce qu'elle a fait :
{
"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"}]
}Les noms de champs de votre application seront différents. Ce qui compte, c'est qu'elle puisse vous dire, pour chaque question, les sources classées qu'elle a récupérées, celles qui ont atteint le modèle et celles qu'elle a citées. Si elle ne le peut pas, ajoutez-les d'abord à sa réponse ou à ses journaux : Oloproof mesure ce qui est enregistré et ne déduit jamais la récupération d'une réponse.
L'adaptateur
run appelle l'application sans la modifier et projette la réponse sur trois artefacts typés, les enregistrements que lisent les évaluateurs de récupération et de citation :
@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 | Forme | Lu par |
|---|---|---|
| retrieval/v1 | query, depth, et candidates dans l'ordre où votre système de récupération les a renvoyés, chacun un Passage(doc_id, chunk_id, score, text) | hit_rate, recall, mrr, ndcg |
| context/v1 | les items qui ont atteint le modèle (doc_id, position, tokens, text), les éléments dropped avec une reason valant top_k ou token_budget, et token_budget | citation_validity, groundedness_judge, citation_support_judge |
| citations/v1 | ids, chacun un doc_id ou doc_id#chunk_id | citation_validity, citation_support_judge |
Oloproof enregistre les positions telles quelles et ne reclasse jamais. Un artefact mal formé arrête l'exécution avec le code de sortie 2 au lieu d'être stocké. case est l'objet input du cas, donc case["question"] est la question du jeu de données.
Pour utiliser votre propre application, remplacez le corps de support_api par un appel à celle-ci (un appel de SDK, une requête HTTP) et gardez run. Faites pointer system.callable dans oloproof.yaml vers elle sous la forme module:function.
La variante HTTP
Un système HTTP ne peut pas appeler l'enregistreur, donc sa réponse porte les preuves à la place, déjà sous les trois formes ci-dessus, et la configuration indique où :
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 sert exactement cela. Démarrez-le, puis exécutez contre lui :
python server.py 8766
oloproof run --config oloproof.http.yamlL'entrée du cas est envoyée comme corps JSON. output_path extrait la sortie de la réponse, et chaque entrée artifacts enregistre un chemin pointé comme ce type ; un champ absent ou mal formé arrête l'exécution avec le code de sortie 2. Les résultats sont identiques au chemin par appelable ci-dessous. Dans votre propre service, l'objet de preuves est généralement un champ de débogage que vous activez pour le trafic d'évaluation.
Ce que déclare un cas
{"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 liste les passages qui répondent à la question. Les métriques de récupération le lisent. Un cas qui ne l'a pas, comme office_hours, en est exclu avec no_relevance_labels : il sort du dénominateur au lieu de compter comme une réussite ou un échec.
- expected.gold_context est le texte du passage lui-même. Le chemin A ne l'utilise jamais ; le chemin B le substitue au contexte récupéré pendant le diagnostic.
Les cas sans étiquette sont normaux en pratique, car étiqueter la pertinence demande du travail. Ils comptent tout de même pour les vérifications de réponse et de citation.
Choisir les évaluateurs
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 vérifie que la réponse contient le texte attendu. C'est la vérification de la tâche : l'utilisateur a-t-il obtenu la bonne réponse. Utilisez plutôt un juge exact ou à grille quand la formulation varie.
- hit_rate et recall à k: 2 mesurent la récupération à la profondeur que l'application met réellement dans le prompt. Une métrique de récupération à une profondeur que le modèle ne voit jamais décrit l'index, pas l'application.
- citation_validity vérifie que chaque identifiant cité désigne un passage qui a atteint le modèle ; require_citations: true fait aussi échouer une réponse qui ne cite rien.
- groundedness_judge et citation_support_judge (facultatifs) demandent à un modèle si la réponse est étayée par le contexte. Ils nécessitent un fournisseur, un modèle et des identifiants dans une variable d'environnement, et coûtent de l'argent par cas ; voir Juges pour ce qu'un juge doit franchir avant de pouvoir servir de porte.
Les segments relevant_position et context_truncated ne sont pas disponibles ici : ils comparent les positions au top-k de l'application, que seul un système en étapes déclare. Les demander arrête l'exécution avec slice 'relevant_position' compares relevant positions with top_k, so it needs a staged system.
La politique de publication
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: 0Une règle min ne passe que lorsque tout l'intervalle franchit le plancher, échoue lorsque tout l'intervalle se situe en dessous, et vaut INSUFFICIENT_EVIDENCE sinon. Une règle observed_count décide sur les cas réellement exécutés, sans intervalle : « aucune citation invalide dans cette suite ». Voir Porte de CI.
L'exécuter
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 missComment le lire :
- Gate: BLOCK (exit 1) : une règle a donné FAIL. La sortie 1 signifie un FAIL ; la sortie 3 signifie que la porte a bloqué sans FAIL (ici ce serait INSUFFICIENT_EVIDENCE) ; la sortie 0 signifie rien sur quoi la politique bloque. [DECIDED/COMPLETE] est l'état d'exécution : chaque cas a été exécuté.
- citations-valid donne FAIL : une réponse ne citait rien, et require_citations compte cela comme invalide.
- answer-floor vaut INSUFFICIENT_EVIDENCE, pas PASS, bien que 73.3 % dépasse 70 % : avec 15 cas, l'intervalle descend jusqu'à 44.8 %, donc les preuves ne peuvent pas montrer que le plancher est atteint.
- hit_rate_at_2 indique 2 excluded : les deux cas sans étiquette. Son dénominateur est 13, pas 15.
- La table Slices qui suit est exploratoire et ne sert jamais de porte ; un segment sous min_slice_support n'affiche pas d'intervalle.
Inspecter les échecs
L'identifiant de l'exécution figure sur la première ligne de sa sortie.
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 affiche l'entrée, les valeurs attendues, la sortie et chaque jugement d'un cas. Les artefacts enregistrés se trouvent dans le paquet exporté :
oloproof export RUN_IDChaque ligne de .oloproof/bundles/RUN_ID/cases.jsonl est l'enregistrement d'un cas ; son champ artifacts contient ce qui a été enregistré. Pour money_back, ce champ indique :
{"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": []}]}Lecture des quatre échecs à partir des seules preuves enregistrées :
| Cas | Ce que montre l'enregistrement | Une action suivante pertinente |
|---|---|---|
| money_back | La récupération n'a rien renvoyé : la question ne partage aucun mot avec le passage sur les remboursements | Réécriture de requête ou synonymes, mesurés par hit_rate_at_2 |
| refund_review, security_review | hit_rate_at_2 a réussi, mais la réponse venait d'un autre passage | Inspecter context/v1 : le passage pertinent a-t-il été retiré pour le budget ? |
| seat_count | Le bon passage a été récupéré, conservé et cité ; la réponse dit « five », le cas attend « 5 » | Corriger l'attente ou le format de la réponse, pas la récupération |
Ce tableau est votre lecture de l'enregistrement. C'est une association entre un échec et une étape, pas une cause démontrée : rien n'a réexécuté le cas avec l'étape modifiée.
Ce que fait diagnose sur une boîte noire
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:8809e100ab2ec1dad8ffeacc136cd510300081a0edf01ec11f881c543ed104bcChaque cas est UNRESOLVED avec la raison intervention_unsupported. Oloproof ne peut pas donner à une boîte noire le passage de référence à la place de sa propre récupération, il ne fait donc pas semblant. Les interventions contrôlées nécessitent le chemin B.
Faire une modification candidate et comparer
L'enregistrement indique que money_back a échoué à la récupération. La modification candidate enrichit la question de synonymes avant la recherche. Dans app.py :
EXPAND_QUERY = TrueModifier le code change la version du système enregistrée pour l'exécution. Exécutez à nouveau, puis comparez le candidat à la référence :
oloproof run
oloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy compare.yamlL'exécution candidate seule : citations-valid donne désormais PASS, hit_rate_at_2 indique 100.0 % [75.2 %, 100.0 %], et la porte bloque toujours avec la sortie 3 car answer-floor et retrieval-floor restent INSUFFICIENT_EVIDENCE. La comparaison :
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 modification a corrigé le cas visé (une réponse de plus, +6.7 points sur 15 cas appariés). La comparaison ne peut toujours pas établir que le candidat n'est pas pire que la référence de plus que la marge : 15 cas appariés laissent un intervalle large d'environ 67 points. La ligne de planification indique combien de cas appariés supplémentaires trancheraient si la différence se maintenait. Une suite plus grande, et non une marge différente, est l'action suivante. Voir Comparer un candidat à une référence et Règles de comparaison.
Chemin B : une application en étapes avec diagnostic
Les fichiers en étapes
Le chemin B exécute l'exemple support_rag, décrit sur la page Évaluation RAG. Copiez-le :
oloproof init --example support_rag my-staged-rag
cd my-staged-rag| Fichier | Ce que c'est |
|---|---|
| app.py | SupportRag, une classe décorée avec @rag_system : retrieve(input, depth), generate(input, context), count_tokens(passage) |
| data/corpus.jsonl, data/support.jsonl | La base de connaissances, et 13 cas, chacun avec relevant et gold_context |
| oloproof.yaml | system.rag pointe vers la classe et fixe depth, top_k, token_budget, index_version |
| release.yaml, compare.yaml | Les mêmes politiques que pour le chemin A |
La différence avec le chemin A tient à qui assemble le contexte. Ici, Oloproof appelle retrieve, garde les top_k premiers candidats, retire les passages au-delà de token_budget et passe le reste à generate. Parce qu'il tient les étapes séparées, il peut les mettre en cache séparément et réexécuter la génération avec un autre contexte. Pour adapter votre propre application, remplacez les corps de retrieve (appelez votre index, renvoyez Retrieval(candidates=[Passage(...)]) dans l'ordre de votre système de récupération) et de generate (appelez votre modèle avec les passages fournis). Donnez à index_version une valeur qui change quand votre index change : elle fait partie de l'identité de la récupération, et une valeur périmée réutilise des récupérations en cache contre un index qui ne les renvoie plus.
La même configuration autorise aussi les segments relevant_position et context_truncated, et un évaluateur ndcg sur toute la profondeur de récupération.
Exécuter la suite en étapes
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 ligne Stages est le cache propre du système en étapes. Sortie 3 : rien n'a donné FAIL, mais deux règles manquent de preuves pour donner PASS.
Diagnostiquer avec le contexte de référence, à côté d'un témoin
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…Deux exécutions filles sont créées à partir des cas en échec : l'une avec le gold_context du cas à la place du contexte récupéré, et un témoin qui les réexécute sans changement. Le témoin est ce qui rend la lecture sûre : un cas qui réussit lors d'une simple réexécution était instable, pas diagnostiqué. diagnose se termine avec 0 quoi qu'il trouve ; il ne décide rien sur la publication.
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 2Lire les étiquettes
| Étiquette | Ce qui a été observé | Ce qu'elle n'établit pas |
|---|---|---|
| RETRIEVAL_MISS | Aucun passage pertinent n'a été récupéré, et le cas a réussi avec le passage de référence | Que la récupération soit la seule chose qui cloche, ou qu'une modification donnée de la récupération le corrigera |
| RANKED_OUT | Un passage pertinent a été récupéré sous top_k, et le cas a réussi avec le passage de référence | Qu'élargir le top-k aidera d'autres cas |
| CONTEXT_ASSEMBLY_LOSS | Un passage pertinent dans le top-k a été retiré du contexte, et le cas a réussi avec le passage de référence | Quel budget suffirait |
| GENERATION_FAILURE | Le cas a encore échoué avec le passage de référence en main | Que le modèle, plutôt que le prompt ou l'attente, soit en faute |
| UNRESOLVED | Rien n'a pu être conclu : le système n'est pas en étapes (intervention_unsupported), le cas a été récupéré sous le témoin (unstable_under_control), il n'a pas d'étiquettes de pertinence (no_relevance_labels), ou des preuves manquent | Quoi que ce soit sur le cas |
Chaque étiquette est une association entre un échec et une étape sous une intervention sur ces cas. Ce n'est pas une cause démontrée : « Implicated » et « Candidate experiment » sont les mots les plus forts qu'emploie la sortie, et les comptes ne décrivent que les cas sélectionnés (« no population claim »). seat_count est un bon rappel : il échoue avec le bon passage parce que la base de connaissances dit « five » et que le cas attend « 5 », ce qu'aucune modification de la récupération ne peut corriger.
Cas avec et sans passages de référence
Seuls les cas en échec qui déclarent expected.gold_context peuvent être réexécutés. Retirez le passage de référence de seat_count et de money_back (et l'étiquette de pertinence de money_back) et la même commande rapporte :
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 contextLes cas exclus sont listés, pas retirés en silence. Notez aussi ce que retirer une étiquette de pertinence fait à l'exécution elle-même : hit_rate_at_2 est monté à 100.0 % (12 / 12 observés, 1 exclu), car le seul cas que la récupération manquait n'est plus mesuré. Les cas sans étiquette sortent du dénominateur ; ils ne comptent pas comme des réussites, et une métrique sur moins de cas peut paraître meilleure que l'application ne l'est. Étiquetez d'abord les cas difficiles.
Tester une correction avant de la faire : top-k et un reclasseur
Deux autres interventions rejouent la récupération enregistrée avec un réglage différent, de sorte que le système de récupération n'est pas rappelé :
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 reclasseur est une fonction (input, candidates) -> candidates que vous écrivez. Enregistrez-la sous rerank.py à côté de 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 recoveredAucune ne récupère quoi que ce soit, ce que les étiquettes du contexte de référence prédisaient : aucun échec ici n'était un passage classé juste sous la coupure. Chaque rejeu reporte les étiquettes du contexte de référence, de sorte que les diagnostics se lisent ensemble.
Mener l'expérience que le diagnostic a nommée, et comparer
Portez token_budget à 120 dans oloproof.yaml, puis :
oloproof run
oloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy compare.yamlStages: retrieve 13 hit/0 miss; generate 7 hit/6 missChaque récupération a été réutilisée, car top_k et le budget sont hors de l'identité de la récupération ; seuls les six cas dont le contexte a changé ont été générés à nouveau.
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'expérience n'a pas aidé : aucun cas n'a changé de verdict, donc l'hypothèse proposée par le diagnostic n'est pas étayée pour ces cas. C'est un résultat utile. L'expérience suivante porte sur des fragments plus petits, ou sur les prompts des deux cas d'assemblage du contexte ; seat_count a besoin que son attente soit corrigée.
Dépannage
| Symptôme | Cause | Correction |
|---|---|---|
| Configuration error: slice 'relevant_position' ... needs a staged system | Un segment de position sur un système appelable ou HTTP | Retirez le segment, ou passez au chemin B |
| L'exécution s'arrête avec la sortie 2 et malformed retrieval/v1 artifact | Un champ que le schéma n'autorise pas, ou plus de candidats que depth | Ne projetez que les champs documentés ; fixez depth au moins au nombre renvoyé |
| citations_valid indique 0 / 0 observed · 15 missing et sa règle vaut INSUFFICIENT_EVIDENCE avec no_observations | L'adaptateur n'a pas enregistré citations/v1 (ou context/v1) ; chaque cas concerné est manquant, pas réussi | Enregistrez les deux sur chaque chemin de l'adaptateur, y compris « pas de réponse » ; oloproof inspect RUN_ID --failures montre l'erreur par cas |
| Une métrique de récupération montre beaucoup d'excluded | Des cas sans expected.relevant | Étiquetez-les, ou acceptez sciemment le dénominateur plus petit |
| diagnose indique UNRESOLVED ... not staged | Chemin A | Attendu ; utilisez le chemin B pour les interventions |
| diagnose refuse avec an intervention must re-execute the same system | Le code ou la configuration a changé depuis l'exécution | Diagnostiquez une exécution de la version actuelle, ou restaurez la version exécutée |
| Le diagnostic sélectionne moins de cas qu'il n'y a d'échecs | Des cas en échec sans expected.gold_context | Ajoutez les passages de référence ; les cas exclus sont nommés dans la sortie |
| Des récupérations sont réutilisées après un changement d'index | index_version inchangé | Changez index_version quand l'index change |
Limites
- Oloproof appelle votre application ; il ne l'héberge pas, ne l'isole pas et ne la réinitialise pas. Son index, ses caches et tout état qu'elle conserve vous appartiennent.
- Sur une boîte noire, les interventions ne sont pas disponibles : diagnose étiquette chaque cas UNRESOLVED et ne réexécute rien.
- Les interventions sont le contexte de référence, le top-k et un reclasseur. Il n'y a pas d'intervention sur le découpage, les plongements ou le prompt.
- Les étiquettes de diagnostic décrivent les cas en échec sélectionnés sous une intervention à côté d'un témoin. Elles associent un échec à une étape ; elles ne démontrent pas une cause, et n'affirment rien sur les cas non sélectionnés.
- Les métriques de récupération nécessitent des étiquettes de pertinence, et le diagnostic nécessite des passages de référence ; Oloproof ne crée ni les unes ni les autres.
- Les exemples déterministes tiennent lieu d'un vrai système de récupération et d'un vrai modèle. Un modèle réel dans generate ou un évaluateur juge appelle un fournisseur, nécessite des identifiants et coûte de l'argent par cas.
- Ce qui fonctionne où, SDK face au YAML face au navigateur, se trouve sur Ce qui fonctionne aujourd'hui.