Quase todo projeto de IA aplicada que me chega começa com a mesma frase: "a gente já testou no chat e funcionou muito bem". Funcionou mesmo. No chat, com uma pessoa atenta lendo a resposta, corrigindo o prompt na hora e descartando em silêncio as saídas ruins.
Produto não tem essa pessoa. Produto tem mil execuções por dia, sem ninguém olhando, e uma resposta ruim vira registro no banco, e-mail enviado ou cobrança errada. A distância entre esses dois mundos é onde mora todo o trabalho de engenharia — e é a parte que quase nunca aparece na demo.
Texto livre é dívida técnica
O primeiro erro estrutural é deixar o modelo devolver prosa e depois tentar entender essa prosa com regex. Já vi parser de trinta linhas para extrair um valor monetário de uma frase que o modelo escrevia de quatro jeitos diferentes dependendo do dia.
A saída de um LLM dentro de um sistema precisa ser um contrato, exatamente como qualquer outra integração. Hoje isso se resolve com saída estruturada: você declara o schema, o modelo responde dentro dele, e o que chega no seu código é um objeto validável.
{
"categoria": "reembolso",
"urgencia": "alta",
"valor_centavos": 12990,
"resumo": "Cliente pede estorno de cobrança duplicada em 12/07.",
"confianca": 0.82
}
Repare no último campo. confianca não é enfeite: é o que permite rotear. Acima de um limiar, o fluxo segue automático; abaixo, cai numa fila de revisão humana. Sem esse número, você só tem duas opções ruins — confiar em tudo ou revisar tudo.
E, mesmo com schema, valide de novo do seu lado. O schema garante a forma, não o sentido. valor_centavos: 999999999 passa em qualquer validação de tipo e ainda assim é absurdo para o seu domínio.
A chamada é lenta, então trate como sistema externo
Um LLM é uma dependência de rede com latência variável, limite de taxa e indisponibilidade eventual. Ou seja: é exatamente igual a um gateway de pagamento, e merece o mesmo tratamento arquitetural.
Na prática, isso significa que a chamada raramente deve acontecer dentro do request HTTP. No pipeline de vídeo que mantenho, tudo que envolve modelo — transcrição do áudio, seleção dos melhores trechos, geração de título e descrição — está em jobs separados, com retentativa e backoff. O usuário do painel vê um status mudando, não uma tela travada por quarenta segundos.
Fila também é o que torna a falha barata. Quando a API responde 529 num pico, o job volta pra fila e roda dez minutos depois. Sem fila, isso vira um erro 500 na cara do cliente e um chamado no suporte.
Cache é a diferença entre viável e inviável
A conta que ninguém faz na fase de protótipo é o custo por operação em escala real. Um pipeline que processa duzentos itens por dia e chama o modelo três vezes por item faz dezoito mil chamadas por mês. Se você não mediu isso antes de aprovar a feature, vai descobrir na fatura.
Duas coisas cortam esse custo de forma quase gratuita:
- Cache de resultado por hash da entrada. Se o input é idêntico, a resposta pode ser reaproveitada. Em classificação de tickets, chamado repetido é regra, não exceção — vi taxa de acerto de cache passar de 30% só com isso.
- Escolher o modelo por tarefa. Classificar em cinco categorias não precisa do modelo mais caro do catálogo. Redação final para o cliente talvez precise. Tratar "o modelo" como uma escolha única para o produto inteiro é desperdício.
E tem a economia que é só disciplina: não mande o documento inteiro quando três parágrafos resolvem. Contexto é o item de linha mais caro da conta.
Sem avaliação, você está chutando
Essa é a parte que mais separa protótipo de produto. Como você sabe que mexer no prompt melhorou alguma coisa?
A resposta útil é chata: um conjunto de casos com o resultado esperado, rodado a cada mudança. Não precisa de ferramenta sofisticada — comecei com um arquivo de casos e um comando Artisan cuspindo uma taxa de acerto no terminal. Cinquenta casos reais, tirados do que já aconteceu em produção, incluindo os feios: texto truncado, mensagem em duas línguas, cliente irritado escrevendo tudo em caixa alta.
Sem isso, cada ajuste de prompt é superstição. Alguém troca uma frase, testa em dois exemplos, acha que melhorou, e ninguém percebe que quebrou um caso que funcionava desde março.
Projete para o erro, não para o acerto
A pergunta que eu faço em toda reunião de escopo de IA é: o que acontece quando o modelo erra?
Se a resposta for "o cliente recebe um e-mail errado" ou "a cobrança sai com o valor errado", a funcionalidade não pode ser automática. Ela pode sugerir, pré-preencher, ordenar por prioridade, rascunhar — tudo com uma pessoa apertando o botão final. Se a resposta for "o item fica na categoria errada e alguém arrasta de volta", aí sim automatize.
Essa distinção define o produto muito mais do que a escolha do modelo. E ela é uma decisão de negócio, não técnica.
O resumo
A parte de IA de uma feature de IA costuma ser dez linhas de código. O resto — schema, validação, fila, cache, avaliação, fallback e desenho do momento em que o humano entra — é engenharia comum, do tipo que todo dev sênior já sabe fazer. A boa notícia é que a experiência anterior conta. A má é que ninguém escapa dessa parte.