Guias
Tutorial: avalie uma aplicação RAG
Um passo a passo executável para uma aplicação aumentada por recuperação, em dois caminhos: uma aplicação caixa-preta existente cuja recuperação, contexto e citações você registra de fora, e uma aplicação em etapas que o Oloproof executa etapa por etapa para que oloproof diagnose possa reexecutar os casos que falharam sob mudanças controladas. Ambos rodam localmente, sem credenciais de provedor.
Os conceitos por trás de cada passo (etapas, rótulos de relevância, contexto ouro, os quatro rótulos de falha) estão na página Avaliação de RAG; os termos caso, avaliador, métrica, intervalo e gate estão em Conceitos básicos. Esta página é o caminho prático por eles.
Qual caminho é o seu
| Sua aplicação | Caminho | O que você obtém | O que você não obtém |
|---|---|---|---|
| Uma chamada entra, uma resposta sai (um serviço, um endpoint HTTP, uma cadeia de framework que você não quer dividir) | A, caixa-preta | Métricas de recuperação, verificações de citação, juízes de fundamentação, gate, comparação | Intervenções controladas: diagnose não reexecuta nada |
| Recuperação e geração que você pode chamar separadamente | B, em etapas | Tudo de A, cache por etapa, e diagnose com contexto ouro, top-k e um reranker ao lado de um controle | Intervenções além dessas três |
Comece por A se estiver em dúvida. Ele não exige mudança na aplicação, e passar para B depois mantém o dataset, os avaliadores e a política.
Pré-requisitos
- Python 3.11 ou posterior, e o Oloproof instalado (pip install oloproof).
- Os projetos de exemplo, que vêm com o pacote: blackbox_rag para o caminho A e support_rag para o caminho B. Copie um para um diretório novo e trabalhe nele:
oloproof init --example blackbox_rag my-rag
cd my-ragTodos os comandos abaixo rodam de dentro do diretório copiado. Execuções, julgamentos e diagnósticos ficam armazenados em .oloproof/ ali.
Caminho A: uma aplicação existente como caixa-preta
Os arquivos
| Arquivo | O que é |
|---|---|
| app.py | support_api(question), no lugar da sua aplicação, e run(case), o adaptador |
| server.py | A mesma aplicação por HTTP, para a variante HTTP abaixo |
| data/corpus.jsonl | A base de conhecimento de 14 passagens que a aplicação pesquisa |
| data/support.jsonl | 15 casos: 13 com rótulos de relevância e passagens ouro, 2 sem nenhum dos dois |
| oloproof.yaml | A suíte: dataset, sistema, avaliadores, segmentos |
| oloproof.http.yaml | A mesma suíte contra o servidor HTTP |
| release.yaml | A política de lançamento para uma única execução |
| compare.yaml | A política para comparar uma execução candidata com uma linha de base |
O que a aplicação retorna
support_api se comporta como uma aplicação que você já tem: ela pesquisa, monta um prompt a partir das melhores fontes que cabem num orçamento de palavras, responde e cita. A resposta dela já traz o que ela fez:
{
"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"}]
}Os nomes de campo da sua aplicação serão outros. O que importa é que ela consiga informar, por pergunta, as fontes ranqueadas que recuperou, as que chegaram ao modelo e as que citou. Se não conseguir, acrescente isso à resposta ou aos logs dela primeiro: o Oloproof mede o que está registrado e nunca infere a recuperação a partir de uma resposta.
O adaptador
run chama a aplicação sem alterações e mapeia a resposta em três artefatos tipados, os registros que os avaliadores de recuperação e de citação leem:
@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"]}| Artefato | Forma | Lido por |
|---|---|---|
| retrieval/v1 | query, depth e candidates na ordem em que o seu recuperador os retornou, cada um um Passage(doc_id, chunk_id, score, text) | hit_rate, recall, mrr, ndcg |
| context/v1 | items que chegaram ao modelo (doc_id, position, tokens, text), itens dropped com um reason de top_k ou token_budget, e token_budget | citation_validity, groundedness_judge, citation_support_judge |
| citations/v1 | ids, cada um um doc_id ou doc_id#chunk_id | citation_validity, citation_support_judge |
O Oloproof registra as posições como foram dadas e nunca reordena. Um artefato malformado interrompe a execução com código de saída 2 em vez de ser armazenado. case é o objeto input do caso, então case["question"] é a pergunta do dataset.
Para usar a sua própria aplicação, substitua o corpo de support_api por uma chamada a ela (uma chamada de SDK, uma requisição HTTP) e mantenha run. Aponte system.callable em oloproof.yaml para ela como module:function.
A variante HTTP
Um sistema HTTP não consegue chamar o registrador, então a resposta dele traz a evidência no lugar, já nas três formas acima, e a configuração indica onde:
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 exatamente isso. Inicie-o e depois execute contra ele:
python server.py 8766
oloproof run --config oloproof.http.yamlA entrada do caso é enviada como corpo JSON. output_path extrai a saída da resposta, e cada entrada de artifacts registra um caminho pontuado como aquele tipo; um campo ausente ou malformado interrompe a execução com código de saída 2. Os resultados são idênticos aos do caminho por callable abaixo. No seu próprio serviço, o objeto de evidência costuma ser um campo de depuração que você ativa para o tráfego de avaliação.
O que um caso declara
{"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 lista as passagens que respondem à pergunta. As métricas de recuperação o leem. Um caso sem ele, como office_hours, é excluído delas com no_relevance_labels: sai do denominador em vez de contar como aprovação ou falha.
- expected.gold_context é o próprio texto da passagem. O caminho A nunca o usa; o caminho B o coloca no lugar do contexto recuperado durante o diagnóstico.
Casos sem rótulo são normais na prática, já que rotular relevância dá trabalho. Eles continuam contando para as verificações de resposta e de citação.
Escolhendo avaliadores
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 se a resposta contém o texto esperado. É a verificação da tarefa: o usuário recebeu a resposta certa. Use um juiz exato ou de rubrica quando a redação variar.
- hit_rate e recall com k: 2 medem a recuperação na profundidade que a aplicação de fato coloca no prompt. Uma métrica de recuperação numa profundidade que o modelo nunca vê descreve o índice, não a aplicação.
- citation_validity verifica se todo id citado nomeia uma passagem que chegou ao modelo; require_citations: true também reprova uma resposta que não cita nada.
- groundedness_judge e citation_support_judge (opcionais) perguntam a um modelo se a resposta é sustentada pelo contexto. Eles precisam de um provedor, um modelo e credenciais numa variável de ambiente, e custam dinheiro por caso; veja Juízes para o que um juiz precisa cumprir antes de poder decidir um gate.
Os segmentos relevant_position e context_truncated não estão disponíveis aqui: eles comparam posições com o top-k da aplicação, que só um sistema em etapas declara. Pedi-los interrompe a execução com slice 'relevant_position' compares relevant positions with top_k, so it needs a staged system.
A política de lançamento
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: 0Uma regra min só passa quando o intervalo inteiro fica acima do piso, falha quando o intervalo inteiro fica abaixo dele, e é INSUFFICIENT_EVIDENCE caso contrário. Uma regra observed_count decide sobre os casos de fato executados, sem intervalo: "nenhuma citação inválida nesta suíte". Veja Gate.
Execute
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 missComo ler:
- Gate: BLOCK (exit 1): uma regra deu FAIL. Saída 1 significa um FAIL; saída 3 significa que o gate bloqueou sem um FAIL (aqui seria INSUFFICIENT_EVIDENCE); saída 0 significa nada em que a política bloqueia. [DECIDED/COMPLETE] é o estado de execução: todos os casos rodaram.
- citations-valid dá FAIL: uma resposta não citou nada, e require_citations conta isso como inválido.
- answer-floor é INSUFFICIENT_EVIDENCE, não PASS, embora 73.3% esteja acima de 70%: com 15 casos o intervalo desce até 44.8%, então a evidência não consegue mostrar que o piso foi atingido.
- hit_rate_at_2 mostra 2 excluded: os dois casos sem rótulo. O denominador dele é 13, não 15.
- A tabela Slices que vem a seguir é exploratória e nunca entra no gate; um segmento abaixo de min_slice_support não mostra intervalo.
Inspecione as falhas
O id da execução está na primeira linha da saída da execução.
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 imprime a entrada, os valores esperados, a saída e todos os julgamentos de um caso. Os artefatos registrados estão no pacote exportado:
oloproof export RUN_IDCada linha de .oloproof/bundles/RUN_ID/cases.jsonl é o registro de um caso; o campo artifacts dele guarda o que foi registrado. Para money_back, esse campo diz:
{"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": []}]}Lendo as quatro falhas apenas a partir da evidência registrada:
| Caso | O que o registro mostra | Uma próxima ação com sentido |
|---|---|---|
| money_back | A recuperação não retornou nada: a pergunta não compartilha nenhuma palavra com a passagem de reembolso | Reescrita da consulta ou sinônimos, medidos por hit_rate_at_2 |
| refund_review, security_review | hit_rate_at_2 passou, mas a resposta veio de outra passagem | Inspecione context/v1: a passagem relevante foi descartada por causa do orçamento? |
| seat_count | A passagem certa foi recuperada, mantida e citada; a resposta diz "five", o caso espera "5" | Corrija a expectativa ou o formato da resposta, não a recuperação |
Essa tabela é a sua leitura do registro. É uma associação entre uma falha e uma etapa, não uma causa comprovada: nada reexecutou o caso com a etapa alterada.
O que diagnose faz numa caixa-preta
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:8809e100ab2ec1dad8ffeacc136cd510300081a0edf01ec11f881c543ed104bcTodo caso fica UNRESOLVED com o motivo intervention_unsupported. O Oloproof não consegue entregar a uma caixa-preta a passagem ouro no lugar da recuperação dela, então não finge que consegue. Intervenções controladas precisam do caminho B.
Faça uma mudança candidata e compare
O registro diz que money_back falhou na recuperação. A mudança candidata expande a pergunta com sinônimos antes de pesquisar. Em app.py:
EXPAND_QUERY = TrueMudar o código muda a versão do sistema registrada para a execução. Execute de novo e depois compare a candidata com a linha de base:
oloproof run
oloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy compare.yamlA execução candidata sozinha: citations-valid agora dá PASS, hit_rate_at_2 mostra 100.0% [75.2%, 100.0%], e o gate continua bloqueando com saída 3 porque answer-floor e retrieval-floor seguem INSUFFICIENT_EVIDENCE. A comparação:
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)A mudança corrigiu o caso que visava (uma resposta a mais, +6.7 pontos sobre 15 casos pareados). A comparação ainda não consegue estabelecer que a candidata não é pior que a linha de base por mais que a margem: 15 casos pareados deixam um intervalo de cerca de 67 pontos de largura. A linha de planejamento diz quantos casos pareados a mais decidiriam a questão se a diferença se mantivesse. Uma suíte maior, não uma margem diferente, é a próxima ação. Veja Comparar duas execuções e Regras de comparação.
Caminho B: uma aplicação em etapas com diagnóstico
Os arquivos em etapas
O caminho B executa o exemplo support_rag, descrito na página Avaliação de RAG. Copie-o:
oloproof init --example support_rag my-staged-rag
cd my-staged-rag| Arquivo | O que é |
|---|---|
| app.py | SupportRag, uma classe decorada com @rag_system: retrieve(input, depth), generate(input, context), count_tokens(passage) |
| data/corpus.jsonl, data/support.jsonl | A base de conhecimento e 13 casos, cada um com relevant e gold_context |
| oloproof.yaml | system.rag aponta para a classe e define depth, top_k, token_budget, index_version |
| release.yaml, compare.yaml | As mesmas políticas do caminho A |
A diferença em relação ao caminho A é quem monta o contexto. Aqui o Oloproof chama retrieve, mantém os primeiros top_k candidatos, descarta as passagens que passam de token_budget e entrega o resto a generate. Como ele mantém as etapas separadas, pode fazer cache delas separadamente e reexecutar a geração com outro contexto. Para adaptar a sua própria aplicação, substitua os corpos de retrieve (chame o seu índice, retorne Retrieval(candidates=[Passage(...)]) na ordem do seu recuperador) e de generate (chame o seu modelo com as passagens dadas). Defina index_version com algo que mude quando o seu índice mudar: ele faz parte da identidade da recuperação, e um valor desatualizado reutiliza recuperações em cache contra um índice que não as retorna mais.
A mesma configuração também permite os segmentos relevant_position e context_truncated, e um avaliador ndcg sobre toda a profundidade de recuperação.
Execute a suíte em etapas
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 missA linha Stages é o cache próprio do sistema em etapas. Saída 3: nada deu FAIL, mas duas regras não têm evidência para dar PASS.
Diagnostique com contexto ouro, ao lado de um 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…Duas execuções filhas são feitas a partir dos casos que falharam: uma com o gold_context do caso no lugar do contexto recuperado, e um controle que os reexecuta sem alterações. O controle é o que torna a leitura segura: um caso que passa numa simples reexecução era instável, não diagnosticado. diagnose sai com 0 seja o que for que encontre; ele não decide nada sobre o lançamento.
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 2Lendo os rótulos
| Rótulo | O que foi observado | O que ele não estabelece |
|---|---|---|
| RETRIEVAL_MISS | Nenhuma passagem relevante foi recuperada, e o caso passou com a passagem ouro | Que a recuperação é a única coisa errada, ou que uma dada mudança na recuperação vai corrigi-la |
| RANKED_OUT | Uma passagem relevante foi recuperada abaixo de top_k, e o caso passou com a passagem ouro | Que ampliar o top-k vai ajudar outros casos |
| CONTEXT_ASSEMBLY_LOSS | Uma passagem relevante dentro do top-k foi descartada do contexto, e o caso passou com a passagem ouro | Qual orçamento seria suficiente |
| GENERATION_FAILURE | O caso falhou mesmo com a passagem ouro em mãos | Que a culpa é do modelo, e não do prompt ou da expectativa |
| UNRESOLVED | Nada pôde ser concluído: o sistema não está em etapas (intervention_unsupported), o caso se recuperou sob o controle (unstable_under_control), ele não tem rótulos de relevância (no_relevance_labels), ou falta evidência | Nada sobre o caso |
Todo rótulo é uma associação entre uma falha e uma etapa sob uma intervenção nestes casos. Não é uma causa comprovada: "Implicated" e "Candidate experiment" são as palavras mais fortes que a saída usa, e as contagens descrevem apenas os casos selecionados ("no population claim"). seat_count é um bom lembrete: ele falha com a passagem certa porque a base de conhecimento diz "five" e o caso espera "5", o que nenhuma mudança na recuperação consegue corrigir.
Casos com e sem passagens ouro
Só os casos que falharam e declaram expected.gold_context podem ser reexecutados. Remova a passagem ouro de seat_count e de money_back (e o rótulo de relevância de money_back) e o mesmo comando informa:
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 contextOs casos excluídos são listados, não descartados em silêncio. Note também o que remover um rótulo de relevância faz com a própria execução: hit_rate_at_2 subiu para 100.0% (12 / 12 observados, 1 excluído), porque o único caso que a recuperação errou deixou de ser medido. Casos sem rótulo saem do denominador; eles não contam como aprovações, e uma métrica sobre menos casos pode parecer melhor do que a aplicação é. Rotule primeiro os casos difíceis.
Teste uma correção antes de fazê-la: top-k e um reranker
Mais duas intervenções reproduzem a recuperação registrada com outra configuração, então o recuperador não é chamado de novo:
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 recoveredUm reranker é uma função (input, candidates) -> candidates que você escreve. Salve-a como rerank.py ao lado 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 recoveredNenhuma das duas recupera nada, que é o que os rótulos de contexto ouro previam: nenhuma falha aqui era uma passagem ranqueada logo abaixo do corte. Cada reprodução leva adiante os rótulos de contexto ouro, então os diagnósticos se leem juntos.
Execute o experimento que o diagnóstico nomeou, e compare
Aumente token_budget para 120 em oloproof.yaml e então:
oloproof run
oloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy compare.yamlStages: retrieve 13 hit/0 miss; generate 7 hit/6 missTodas as recuperações foram reutilizadas, porque top_k e o orçamento ficam fora da identidade da recuperação; só os seis casos cujo contexto mudou foram gerados de novo.
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)O experimento não ajudou: nenhum caso mudou de veredito, então a hipótese que o diagnóstico ofereceu não é sustentada para estes casos. Esse é um resultado útil. O próximo experimento são chunks menores, ou os prompts dos dois casos de montagem de contexto; seat_count precisa que a expectativa seja corrigida.
Solução de problemas
| Sintoma | Causa | Correção |
|---|---|---|
| Configuration error: slice 'relevant_position' ... needs a staged system | Um segmento de posição num sistema callable ou HTTP | Remova o segmento, ou passe para o caminho B |
| A execução para com saída 2 e malformed retrieval/v1 artifact | Um campo que o esquema não permite, ou mais candidatos que depth | Mapeie só os campos documentados; defina depth como no mínimo o número retornado |
| citations_valid mostra 0 / 0 observed · 15 missing e a regra dele é INSUFFICIENT_EVIDENCE com no_observations | O adaptador não registrou citations/v1 (ou context/v1); cada caso assim está ausente, não aprovado | Registre os dois em todo caminho pelo adaptador, incluindo "sem resposta"; oloproof inspect RUN_ID --failures mostra o erro por caso |
| Uma métrica de recuperação mostra muitos excluded | Casos sem expected.relevant | Rotule-os, ou aceite conscientemente o denominador menor |
| diagnose diz UNRESOLVED ... not staged | Caminho A | Esperado; use o caminho B para intervenções |
| diagnose recusa com an intervention must re-execute the same system | O código ou a configuração mudou desde a execução | Diagnostique uma execução da versão atual, ou restaure a versão que rodou |
| O diagnóstico seleciona menos casos do que falharam | Casos que falharam sem expected.gold_context | Acrescente as passagens ouro; os casos excluídos são nomeados na saída |
| Recuperações são reutilizadas depois que o índice mudou | index_version inalterado | Mude index_version quando o índice mudar |
Limitações
- O Oloproof chama a sua aplicação; ele não a hospeda, não a isola nem a reinicia. O índice, os caches e qualquer estado que ela mantenha são seus.
- Numa caixa-preta, as intervenções não estão disponíveis: diagnose rotula todo caso como UNRESOLVED e não reexecuta nada.
- As intervenções são contexto ouro, top-k e um reranker. Não há intervenção de chunking, de embedding nem de prompt.
- Os rótulos de diagnóstico descrevem os casos que falharam selecionados sob uma intervenção ao lado de um controle. Eles associam uma falha a uma etapa; não provam uma causa e não afirmam nada sobre casos não selecionados.
- As métricas de recuperação precisam de rótulos de relevância, e o diagnóstico precisa de passagens ouro; o Oloproof não cria nenhum dos dois.
- Os exemplos determinísticos fazem o papel de um recuperador e de um modelo reais. Um modelo real em generate ou um avaliador juiz chama um provedor, precisa de credenciais e custa dinheiro por caso.
- O que funciona onde, SDK contra YAML contra navegador, está em O que funciona hoje.