Python · Django · APIs de IA
Como validar JSON retornado por uma IA em Python
Pedir JSON no prompt não basta. Uma resposta pode vir truncada, ter campos ausentes ou conter tipos e valores que sua aplicação não espera. Trate a saída como entrada externa.
Quando um modelo devolve texto em vez do JSON esperado, o parsing pode lançar json.JSONDecodeError. Mesmo que o parsing dê certo, isso não prova que o objeto serve para sua regra de negócio. Por exemplo, a resposta pode não conter prioridade, usar uma categoria desconhecida ou enviar a confiança como texto.
O padrão confiável tem duas etapas: converter o texto em dados e, depois, validar os dados com regras explícitas do seu sistema.
1. Faça o parsing sem esconder falhas
Comece chamando json.loads e tratando especificamente o erro de formato. Não transforme uma resposta inválida em um objeto vazio “para continuar”: isso cria uma resposta com aparência de sucesso e esconde o defeito.
import json
def interpretar_resposta(texto):
try:
dados = json.loads(texto)
except json.JSONDecodeError as erro:
raise ValueError("A IA devolveu um JSON inválido") from erro
if not isinstance(dados, dict):
raise ValueError("A resposta precisa ser um objeto JSON")
return dados
Se o provedor oferecer saída estruturada, use-a para reduzir respostas fora do formato. Ainda assim, mantenha validação na sua aplicação: formato não substitui regra de negócio. Evite extrair qualquer bloco entre chaves com uma expressão regular e assumir que o primeiro texto parecido com JSON é válido.
2. Valide campos, tipos e limites
Defina quais campos são obrigatórios e quais valores são permitidos. Este exemplo de triagem mostra a ideia; adapte as categorias e os limites ao seu domínio.
CATEGORIAS = {"cobranca", "bug", "duvida", "reclamacao", "outro"}
PRIORIDADES = {"baixa", "normal", "alta", "critica"}
def validar_triagem(dados):
obrigatorios = {"categoria", "prioridade", "confianca", "motivo"}
faltantes = obrigatorios - dados.keys()
if faltantes:
raise ValueError(f"Campos ausentes: {sorted(faltantes)}")
categoria = dados["categoria"]
prioridade = dados["prioridade"]
confianca = dados["confianca"]
if not isinstance(categoria, str) or not isinstance(prioridade, str):
raise ValueError("Categoria e prioridade precisam ser texto")
if isinstance(confianca, bool) or not isinstance(confianca, (int, float)):
raise ValueError("Confiança precisa ser um número")
categoria = categoria.strip().lower()
prioridade = prioridade.strip().lower()
if categoria not in CATEGORIAS or prioridade not in PRIORIDADES:
raise ValueError("Categoria ou prioridade fora da lista permitida")
if not 0 <= confianca <= 1:
raise ValueError("Confiança precisa estar entre 0 e 1")
return {
"categoria": categoria,
"prioridade": prioridade,
"confianca": float(confianca),
"motivo": str(dados["motivo"])[:500],
}
Em Python, bool é uma subclasse de int; por isso, isinstance(True, (int, float)) retorna verdadeiro. Se o contrato pede um número de confiança, rejeite booleanos antes de aceitar inteiros e decimais. Também limite comprimentos e valide qualquer identificador ou URL antes de persistir ou exibir.
3. Integre com segurança à aplicação Django
Coloque parsing e validação em uma camada de serviço e só depois passe os campos permitidos para o modelo Django. Não use eval, não execute o texto do modelo e não deixe a resposta decidir permissões, destinatários de email, valores de cobrança ou chamadas a ferramentas sem checagens independentes.
- Registre falhas de parsing e campos inválidos sem guardar dados pessoais desnecessários.
- Separe erros transitórios do provedor de respostas inválidas; retry indiscriminado pode elevar custos e duplicar efeitos.
- Escreva testes para campo ausente, string no lugar de número, booleano, enum desconhecido e valores fora do intervalo.
- Se a saída puder disparar uma ação externa, use autorização do servidor e uma chave de idempotência apropriada.
Assim, quando a resposta fugir do contrato, a aplicação falha de forma explícita — antes que um dado inválido vire decisão ou efeito externo.