Skip to main content
Bastidores
BastidoresEngineeringDecisions

Quando o nosso provedor de IA desativou o modelo

Uma troca de modelo, respostas vazias sem erro e uma conta que de repente ficou várias vezes maior. O que quebrou e por que a causa era tão difícil de ver.

Publicado em por AlphaCloud4 min de leitura

Em julho de 2026, vários recursos pararam de funcionar ao mesmo tempo: o chat com IA, as respostas de IA nos tickets, os resumos de tickets, o criador de servidor, além da moderação e da tradução de ideias e relatos de bugs.

A causa não era o nosso código. O nosso provedor de IA tinha desativado o modelo que estávamos usando.

Parte um: o modelo sumiu

Essa é a parte óbvia, e foi resolvida rápido. Um provedor descontinua um modelo, você coloca o sucessor, pronto.

O incidente de verdade começou depois.

Parte dois: respostas vazias, sem erros

Depois da troca, as respostas voltaram. Só que às vezes vinham vazias. Não truncadas, não malformadas, mas uma resposta completamente vazia, sem erro nenhum.

A causa está numa diferença que o nome do modelo não revela: o sucessor é um modelo de raciocínio. Antes da resposta propriamente dita, ele primeiro escreve uma linha de raciocínio interna num campo separado. Os dois consomem o mesmo orçamento de tokens.

Se o orçamento é gasto no raciocínio, volta uma resposta formalmente correta: o provedor informa "comprimento atingido" e o campo de conteúdo vem vazio. Sem erro, sem aviso, nada que um try/catch enxergaria.

Reproduzimos isso com um teste real: um orçamento de cinco tokens já basta para gerar uma resposta vazia em toda requisição.

Parte três: a conta

No ponto de chamada mais caro, o criador de servidor com IA, tínhamos definido um orçamento generoso, porque lá são geradas respostas longas. Então o raciocínio não batia em nenhum limite, ele simplesmente rodava.

As consequências vieram de duas direções ao mesmo tempo. As requisições demoravam tanto que estouravam o timeout. E custavam várias vezes mais, porque toda vez se pagava por uma linha de raciocínio inteira e invisível. No fim veio uma mensagem de erro que não tínhamos previsto: saldo insuficiente.

A correção é uma linha. O raciocínio pode ser desativado no corpo da requisição, e aí o modelo volta a se comportar como o antigo. Desde então, essa linha faz parte de todos os pontos de chamada, e há mais do que um punhado deles no repositório.

Parte quatro: o que encontramos ao arrumar

Se você vai mexer em todos os pontos de chamada de IA de qualquer forma, acaba olhando para eles. Isso trouxe à tona um segundo assunto, sem relação com o incidente, mas igualmente caro.

Os provedores cobram bem menos por um prompt cujo começo continua igual e pode ser servido de um cache. A diferença entre um acerto e uma falha é de cerca de trinta vezes.

Esse desconto não vem por uma flag. Testamos especificamente: um campo no corpo da requisição feito para isso teve efeito zero, o cache se aplica automaticamente de qualquer jeito. A única alavanca é a ordem dentro do prompt, do estável para o volátil.

Quatro lugares em que tínhamos feito exatamente o contrário:

Um valor volátil dentro do bloco fixo de instruções. A verificação de duplicatas dos relatos de bugs tinha o nome do módulo no texto de instruções. Isso dava a um bloco, de resto idêntico, uma linha de cache própria por módulo. O valor pertence à parte variável, onde ele muda de qualquer forma.

O novo antes do estável. A mesma verificação enviava o novo relato de bug antes dos até cinquenta candidatos de comparação. Isso fazia do maior prompt da API uma falha completa e permanente.

Dados por usuário na parte fixa. O chat público com IA tinha as notas sobre o usuário individual no bloco de instruções, ou seja, antes do histórico compartilhado do canal. Isso dava a cada usuário no mesmo canal um começo próprio, e o histórico compartilhado era pago separadamente por usuário.

Uma janela deslizante sobre o histórico. Enviar as últimas N mensagens a cada mensagem desloca o começo a cada mensagem. O histórico inteiro vira então uma falha permanente. O jeito certo é cortar em blocos, ou seja, raramente e de uma vez.

E mais um detalhe que parece implicância e não é: uma lista dentro de um prompt ordenada por um único critério pode mudar de ordem em caso de empate. Uma única linha trocada no meio do bloco de instruções custa o acerto para tudo o que vem depois. Ordenações dentro de prompts precisam de um critério de desempate inequívoco.

O que levamos disso

Uma troca de modelo não é uma mudança de configuração. O nome parece um valor numa variável. Por trás dele havia outro comportamento, e esse comportamento quebrou o nosso código, não a interface.

A falha perigosa era a silenciosa. O sumiço do modelo antigo ficou visível na hora e foi corrigido em minutos. As respostas vazias voltavam como respostas formalmente válidas e poderiam ter continuado assim indefinidamente.

A mensurabilidade pertence ao ponto de chamada. Hoje registramos a taxa de acerto do cache em cada um deles. Um ponto bem construído se estabiliza numa taxa alta depois da primeira requisição, um mal construído fica em zero. Você vê isso numa linha de log e em nenhum outro lugar, porque os dois funcionam.

E a conclusão desconfortável: usar o modelo de outra empresa significa que parte do seu produto depende de uma decisão tomada em outro lugar. Por isso, desde agosto, qualquer servidor pode apontar os recursos de IA para o próprio endpoint em vez de depender do nosso.

Mais artigos