Guias
Avaliação de RAG
A versão em inglês desta página mudou desde que foi traduzida. A página em inglês é a atual. Ler em inglês
Uma resposta aumentada por recuperação pode estar errada por quatro razões diferentes: a passagem certa nunca foi recuperada; foi recuperada e ficou numa posição baixa demais; ficou numa posição alta o suficiente e depois foi retirada do contexto; ou chegou ao modelo e o modelo errou mesmo assim. Um único número de acurácia não consegue distingui-las. O Oloproof executa um sistema RAG como duas etapas que ele consegue ver, mede cada uma e reexecuta os casos que falharam sob mudanças controladas para descobrir qual razão se aplica.
examples/support_rag/ é o projeto que esta página executa. Ele não precisa de credenciais de provedor.
Um sistema em etapas
O sistema é uma classe com uma etapa de recuperação e uma etapa de geração, decorada com @rag_system:
from oloproof import Passage, Retrieval, rag_system
@rag_system(
name="support-rag",
version="slice-b-example",
depth=6,
top_k=2,
token_budget=40,
index_version="kb-2026-09-16",
)
class SupportRag:
def retrieve(self, input, depth):
...
return Retrieval(query=input["question"], depth=depth, candidates=tuple(passages))
def generate(self, input, context):
...
return {"answer": answer, "citations": [best.doc_id]}
def count_tokens(self, passage):
return len((passage.text or "").split())retrieve(input, depth) retorna até depth candidatos, como Passage(doc_id=..., score=..., text=...), na ordem em que o seu mecanismo de recuperação os produziu. O Oloproof registra as posições e nunca os reordena. Em seguida, ele mantém os primeiros top_k, descarta as passagens que excedem token_budget e passa o que sobra para generate(input, context). count_tokens(passage) só é necessário com um token_budget; o Oloproof nunca estima tokens.
oloproof.yaml aponta para a classe e pode sobrescrever qualquer uma de suas configurações:
system:
name: support-rag
version: slice-b-example
rag:
object: app:SupportRag
depth: 6
top_k: 2
token_budget: 40
index_version: kb-2026-09-16index_version faz parte da identidade da recuperação. Altere-o quando o índice mudar; caso contrário, recuperações em cache serão reutilizadas contra um índice que já não as retorna.
O que um caso declara
Um caso de RAG traz dois campos em expected de que nenhum outro tipo de caso precisa:
{"id":"refund_annual","input":{"question":"How long do refunds take for annual plans?"},"expected":{"answer":"14 days","relevant":[{"doc_id":"kb-01"}],"gold_context":[{"doc_id":"kb-01","text":"Refunds for annual plans are issued within 14 days of an approved request. Support reviews each request on the same business day."}]},"metadata":{"topic":"billing"}}- expected.relevant lista os documentos que respondem à pergunta. As métricas de recuperação o leem,
e um caso sem ele é excluído delas com no_relevance_labels.
- expected.gold_context é o próprio texto da passagem. O diagnóstico o coloca no lugar do contexto
recuperado, e um caso que falhou sem ele não pode ser diagnosticado.
Os avaliadores
evaluators:
- {type: contains, criterion: answer_correct, field: answer, expected_field: answer}
- {type: hit_rate, k: 2}
- {type: recall, k: 2}
- {type: ndcg, k: 6}
- {type: citation_validity}
slices: [metadata.topic, relevant_position, context_truncated]
min_slice_support: 4hit_rate, recall, mrr e ndcg recebem k e derivam dele o nome do próprio critério: hit_rate_at_2. Uma entrada em expected.relevant também pode trazer um chunk_id e um grade, cujo padrão é 1; relevance_unit: chunk passa então a contar cada chunk como uma unidade própria, em vez de documentos inteiros. citation_validity verifica se cada id que uma resposta cita corresponde a uma passagem do contexto que ela recebeu, e com require_citations: true uma resposta que não cita nada falha. groundedness_judge e citation_support_judge são juízes LLM que leem o contexto montado e recebem um provider e um model como qualquer outro juiz.
oloproof runTrês linhas da tabela de métricas:
│ answer_correct │ 69.2% │ [38.5%, 91.0%] │ 9 / 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 │Entre elas, hit_rate_at_2 e recall_at_2 marcam ambas 92.3%, 12 de 13 observados, com um limite inferior de 63.9%: a passagem relevante de uma pergunta nunca foi recuperada.
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. Recuperação e geração ficam em cache separadamente, então uma mudança na geração nunca reexecuta a recuperação.
Descobrindo o porquê
Quatro perguntas falharam. diagnose as reexecuta com a passagem de referência no lugar do contexto recuperado, ao lado de um controle que as reexecuta sem alterações:
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:b2846cbe04099225bda4bf21beb1738f54d6cc0e9a7ce210bb3eb467619cbd69
Child runs: gold context run_01M3C3REAAZDF9FD8N2C8BG17P, control run_01M3C3REAFVXK2VM4MYAQYH6KE
Cases: oloproof inspect sha256:b2846cbe04099225bda4bf21beb1738f54d6cc0e9a7ce210bb3eb467619cbd69Um caso que passa com a passagem de referência e falha sem ela falhou antes do modelo. Um caso que falha mesmo com a passagem de referência em mãos é responsabilidade do modelo. O controle é o que torna essa leitura segura: um caso que se recupera numa simples reexecução era instável, não foi diagnosticado.
O id do diagnóstico lista o caso por trás de cada contagem:
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 2Ele aponta um fator, nunca uma causa. "Implicated" e "candidate experiment" são as palavras mais fortes que ele usa, porque quatro casos que se recuperam sob uma intervenção não estabelecem por que falharam.
Testando uma correção antes de fazê-la
Duas outras intervenções reproduzem a recuperação registrada com uma configuração diferente, de modo que nenhuma chamada ao mecanismo de recuperação é feita. top-k amplia o corte:
oloproof diagnose RUN_ID --intervention top-k --top-k 4 --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 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:b2846cbe04099225bda4bf21beb1738f54d6cc0e9a7ce210bb3eb467619cbd69): 3 of 4 recovered
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
Diagnosis sha256:668084c3e99df84f7b63f138792aa96f48e5cb8251fee3acae8e1cc0500ba085
Child runs: gold context run_01M3C3REAAZDF9FD8N2C8BG17P, control run_01M3C3REAFVXK2VM4MYAQYH6KE, top-k 4 run_01M3C3RKHTGGV37079V11JJ78M, replay control run_01M3C3RKJ076K7MSVQ94J4ZE2P
Cases: oloproof inspect sha256:668084c3e99df84f7b63f138792aa96f48e5cb8251fee3acae8e1cc0500ba085Nada se recuperou, que é o que os rótulos previam: nenhuma falha aqui era uma passagem classificada logo abaixo do corte. A reprodução leva adiante os rótulos do contexto de referência, de modo que os dois diagnósticos são lidos em conjunto. reranker recebe --reranker com um module:function e, em vez disso, reproduz a recuperação passando pelo seu reranker.
Executando o experimento
O diagnóstico indicou um orçamento de tokens maior. Aumente token_budget para 120 e execute novamente:
Cache: execution 0 hit/13 miss; judgment 0 hit/65 miss
Stages: retrieve 13 hit/0 miss; generate 7 hit/6 missTodas as recuperações foram reutilizadas, porque top_k e o orçamento de tokens estão fora da identidade da recuperação; só os seis casos cujo contexto mudou foram gerados de novo. Em seguida, compare, com a política de comparação do exemplo:
oloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy compare.yamlComparison sha256:d801ed897f1fa1b196ca1e3f73a1ef4ffe6845d6ee8bddaea8a44da94d27a75b of run_01M3C3RYJZ4PAJ8P4P9NT71360 against run_01M3C3R5Y9D18WGSZQFA7N4XRT · 13 paired cases
answer_correct: +0.0 points [-33.6, +33.6] · 13 paired · 0 missing · 0 excluded
hit_rate_at_2: +0.0 points [-33.6, +33.6] · 13 paired · 0 missing · 0 excluded
recall_at_2: +0.0 points [-33.6, +33.6] · 13 paired · 0 missing · 0 excluded
ndcg_at_6: +0.0 points [-33.6, +33.6] · 13 paired · 0 missing · 0 excluded
citations_valid: +0.0 points [-33.6, +33.6] · 13 paired · 0 missing · 0 excludedSegue-se uma linha exploratória para cada segmento e métrica, e depois as decisões:
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 dos treze mudou de veredito. E treze casos pareados não poderiam ter estabelecido uma mudança de nenhum tamanho que importe para um lançamento, que é a outra coisa que o intervalo diz.
Próximos passos
- Segmentos trata de relevant_position e context_truncated.
- Regras de comparação trata das regras pelas quais a última etapa foi decidida.
- Juízes trata do que um juiz de fundamentação precisa cumprir antes de poder fazer gate.