Ir para o conteúdo

Tratamento de Erros

Configure as novas tentativas e monitore os erros do processamento. Falhas de configuração, como extra faltando ou parâmetro inválido, levantam exceção antes da primeira chamada ao modelo; ver Exceções. Esta página trata das falhas por linha, que não interrompem a execução.

Colunas de Status

O DataFrameIt adiciona automaticamente colunas de controle:

Coluna Valores Descrição
_dataframeit_status 'processed', 'error', None Status do processamento; None é linha ainda não processada
_error_details string ou None Motivo do erro; numa linha bem-sucedida que precisou de novas tentativas, "Sucesso após N retry(s)"; numa linha com texto vazio, "Texto ausente"

Quando nenhuma linha falha e nenhuma registra detalhe, as duas colunas são removidas da saída. Confira se a coluna existe antes de filtrar por ela.

Verificando Erros

from dataframeit import dataframeit

resultado = dataframeit(df, Model, PROMPT)

if '_dataframeit_status' not in resultado.columns:
    print("Nenhuma linha falhou.")
else:
    erros = resultado[resultado['_dataframeit_status'] == 'error']
    print(f"Total de erros: {len(erros)}")
    for idx, row in erros.iterrows():
        print(f"Linha {idx}: {row['_error_details']}")

    sucesso = resultado[resultado['_dataframeit_status'] == 'processed']
    sucesso.to_excel('resultado_limpo.xlsx', index=False)

Configurando Retry

O DataFrameIt usa backoff exponencial para retry automático:

resultado = dataframeit(
    df,
    Model,
    PROMPT,
    max_retries=5,        # Total de tentativas, contando a primeira (padrão: 3)
    base_delay=2.0,       # Espera antes da primeira nova tentativa (padrão: 1.0)
    max_delay=60.0        # Teto da espera (padrão: 30.0)
)

Como funciona o backoff com a configuração acima:

Tentativa 1: falha → espera 2s
Tentativa 2: falha → espera 4s
Tentativa 3: falha → espera 8s
Tentativa 4: falha → espera 16s
Tentativa 5: falha → marca como erro

A espera antes da tentativa n + 1 é min(base_delay × 2^(n-1), max_delay), acrescida de até 10% de variação aleatória para que workers paralelos não repitam a chamada no mesmo instante. Um erro permanente encerra a linha na hora, sem esgotar as tentativas.

Tipos de Erros

Erros Transientes (retry automático)

  • Rate limit (429): Muitas requisições
  • Timeout: Servidor demorou muito
  • Erro de conexão: Problemas de rede
  • Erro 5xx: Problemas no servidor

Resposta recusada pela validação

  • Erro de validação: a resposta não passa no modelo Pydantic, inclusive nos validadores próprios (model_validator, field_validator)
  • Erro de parsing: a resposta não é JSON válido ou não veio no formato estruturado

Nos providers do LangChain, a tentativa seguinte leva ao modelo a resposta recusada e a lista de erros, cada um com o caminho do campo e o valor recusado, e pede que ele responda de novo corrigindo esses pontos. Repetir o mesmo prompt tende a repetir o mesmo erro. Quando a resposta não é JSON, o pedido leva o texto do erro do parser.

No claude_code, a tentativa seguinte repete o pedido, sem a lista de erros. No codex, a resposta que não passa na validação levanta ProviderOutputError, e a linha falha sem nova tentativa. Nos dois, a falha de validação grava em _error_details o caminho e a regra de cada erro, sem o valor recusado; caminho e regra ainda trazem texto da resposta quando o Pydantic o põe ali, como a mensagem de um validador próprio e, no claude_code, a chave de um dict. A falha de parsing do claude_code grava só que a resposta não contém JSON válido.

Na OpenAI, o SDK valida a resposta dentro da chamada e levanta o erro antes de devolver a mensagem; a resposta recusada e os tokens são lidos da resposta HTTP anexada ao erro. Quando nenhuma resposta bruta está disponível, o pedido de correção vai junto do prompt, com os valores recusados. Quando uma tentativa seguinte dá certo, os tokens das recusadas entram em _input_tokens e _output_tokens, porque também são cobrados; se todas falham, a linha fica com status error, sem contagem de tokens, e _error_details diz o campo e a regra de cada erro.

Erros Permanentes (sem retry)

  • Erro de autenticação (401/403): API key inválida
  • Recurso inexistente (404): modelo ou endpoint que o provider não conhece
  • Requisição inválida (BadRequestError, InvalidArgument): parâmetro que o provider recusa
  • Prompt maior que a janela de contexto (ContextOverflowError)
  • Configuração local incompatível com o provider
  • Orçamento ou limite de turnos do claude_code esgotado (max_budget_usd, max_turns)

Processamento Incremental

Para datasets grandes, salve checkpoints durante a execução e continue de onde parou:

# Grava o progresso a cada 100 linhas
resultado = dataframeit(
    df, Model, PROMPT,
    batch_size=100,
    checkpoint_path='parcial.xlsx',
)

# Se houver interrupção, carregue o checkpoint e continue
from dataframeit import read_df

df = read_df('parcial.xlsx', Model)
resultado = dataframeit(df, Model, PROMPT, resume=True)
resultado.to_excel('completo.xlsx', index=False)

Como funciona

Com resume=True, o DataFrameIt processa só as linhas sem _dataframeit_status. Linhas com 'processed' ou 'error' ficam como estão; para re-tentar erros, limpe o status delas, como na seção abaixo.

Reprocessando Erros

from dataframeit import read_df

# Carregar resultado com erros
df = read_df('resultado.xlsx', Model)

# Limpar status das linhas com erro para reprocessar
df.loc[df['_dataframeit_status'] == 'error', '_dataframeit_status'] = None
df.loc[df['_error_details'].notna(), '_error_details'] = None

# Reprocessar apenas as linhas sem status
resultado = dataframeit(df, Model, PROMPT, resume=True)

Estratégias para Reduzir Erros

1. Use Rate Limiting

# Previne erros de rate limit
resultado = dataframeit(
    df, Model, PROMPT,
    rate_limit_delay=1.0  # cada worker pausa 1 segundo depois de cada linha
)

2. Simplifique o Modelo

# Modelo muito complexo pode falhar
class ModeloComplexo(BaseModel):
    campo1: str
    campo2: List[SubModelo]
    campo3: Dict[str, OutroModelo]  # Evite se possível

# Modelo mais simples = menos erros
class ModeloSimples(BaseModel):
    campo1: str
    campo2: List[str]

3. Melhore o Prompt

# Prompt vago
PROMPT_RUIM = "Analise o texto."

# Prompt claro
PROMPT_BOM = """
Analise o texto e extraia:
1. Sentimento geral (positivo, negativo ou neutro)
2. Confiança na classificação (alta, média ou baixa)

Se o texto for ambíguo, classifique como neutro com confiança baixa.
"""

4. Use Modelos Mais Capazes

# Se erros persistem, tente um modelo mais capaz
resultado = dataframeit(
    df, Model, PROMPT,
    model='gpt-6-sol'  # Mais capaz que o gpt-6-luna
)