Inteligência artificial, sem ruído.
Modelos e LLMs8 min

Uma letra maiúscula quebrava um bot de IA em silêncio — e o bug não estava no modelo novo

Teste de regressão com 47 mensagens reais de clientes revelou que o modelo em produção escrevia “Request_refund” com R maiúsculo, quebrando o roteamento em silêncio.

Uma letra maiúscula quebrava um bot de IA em silêncio — e o bug não estava no modelo novo

O bug que só um teste de regressão enxerga

Imagine a caixa de entrada de suporte de um banco. Cada mensagem que chega precisa ser classificada e encaminhada. Hoje, cada vez mais, esse trabalho é feito por um modelo de IA que lê a mensagem e devolve uma resposta curta em um formato fixo — como um formulário com as mesmas caixas preenchidas toda vez — para que o restante do programa consiga ler automaticamente e decidir o próximo passo.

Esse formato fixo, na prática, costuma ser um bloco de JSON (JavaScript Object Notation). Pense nele como etiquetas em caixas de um formulário: uma caixa chamada intent guarda a categoria, outra chamada priority guarda a urgência, e assim por diante. O programa que lê a resposta do modelo não entende inglês: ele procura por essas caixas exatas, escritas exatamente como espera, todas as vezes. Se uma caixa sumir — ou se uma etiqueta vier escrita de um jeito ligeiramente diferente do esperado — o programa não tem como perceber sozinho. Ele simplesmente falha em silêncio.

É aqui que mora o problema central de um experimento real conduzido pelo autor no Towards Data Science: um modelo pode soar correto para uma pessoa e, ainda assim, estar errado para o software que consome a resposta dele.

Por que isso importa agora

Empresas de IA lançam versões novas de modelo constantemente, e a decisão de qual LLM usar em uma tarefa normalmente se resume a um único número vindo dos times de teste: com que frequência o modelo escolhe a categoria certa. Esse número pode subir enquanto outra coisa — o formato exato da resposta — piora em silêncio.

O autor resolveu não confiar apenas nesse número. Ele construiu um assistente de triagem de suporte, alimentou-o com 47 mensagens reais de clientes de um dataset público do setor bancário e rodou as mesmas mensagens em três versões reais de um modelo da OpenAI: uma mais antiga (gpt-4o-mini), uma em produção (gpt-4.1-mini) e uma candidata a substituí-la (gpt-5-mini).

A expectativa era que o modelo mais novo acertasse a categoria com mais frequência — e ele acertou. A surpresa veio de outro lugar: o modelo mais novo seguiu o formato exigido em todas as respostas. Foi o modelo em produção quem cometeu o erro de formatação, de forma silenciosa e repetida.

Como o teste foi montado (com Weave)

Para registrar o que a aplicação realmente faz enquanto roda, o autor usou o Weave, ferramenta da Weights & Biases (W&B) para observar aplicações de IA. Basta adicionar uma linha, @weave.op(), acima de qualquer função Python, e cada chamada passa a ser salva automaticamente: o texto exato que entrou, o texto exato que saiu e quanto tempo levou.

O projeto fez cinco coisas:

  • O Weave registra o que acontece quando a aplicação roda: a pergunta, as instruções, o modelo, a resposta e o tempo.
  • As instruções dadas ao modelo são salvas com número de versão, permitindo comparar versões antigas e novas.
  • As perguntas reais de clientes são salvas como um dataset de teste, para que todos os modelos respondam aos mesmos exemplos.
  • Um verificador estrito testa cada resposta contra requisitos exatos: JSON válido, campos obrigatórios, etiquetas permitidas e categoria correta.
  • Um segundo modelo de IA lê cada resposta e dá uma nota de qualidade, como faria um revisor humano.

A aplicação em si é deliberadamente pequena — uma única função, triage_message(text, model, prompt_ref), que lê uma mensagem e pede ao modelo uma resposta em JSON com quatro caixas fixas: intent (categoria), priority (baixa, média ou alta), needs_human (verdadeiro ou falso, para decidir se escala para uma pessoa) e reply (o texto de resposta).

Um detalhe de método importa: o pedido à OpenAI usou JSON por prompt simples — o modelo é apenas instruído, em palavras, a responder naquele formato. Não foi usado o recurso mais estrito de Structured Outputs, de propósito, porque ele esconderia justamente as falhas que o artigo quer encontrar (resposta inválida, texto extra em volta do JSON ou campo com etiqueta errada).

As mensagens reais vieram do BANKING77, um dataset público de um paper de 2020 de Iñigo Casanueva e coautores na PolyAI (licença CC BY 4.0), com 13.083 perguntas reais de atendimento bancário rotuladas à mão em 77 categorias — várias delas próximas o suficiente para confundir um modelo de verdade.

Dois verificadores, duas coisas diferentes

Cada resposta foi avaliada duas vezes, por dois tipos de verificador bem distintos:

  • Verificador estrito (baseado em regras): analisa o texto como JSON, tenta alguns métodos de fallback e responde perguntas objetivas. Os quatro campos estão presentes? A categoria é uma das 77 etiquetas reais permitidas? Bate com a resposta correta? A prioridade é um valor permitido? A decisão de escalonamento segue a regra? Nada disso exige julgamento — um campo ou está lá, ou não está.
  • Juiz de IA (avaliador por notas): uma chamada separada a um modelo que lê a mensagem do cliente, a resposta correta, a regra de escalonamento e a resposta bruta, devolvendo uma nota de 0 a 10 com uma breve explicação. Ele rodou em um modelo separado (gpt-4.1), que não é nenhum dos três comparados, para nunca avaliar o trabalho da própria “família”.

Usar os dois juntos ajuda a revelar problemas que qualquer um deles sozinho deixaria passar.

O resultado real da comparação

Rodando as 47 perguntas por modelo, o resultado foi este (1.000 = praticamente todas as respostas passaram):

O que foi verificadoAntigo (gpt-4o-mini)Produção (gpt-4.1-mini)Candidato (gpt-5-mini)
JSON válido1.0001.0001.000
Quatro campos presentes1.0001.0001.000
Categoria permitida1.0000.9361.000
Categoria correta0.7230.7660.915
Prioridade permitida1.0001.0001.000
Escalonamento correto0.9570.9570.979
Nota média do juiz de IA (0–10)6.577.799.34
Tempo médio de resposta (s)2.133.118.86
Comparação dos três modelos nas 47 mensagens reais do BANKING77.

A descoberta: um “R” maiúsculo quebrando tudo

O candidato empatou ou superou a produção em todas as medidas, incluindo os checks de formatação. Mas a linha de “categoria permitida” conta outra história: a produção marcou 0.936, enquanto os outros dois modelos marcaram 1.000 perfeito. O problema de formatação real estava no modelo em produção, não no candidato.

A causa é específica e se repete de forma idêntica em todas as perguntas de reembolso. Em três mensagens reais distintas, todas pedindo reembolso, o gpt-4.1-mini respondeu com a categoria escrita como Request_refund — com R maiúsculo. A etiqueta real do BANKING77, e o valor escrito em cada linha do dataset, é minúscula: request_refund.

Um programa que verifica essa etiqueta da forma como o software real faz — comparação exata — falharia em rotear silenciosamente cada um desses chamados, mesmo que o texto de resposta embaixo parecesse perfeitamente correto. O mesmo hábito do R maiúsculo apareceu em outras duas perguntas de reembolso, e tanto o gpt-4o-mini quanto o gpt-5-mini escreveram a etiqueta minúscula correta nas três.

É um bug de formatação já em produção, real e enviado aos clientes. O candidato não o introduziu — ele só se tornou visível porque existia algo para comparar.

A honestidade que o experimento exige

O projeto não encontrou o padrão que se propôs a procurar. O candidato nunca quebrou uma regra que a produção seguia corretamente. Ainda assim, o teste se pagou: um teste construído para pegar um problema novo acabou pegando um antigo — um bug que uma pessoa lendo a resposta por cima jamais notaria, porque a resposta em si parece completamente correta.

Há ainda um ponto que complica a história em vez de fechá-la de forma arrumada. Para a mensagem “Onde posso ver meu PIN?”, a categoria correta deveria disparar escalonamento, mas os três modelos responderam com uma categoria sobre trocar o PIN e marcaram como “não precisa de humano” — um palpite razoável que perde o ponto. O autor trata isso como uma possível questão de rotulagem do próprio dataset, não apenas um erro compartilhado dos modelos.

Datasets públicos são feitos por pessoas, e os rótulos não estão acima de questionamento. Um projeto honesto diz isso quando encontra um caso assim, em vez de contá-lo silenciosamente como mais um erro do modelo.

A lição prática para quem mantém LLMs em produção

O ponto mais valioso do experimento não foi sobre o modelo futuro que estava sendo avaliado, mas sobre o que já estava no ar. E a única razão para enxergá-lo foi ter construído algo para comparar. O juiz de IA passou direto pela diferença do R maiúsculo porque avaliava por significado; o verificador estrito a pegou porque avaliava por correspondência exata.

Se um projeto tivesse apenas o juiz de IA, sem o verificador baseado em regras rodando ao lado, como alguém pegaria um bug assim — uma resposta que parece obviamente correta e que, por baixo, está silenciosamente quebrada? Essa é a pergunta que fica em aberto, e vale a pena sentar com ela antes de decidir trocar qualquer modelo em produção.

O loop completo é repetível: trace uma aplicação pequena com o Weave, corrija as instruções quando um teste de fumaça encontrar uma lacuna real, transforme os traces em dataset, construa dois verificadores (um estrito, um que lê por significado), cheque um contra o outro, rode a comparação e, por fim, rode a comparação que realmente importa — o modelo no ar contra o que vai substituí-lo.


Descubra mais sobre noticiAI

Assine para receber nossas notícias mais recentes por e-mail.

R
Sobre o autorRedação Noticiai

Equipe editorial dedicada a explicar inteligência artificial com clareza, independência e contexto.