Validação, retry e revisão multi-pass
Objetivos de aprendizagem
- Implementar retry com feedback: reenviar documento + extração falha + erro de validação específico (task statement 4.4).
- Reconhecer quando retry é inútil: a informação não existe no documento-fonte.
- Projetar autovalidação no schema:
calculated_totalvsstated_totaleconflict_detected. - Usar
detected_patternnos achados para análise sistemática de falsos positivos. - Explicar as limitações do self-review e por que uma instância independente revisa melhor (task statement 4.6).
- Estruturar revisões grandes em multi-pass: por arquivo + passada de integração cross-file.
Retry com feedback do erro
Depois que o schema elimina os erros de sintaxe (Lição 4), sobram os erros semânticos, detectados por validação programática (Pydantic, regras de negócio). O padrão eficaz de correção não é simplesmente repetir a chamada — é o retry com feedback: uma nova requisição contendo (1) o documento original, (2) a extração que falhou e (3) o erro de validação específico. O erro concreto direciona o modelo para a correção; repetir sem feedback só re-amostra o mesmo erro.
import anthropic
from pydantic import BaseModel, ValidationError
from typing import Optional, List
class Invoice(BaseModel):
supplier: str
stated_total: Optional[float]
line_items: List[float]
client = anthropic.Anthropic()
SCHEMA = {
"type": "json_schema",
"schema": {
"type": "object",
"properties": {
"supplier": {"type": "string"},
"stated_total": {"type": ["number", "null"]},
"line_items": {"type": "array", "items": {"type": "number"}},
},
"required": ["supplier", "stated_total", "line_items"],
"additionalProperties": False,
},
}
def extract_once(prompt: str) -> str:
response = client.messages.create(
model="claude-opus-5",
max_tokens=1024,
output_config={"format": SCHEMA},
messages=[{"role": "user", "content": prompt}],
)
return next(b.text for b in response.content if b.type == "text")
def extract_with_retry(document: str, max_retries: int = 2) -> Invoice:
prompt = "<document>\n" + document + "\n</document>\nExtraia os dados."
last_error = "sem erro"
for attempt in range(max_retries + 1):
raw = extract_once(prompt)
try:
invoice = Invoice.model_validate_json(raw)
# validação semântica além do schema:
calculated = sum(invoice.line_items)
if invoice.stated_total is not None:
if abs(calculated - invoice.stated_total) > 0.01:
raise ValueError(
f"line_items somam {calculated}, "
f"mas stated_total é {invoice.stated_total}"
)
return invoice
except (ValidationError, ValueError) as e:
last_error = str(e)
# retry COM feedback: documento + extração falha + erro específico
prompt = (
"<document>\n" + document + "\n</document>\n"
"<failed_extraction>\n" + raw + "\n</failed_extraction>\n"
"<validation_error>\n" + last_error + "\n</validation_error>\n"
"Corrija a extração considerando o erro acima."
)
raise RuntimeError(f"Extração falhou após retries: {last_error}")
Quando o retry é inútil
Retry corrige erros de formato e de estrutura (data no formato errado, valor no campo errado, soma inconsistente por leitura equivocada). Retry não corrige ausência de informação: se o campo exigido só existe em um anexo que não foi fornecido, nenhuma quantidade de tentativas fará o valor aparecer — cada retry só queima tokens e, pior, aumenta a chance de fabricação. Diagnóstico na prática: se a validação falha porque um campo é null e o documento realmente não traz a informação, o caminho é aceitar o null (schema nullable), buscar a fonte que falta ou rotear para revisão humana — não retry.
Padrão de prova: "a extração de X falha repetidamente; logs mostram que X só aparece no documento Y, não enviado" → a resposta correta nunca é "aumentar retries" nem "melhorar o prompt": é fornecer a fonte correta ou tratar como ausente.
Autovalidação no schema: calculated_total e conflict_detected
Parte da validação pode ser embutida na própria extração:
calculated_totalao lado destated_total: o modelo extrai o total declarado no documento e calcula a soma dos itens. O código compara os dois: divergência sinaliza erro de extração ou documento internamente inconsistente — casos que merecem revisão.conflict_detected(booleano): quando o próprio documento traz dados contraditórios (dois totais diferentes, datas incompatíveis), o modelo marca o conflito em vez de escolher silenciosamente um dos valores. O downstream decide o que fazer.
Feedback loop de falsos positivos: detected_pattern
No cenário de revisão de código, incluir no achado estruturado um campo detected_pattern — qual construção de código disparou o achado (ex.: "atribuição dentro de condição", "SQL concatenado") — permite agrupar os achados que os desenvolvedores descartam e identificar sistematicamente quais padrões geram falso positivo. Sem esse campo, cada descarte é um dado isolado; com ele, o time enxerga "80% dos descartes vêm do padrão X" e corrige o critério certo (ou desabilita a categoria — Lição 2).
Self-review e suas limitações
Pedir ao modelo "revise seu próprio código antes de finalizar" na mesma sessão tem eficácia limitada: o modelo mantém o contexto de raciocínio da geração e tende a não questionar as próprias decisões — os mesmos vieses que produziram o bug o escondem na revisão. Extended thinking não elimina essa limitação, pois o problema é o contexto compartilhado, não a profundidade do raciocínio.
A alternativa eficaz é uma instância independente: uma segunda chamada/sessão que recebe o código (e os requisitos), sem o histórico de raciocínio da geração. Sem o compromisso com as decisões anteriores, ela questiona premissas e captura problemas sutis que o self-review deixa passar. É o mesmo princípio do exam guide para CI: a sessão que gerou o código é menos eficaz revisando as próprias mudanças do que uma instância de revisão independente. Uma variação útil: a passada de verificação reporta a confiança por achado, permitindo rotear achados de baixa confiança para revisão humana (calibração no Domínio 5).
Revisão multi-pass: por arquivo + integração
Revisar um PR de muitos arquivos em uma única passada dilui a atenção: profundidade desigual entre arquivos, bugs óbvios perdidos, feedback contraditório (o mesmo padrão sinalizado num arquivo e aprovado noutro). A estrutura recomendada é multi-pass:
- Passadas locais, por arquivo: cada arquivo é analisado individualmente, com profundidade consistente, focando problemas locais.
- Passada de integração, cross-file: uma análise separada examina o conjunto — fluxo de dados entre arquivos, contratos de interface, duplicações e inconsistências entre os achados locais.
flowchart TD
PR[PR com 14 arquivos] --> F1[Pass 1: arquivo A - problemas locais]
PR --> F2[Pass 1: arquivo B - problemas locais]
PR --> F3[Pass 1: arquivo C...N - problemas locais]
F1 --> INT[Pass 2: integração cross-file]
F2 --> INT
F3 --> INT
INT --> OUT[Achados consolidados e consistentes]
Pegadinhas da prova
- Distrator típico: retry "cego" (repetir a mesma chamada) para erro de validação — o padrão correto inclui o erro específico, a extração falha e o documento no reenvio.
- Distrator típico: aumentar retries quando a informação não existe na fonte — retry só resolve erro de formato/estrutura; ausência de informação pede outra fonte, null ou revisão humana.
- Distrator típico: "adicione 'revise seu trabalho cuidadosamente antes de responder'" ou "aumente o extended thinking" para melhorar qualidade de revisão — a limitação do self-review é o contexto compartilhado; a resposta forte é instância independente.
- Distrator típico: para revisão inconsistente de PR grande, "usar modelo com janela de contexto maior" — janela maior não resolve diluição de atenção; multi-pass sim.
- Distrator típico: "rodar 3 vezes e só reportar o que aparece em 2+" — consenso suprime bugs reais detectados intermitentemente.
Resumo em 5 linhas
- Retry eficaz = documento + extração falha + erro de validação específico; repetir sem feedback re-amostra o erro.
- Retry não cria informação ausente da fonte — nesse caso: nullable, outra fonte ou revisão humana.
calculated_totalvsstated_totaleconflict_detectedembutem autovalidação na extração.detected_patternem cada achado permite análise sistemática de falsos positivos a partir dos descartes.- Self-review na mesma sessão é fraco (contexto compartilhado); use instância independente e revisão multi-pass (por arquivo + integração cross-file).
Documentação oficial
Questões de fixação
1. A validação Pydantic rejeita uma extração porque due_date veio como "15/12/2026" em vez de ISO 8601. Qual é o conteúdo correto da requisição de retry?
Gabarito: B. O retry com feedback dá ao modelo tudo de que ele precisa: a fonte, o que produziu e o que exatamente está errado. A depende de sorte — erros de formato tendem a se repetir sem orientação. C diz que há erro mas não qual, nem dá a fonte. D remove o documento, impedindo o modelo de re-verificar o valor correto na fonte.
2. Um campo "número da apólice" falha validação em 100% dos retries para certo lote. Investigando, descobre-se que essa informação só existe no anexo B, que não é enviado ao modelo. O que fazer?
Gabarito: C. O problema é ausência de informação na entrada — nenhuma técnica de prompt ou retry resolve. A e B gastam tokens refinando um processo que não tem acesso ao dado. D é ativamente perigoso: com campo obrigatório e informação ausente, o modelo tende a fabricar um número para satisfazer o schema.
3. Por que extrair calculated_total (soma dos itens) junto com stated_total (total impresso no documento)?
Gabarito: A. É o padrão de autovalidação: divergência entre o declarado e o calculado é um sinal automático de problema (na extração ou no próprio documento), roteável para retry ou revisão humana. B é regra inventada de strict. C não faz sentido estatístico — média de um valor certo com um errado dá um valor errado. D é falso e irrelevante.
4. Uma equipe usa a mesma sessão de Claude Code que gerou o código para revisá-lo em seguida ("agora revise o que você escreveu com muito cuidado"). Bugs sutis continuam passando. Qual mudança o exame espera?
Gabarito: D. O self-review falha porque o revisor carrega o raciocínio (e os vieses) da geração; uma instância independente questiona premissas. A é instrução vaga sobre o mesmo contexto viciado. B aumenta profundidade, mas não remove o viés do contexto compartilhado. C repete o mesmo viés três vezes — os mesmos pontos cegos persistem.
5. Para que serve o campo detected_pattern em achados estruturados de revisão de código?
Gabarito: B. detected_pattern alimenta o feedback loop: agrupando os achados descartados por padrão, o time descobre quais construções geram falso positivo e corrige o critério certo. A confunde com severidade/política de gate. C não é a função do campo. D é falso — o campo complementa a severidade, não a substitui.