Pular para o conteúdo

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çãoCaminhoO que você obtémO 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-pretaMétricas de recuperação, verificações de citação, juízes de fundamentação, gate, comparaçãoIntervenções controladas: diagnose não reexecuta nada
Recuperação e geração que você pode chamar separadamenteB, em etapasTudo de A, cache por etapa, e diagnose com contexto ouro, top-k e um reranker ao lado de um controleIntervençõ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-rag

Todos 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

ArquivoO que é
app.pysupport_api(question), no lugar da sua aplicação, e run(case), o adaptador
server.pyA mesma aplicação por HTTP, para a variante HTTP abaixo
data/corpus.jsonlA base de conhecimento de 14 passagens que a aplicação pesquisa
data/support.jsonl15 casos: 13 com rótulos de relevância e passagens ouro, 2 sem nenhum dos dois
oloproof.yamlA suíte: dataset, sistema, avaliadores, segmentos
oloproof.http.yamlA mesma suíte contra o servidor HTTP
release.yamlA política de lançamento para uma única execução
compare.yamlA 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"]}
ArtefatoFormaLido por
retrieval/v1query, 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/v1items que chegaram ao modelo (doc_id, position, tokens, text), itens dropped com um reason de top_k ou token_budget, e token_budgetcitation_validity, groundedness_judge, citation_support_judge
citations/v1ids, cada um um doc_id ou doc_id#chunk_idcitation_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.citations

server.py serve exatamente isso. Inicie-o e depois execute contra ele:

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

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

Uma 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 run
Run run_01M4FCBPE0G550CKCVGXCNEM2P [DECIDED/COMPLETE]
Gate: BLOCK (exit 1)
│ answer-floor    │ answer_correct  │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold    │
│ retrieval-floor │ hit_rate_at_2   │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold    │
│ citations-valid │ citations_valid │ FAIL                  │ observed_failures_exceed_limit │

│ answer_correct  │ 73.3%    │ [44.8%, 92.3%] │ 11 / 15 observed · 0 missing · 0 excluded │
│ hit_rate_at_2   │ 92.3%    │ [63.9%, 99.9%] │ 12 / 13 observed · 0 missing · 2 excluded │
│ recall_at_2     │ 92.3%    │ [63.9%, 99.9%] │ 12 / 13 observed · 0 missing · 2 excluded │
│ citations_valid │ 93.3%    │ [68.0%, 99.9%] │ 14 / 15 observed · 0 missing · 0 excluded │
Cache: execution 0 hit/15 miss; judgment 0 hit/56 miss

Como 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 --failures
4 of 15 cases failed, errored or did not finish

refund_review
  output: {"answer": "Every refund request on an annual plan is logged in the audit trail, and the same request is listed again on the day it was reviewed and approved."…
  answer_correct: failed

money_back
  output: {"answer": "I could not find that in the knowledge base.", "citations": []}
  answer_correct: failed
  hit_rate_at_2: failed
  recall_at_2: failed
  citations_valid: failed

security_review
  output: {"answer": "Security reviews during Enterprise onboarding include an access review and a written summary for the customer, and every review is scheduled with t…
  answer_correct: failed

seat_count
  output: {"answer": "Team plans include five seats.", "citations": ["kb-03"]}
  answer_correct: failed

oloproof inspect RUN_ID --case refund_review 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_ID

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

CasoO que o registro mostraUma próxima ação com sentido
money_backA recuperação não retornou nada: a pergunta não compartilha nenhuma palavra com a passagem de reembolsoReescrita da consulta ou sinônimos, medidos por hit_rate_at_2
refund_review, security_reviewhit_rate_at_2 passou, mas a resposta veio de outra passagemInspecione context/v1: a passagem relevante foi descartada por causa do orçamento?
seat_countA 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_correct
Selected: 4 failed cases with gold context (observed; no population claim)
UNRESOLVED: 4 of 4, the system is not staged, so no case was re-executed
Diagnosis sha256:8809e100ab2ec1dad8ffeacc136cd510300081a0edf01ec11f881c543ed104bc
Cases: oloproof inspect sha256:8809e100ab2ec1dad8ffeacc136cd510300081a0edf01ec11f881c543ed104bc

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

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

A 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
ArquivoO que é
app.pySupportRag, uma classe decorada com @rag_system: retrieve(input, depth), generate(input, context), count_tokens(passage)
data/corpus.jsonl, data/support.jsonlA base de conhecimento e 13 casos, cada um com relevant e gold_context
oloproof.yamlsystem.rag aponta para a classe e define depth, top_k, token_budget, index_version
release.yaml, compare.yamlAs 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 run
Gate: BLOCK (exit 3)
│ answer-floor    │ answer_correct  │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold    │
│ retrieval-floor │ hit_rate_at_2   │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold    │
│ citations-valid │ citations_valid │ PASS                  │ observed_failures_within_limit │
│ answer_correct  │ 69.2%    │ [38.5%, 91.0%]  │ 9 / 13 observed · 0 missing · 0 excluded     │
│ hit_rate_at_2   │ 92.3%    │ [63.9%, 99.9%]  │ 12 / 13 observed · 0 missing · 0 excluded    │
│ recall_at_2     │ 92.3%    │ [63.9%, 99.9%]  │ 12 / 13 observed · 0 missing · 0 excluded    │
│ ndcg_at_6       │ 0.866    │ [0.506, 0.990]  │ mean of 13 observed · 0 missing · 0 excluded │
│ citations_valid │ 100.0%   │ [75.2%, 100.0%] │ 13 / 13 observed · 0 missing · 0 excluded    │
Cache: execution 0 hit/13 miss; judgment 0 hit/65 miss
Stages: retrieve 0 hit/13 miss; generate 0 hit/13 miss

A 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_correct
Selected: 4 failed cases with gold context (observed; no population claim)
Control: 0 of 4 passed when re-executed without the intervention
Recovered under gold context: 3 of 4
RETRIEVAL_MISS: 1 of 4, recovered; no relevant evidence was retrieved
CONTEXT_ASSEMBLY_LOSS: 2 of 4, recovered; relevant evidence within top-k was left out of the context
GENERATION_FAILURE: 1 of 4, still failed with the gold context
Implicated: context budget, in 2 of the 3 recovered failures.
Candidate experiment: a larger token budget. This is a hypothesis to test, not an established cause.
Candidate experiment: smaller chunks. This is a hypothesis to test, not an established cause.
Diagnosis sha256:50a6124f…
Child runs: gold context run_…, control run_…
Cases: oloproof inspect sha256:50a6124f…

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_ID
money_back: RETRIEVAL_MISS, relevant_not_retrieved, strength intervention_recovery, best relevant position none
refund_review: CONTEXT_ASSEMBLY_LOSS, relevant_dropped_from_context, strength intervention_recovery, best relevant position 2
seat_count: GENERATION_FAILURE, fails_with_gold_context, strength intervention_non_recovery, best relevant position 1
security_review: CONTEXT_ASSEMBLY_LOSS, relevant_dropped_from_context, strength intervention_recovery, best relevant position 2

Lendo os rótulos

RótuloO que foi observadoO que ele não estabelece
RETRIEVAL_MISSNenhuma passagem relevante foi recuperada, e o caso passou com a passagem ouroQue a recuperação é a única coisa errada, ou que uma dada mudança na recuperação vai corrigi-la
RANKED_OUTUma passagem relevante foi recuperada abaixo de top_k, e o caso passou com a passagem ouroQue ampliar o top-k vai ajudar outros casos
CONTEXT_ASSEMBLY_LOSSUma passagem relevante dentro do top-k foi descartada do contexto, e o caso passou com a passagem ouroQual orçamento seria suficiente
GENERATION_FAILUREO caso falhou mesmo com a passagem ouro em mãosQue a culpa é do modelo, e não do prompt ou da expectativa
UNRESOLVEDNada 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ênciaNada 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 context

Os 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_correct
Recovered under top-k 4: 0 of 4
Confirmed under top-k 4: 0 of 0 RANKED_OUT cases also recovered
Labels from gold context (diagnosis sha256:50a6124f…): 3 of 4 recovered

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

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

Todas 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

SintomaCausaCorreção
Configuration error: slice 'relevant_position' ... needs a staged systemUm segmento de posição num sistema callable ou HTTPRemova o segmento, ou passe para o caminho B
A execução para com saída 2 e malformed retrieval/v1 artifactUm campo que o esquema não permite, ou mais candidatos que depthMapeie 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_observationsO adaptador não registrou citations/v1 (ou context/v1); cada caso assim está ausente, não aprovadoRegistre 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 excludedCasos sem expected.relevantRotule-os, ou aceite conscientemente o denominador menor
diagnose diz UNRESOLVED ... not stagedCaminho AEsperado; use o caminho B para intervenções
diagnose recusa com an intervention must re-execute the same systemO código ou a configuração mudou desde a execuçãoDiagnostique uma execução da versão atual, ou restaure a versão que rodou
O diagnóstico seleciona menos casos do que falharamCasos que falharam sem expected.gold_contextAcrescente as passagens ouro; os casos excluídos são nomeados na saída
Recuperações são reutilizadas depois que o índice mudouindex_version inalteradoMude 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.