AI Engineering Academy · Aula

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.

Aula 4 de 413 etapas

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:

  1. 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
  2. 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
  3. 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
  4. 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)
  5. 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 self

Registrando 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 logic

Pontuaçõ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:

  1. Resultado parcial: retorne os campos que foram validados e marque os campos com falha como nulos
  2. Fila de revisão humana: adicione o documento a uma fila para revisão manual, especialmente no caso de documentos de alto valor
  3. Extração com menor fidelidade: use como fallback um esquema mais simples que solicite menos campos, aceitando menos estrutura em favor da robustez
  4. 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.

Grátis para começar

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

  1. Modo JSON e response_format
  2. Saídas estruturadas com Pydantic
  3. Extraindo dados de texto não estruturado
  4. Validando e repetindo saídas inválidas
← Voltar para AI Engineering Academy