Validando e repetindo saídas inválidas
Implemente uma camada de validação que verifique os dados extraídos segundo regras de negócio, faça novas tentativas automaticamente com feedback corretivo quando a validação falhar e registre padrões de falha.
Validando e repetindo saídas inválidas é uma aula grátis de AI Engineering Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Engineering Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Engineering Academy inclui 4 aulas no total.
Por que as saídas dos LLMs precisam de validação
Mesmo com saídas estruturadas e esquemas Pydantic, a extração por LLM pode produzir saídas sintaticamente válidas, mas semanticamente incorretas. Uma pontuação de confiança de 1,5 (fora do intervalo de 0 a 1), um preço de -99,99, uma cadeia de caracteres de data que não pode ser analisada ou um número de telefone com letras: tudo isso passa pela análise de JSON, mas falha nas regras da sua empresa.
A validação é uma responsabilidade separada da extração. A extração pergunta: “Obtivemos dados estruturados?” A validação pergunta: “Os dados estruturados estão corretos e podem ser usados?” Ambas as camadas são necessárias para um pipeline adequado à produção. Pense nisso como um filtro em duas etapas: o LLM extrai, e o seu validador aceita ou rejeita.
Camadas de validação
Um sistema robusto de validação de saídas opera em vários níveis:
- Validação do esquema (Pydantic): tipos corretos de campos, presença dos campos obrigatórios e correspondência dos enumeradores aos valores permitidos — tratada automaticamente pelas saídas estruturadas
- Validação do formato: números de telefone correspondem a uma expressão regular, e-mails são válidos, datas podem ser analisadas e valores estão dentro de intervalos realistas
- Validação da lógica empresarial: o total da fatura é igual à soma dos itens de linha, a data final é posterior à data inicial e a quantidade é um número inteiro positivo
- Validação entre campos: o valor de um campo depende do valor de outro campo (por exemplo, o percentual de desconto não pode exceder 100)
- Validação semântica: o nome da empresa extraído corresponde a uma empresa conhecida no seu banco de dados
Validadores Pydantic para verificações de formato
O decorador Pydantic field_validator permite adicionar uma lógica de validação personalizada executada quando o modelo é instanciado. Use-o para verificações no nível do formato, como a validação por expressão regular de números de telefone e e-mails, a análise de datas e as verificações de intervalo em campos numéricos.
from pydantic import BaseModel, Field, field_validator
from typing import Optional
import re
from datetime import datetime
class ExtractedInvoice(BaseModel):
vendor: str
invoice_number: Optional[str]
amount: float = Field(gt=0, description='Must be positive')
currency: str = Field(min_length=3, max_length=3)
invoice_date: str
@field_validator('currency')
@classmethod
def currency_must_be_uppercase(cls, v):
return v.upper()
@field_validator('invoice_date')
@classmethod
def parse_date(cls, v):
# Try to parse common date formats
for fmt in ('%Y-%m-%d', '%d/%m/%Y', '%m/%d/%Y', '%B %d, %Y'):
try:
datetime.strptime(v, fmt)
return v
except ValueError:
continue
raise ValueError(f'Cannot parse date: {v}')
@field_validator('amount')
@classmethod
def reasonable_amount(cls, v):
if v > 10_000_000:
raise ValueError(f'Amount {v} seems unreasonably large. Flag for review.')
return round(v, 2)O padrão de nova tentativa com feedback corretivo
Quando a validação falha, a estratégia de recuperação mais eficaz é a nova tentativa com feedback corretivo: envie a mensagem de erro de validação de volta ao modelo como contexto, explique o que deu errado e peça que ele corrija somente os campos que falharam. Isso fornece ao modelo as informações necessárias para corrigir sua saída, em vez de simplesmente tentar novamente às cegas.
import openai
from pydantic import BaseModel, ValidationError, Field
client = openai.OpenAI()
class PriceExtraction(BaseModel):
product: str
price_usd: float = Field(gt=0, lt=100000)
quantity: int = Field(ge=1)
def extract_with_retry(text: str, max_retries: int = 3) -> PriceExtraction:
messages = [
{'role': 'system', 'content': 'Extract product pricing information.'},
{'role': 'user', 'content': text}
]
for attempt in range(max_retries):
result = client.beta.chat.completions.parse(
model='gpt-4o-mini',
messages=messages,
response_format=PriceExtraction
)
msg = result.choices[0].message
if msg.refusal:
raise ValueError(f'Model refused: {msg.refusal}')
try:
return msg.parsed # Pydantic validates on parse
except ValidationError as e:
if attempt == max_retries - 1:
raise
# Add corrective feedback for the next attempt
messages.append({'role': 'assistant', 'content': msg.content})
messages.append({'role': 'user', 'content': f'The previous extraction failed validation: {e}\nPlease correct and try again.'})
print(f'Attempt {attempt+1} failed. Retrying with feedback...')Validação da lógica empresarial
A validação da lógica empresarial verifica propriedades que abrangem vários campos ou que dependem de fontes de dados externas. O model_validator de Pydantic é executado após todos os validadores no nível dos campos e pode acessar o modelo totalmente preenchido, o que faz dele o local adequado para verificações entre campos.
from pydantic import BaseModel, Field, model_validator
from typing import List
class LineItem(BaseModel):
description: str
quantity: int = Field(ge=1)
unit_price: float = Field(ge=0)
line_total: float
@model_validator(mode='after')
def check_line_total(self):
expected = round(self.quantity * self.unit_price, 2)
actual = round(self.line_total, 2)
if abs(expected - actual) > 0.02: # Allow 2-cent rounding tolerance
raise ValueError(
f'Line total {actual} does not match quantity*price={expected}'
)
return self
class Invoice(BaseModel):
line_items: List[LineItem]
subtotal: float
tax: float
total: float
@model_validator(mode='after')
def check_invoice_total(self):
expected_total = round(self.subtotal + self.tax, 2)
if abs(expected_total - round(self.total, 2)) > 0.02:
raise ValueError(
f'Invoice total {self.total} != subtotal+tax ({expected_total})'
)
return selfRegistrando falhas de validação
Cada falha de validação é um sinal de onde o seu pipeline está apresentando problemas. Registre cada falha com: o texto de entrada (ou um hash dele, por motivos de privacidade), a saída extraída, o erro de validação específico e o número da tentativa. Agregue esses registros para identificar padrões sistemáticos: o modelo está errando consistentemente um campo? Existe uma classe de documentos que causa falhas? Esses dados orientam melhorias específicas nos prompts.
import logging
from pydantic import ValidationError
logger = logging.getLogger(__name__)
def extract_with_logging(text: str, doc_id: str) -> dict:
result = None
for attempt in range(3):
try:
result = run_extraction(text) # Your extraction function
logger.info('Extraction success', extra={
'doc_id': doc_id,
'attempt': attempt + 1
})
return result
except ValidationError as e:
logger.warning('Validation failure', extra={
'doc_id': doc_id,
'attempt': attempt + 1,
'errors': e.errors(),
'error_count': len(e.errors())
})
# All retries failed
logger.error('Extraction failed after max retries', extra={'doc_id': doc_id})
return {'error': 'extraction_failed', 'doc_id': doc_id}
def run_extraction(text):
pass # Placeholder for actual extraction logicPontuações e limites de confiança
Adicione um campo confidence ao seu esquema de extração e instrua o modelo a avaliar sua confiança em cada extração de 0 a 1. Em seguida, aplique regras empresariais com base na confiança: extrações com alta confiança vão diretamente para o seu banco de dados, extrações com confiança média são sinalizadas para verificações por amostragem e extrações com baixa confiança vão para uma fila de revisão humana.
Essa abordagem probabilística é muito mais prática do que exigir 100% de precisão do LLM: você projeta seu pipeline para lidar adequadamente com a incerteza, em vez de fingir que ela não existe.
from pydantic import BaseModel, Field
from typing import Optional
class ExtractedWithConfidence(BaseModel):
value: Optional[str]
confidence: float = Field(ge=0.0, le=1.0)
reason: Optional[str] = None # Why confidence is low, if below threshold
class DocumentExtraction(BaseModel):
vendor_name: ExtractedWithConfidence
invoice_amount: ExtractedWithConfidence
due_date: ExtractedWithConfidence
def route_by_confidence(extraction: DocumentExtraction, threshold=0.85):
low_confidence_fields = []
for field_name, field_val in extraction.model_dump().items():
if isinstance(field_val, dict) and field_val.get('confidence', 1.0) < threshold:
low_confidence_fields.append(field_name)
if not low_confidence_fields:
return 'auto_approve'
elif len(low_confidence_fields) > 2:
return 'human_review'
else:
return f'spot_check: {low_confidence_fields}'Estratégias de fallback quando as novas tentativas falham
Quando todas as novas tentativas se esgotam e a validação continua falhando, você precisa de uma estratégia de fallback. Opções, em ordem de preferência:
- Resultado parcial: retorne os campos que foram validados e marque os campos com falha como nulos
- Fila de revisão humana: adicione o documento a uma fila para revisão manual, especialmente no caso de documentos de alto valor
- Extração com menor fidelidade: use como fallback um esquema mais simples que solicite menos campos, aceitando menos estrutura em favor da robustez
- Armazenamento do texto bruto: armazene o texto original com metadados para reprocessá-lo posteriormente, quando seu pipeline de extração tiver sido aprimorado
Nunca descarte o documento silenciosamente. Sempre registre a falha e garanta que seja possível acessá-lo novamente.
Validação semântica com base em dados externos
Algumas regras de validação exigem consultas a dados externos que não podem ser realizadas dentro dos validadores do Pydantic. Por exemplo, verificar se o nome de uma empresa extraída aparece no seu CRM ou se um SKU de produto extraído existe no seu inventário. Essas verificações pertencem a uma etapa de validação pós-extração, executada depois que a validação do Pydantic é aprovada.
from typing import Optional
# Simulated external data source
KNOWN_VENDORS = {'acme corp', 'techsupplies inc', 'globex corporation'}
def validate_against_crm(extraction: dict) -> dict:
vendor = extraction.get('vendor', '').lower()
warnings = []
if vendor and vendor not in KNOWN_VENDORS:
warnings.append({
'field': 'vendor',
'issue': f'Vendor "{vendor}" not found in CRM',
'severity': 'warning'
})
# Optionally suggest closest match
# from difflib import get_close_matches
# matches = get_close_matches(vendor, KNOWN_VENDORS, n=1, cutoff=0.8)
# if matches: warnings[-1]['suggestion'] = matches[0]
return {
'extraction': extraction,
'warnings': warnings,
'requires_review': len(warnings) > 0
}
print('Semantic validation pattern defined')Testando seu pipeline de validação
Sua lógica de validação precisa de um conjunto próprio de testes, separado dos testes de extração. Escreva testes unitários que forneçam saídas sabidamente inválidas aos seus validadores e verifique se os erros corretos são gerados. Teste casos-limite: valores nos limites, datas em formatos incomuns, campos com espaços em branco inesperados e campos que sejam strings numéricas em vez de números.
Este conjunto de testes de validação é executado sem chamadas à API, o que torna sua execução rápida e barata a cada alteração no código. Ele também é a melhor documentação das suas regras de validação — os casos de teste deixam explícitos todos os formatos e requisitos de negócio impostos pelo seu pipeline.
from pydantic import ValidationError
def test_extraction_validation():
# Test cases: (input_data, should_pass)
test_cases = [
({'vendor': 'ACME', 'amount': 150.00, 'currency': 'USD', 'invoice_date': '2025-01-15'}, True),
({'vendor': 'ACME', 'amount': -50.00, 'currency': 'USD', 'invoice_date': '2025-01-15'}, False), # negative
({'vendor': 'ACME', 'amount': 150.00, 'currency': 'EURO', 'invoice_date': '2025-01-15'}, False), # 4-char
({'vendor': 'ACME', 'amount': 150.00, 'currency': 'USD', 'invoice_date': 'yesterday'}, False), # bad date
]
passed = failed = 0
for data, should_pass in test_cases:
try:
# ExtractedInvoice(**data) # Your Pydantic model
if should_pass:
passed += 1
else:
print(f'MISSED: Should have failed for {data}')
failed += 1
except (ValidationError, ValueError):
if not should_pass:
passed += 1
else:
print(f'UNEXPECTED FAIL for {data}')
failed += 1
print(f'Tests: {passed} passed, {failed} failed')
test_extraction_validation()Análise de falhas recorrentes e ajuste de prompts
Depois de executar seu pipeline de extração em uma amostra de documentos reais e analisar as falhas de validação, é provável que você descubra que 80% das falhas compartilham um pequeno número de causas-raiz. Entre os culpados comuns estão: o modelo formatar datas consistentemente de forma incorreta em uma localidade específica, identificar incorretamente o valor do imposto em vez do total ou produzir números de telefone sem hífens quando o seu validador espera hífens.
Para cada padrão de falha recorrente, atualize seu prompt de extração com um exemplo específico e uma restrição que impeça esse erro. Depois da atualização, execute novamente todo o seu conjunto de testes para confirmar que a correção melhorou a precisão sem causar regressões em outros casos. Esse ciclo iterativo de solicitar e depois avaliar é como os pipelines de extração em produção alcançam mais de 95% de precisão em dados do mundo real.
Verificação rápida
Teste sua compreensão dos conceitos de Engenharia de IA desta lição.
Recapitulação da lição
Nesta lição, você aprendeu que: a validação funciona em várias camadas — esquema, formato, lógica de negócio e semântica — e cada uma exige abordagens de implementação diferentes; a repetição com feedback corretivo fornece ao modelo um contexto específico sobre o erro para que ele corrija sua saída com eficiência; e as pontuações de confiança permitem o roteamento probabilístico para filas de aprovação automática, verificação por amostragem ou análise humana, com base na certeza da extração. Você concluiu o curso de Saída Estruturada e Modo JSON. A seguir, exploraremos os embeddings vetoriais — a base de todo sistema RAG.
Aprenda Python com um tutor de IA — grátis
Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.
- Cursos
- 30
- Aulas
- 120
Perguntas Frequentes
A aula “Validando e repetindo saídas inválidas” é grátis?
Sim — o texto completo de “Validando e repetindo saídas inválidas” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Engineering Academy, atualize para CoddyKit PRO. O curso de AI Engineering Academy inclui 4 aulas no total.
O que vou aprender em “Validando e repetindo saídas inválidas”?
Implemente uma camada de validação que verifique os dados extraídos segundo regras de negócio, faça novas tentativas automaticamente com feedback corretivo quando a validação falhar e registre padrõe… Você pratica AI Engineering Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar AI Engineering Academy?
Nenhuma experiência prévia é necessária. AI Engineering Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.
Quanto tempo leva a aula “Validando e repetindo saídas inválidas”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de AI Engineering Academy?
Sim. Cada aula de AI Engineering Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Modo JSON e response_format
- Saídas estruturadas com Pydantic
- Extraindo dados de texto não estruturado
- Validando e repetindo saídas inválidas