Conteúdo da trilha
8 minNarração em inglês, legenda em portuguêsPodcast (RSS)
Capítulos
  1. 0:00Abertura
  2. 1:00O diagnóstico
  3. 2:28Por que acontece
  4. 3:11Quanto custa
  5. 4:07Um desafio
  6. 4:59O tratamento
  7. 6:43Quando ignorar
  8. 7:41Fechamento
Transcrição

Abertura

Uma distribuidora brasileira lê notas fiscais eletrônicas com um modelo. Toda empresa no Brasil precisa emitir, então são milhares por dia.

O prompt pede muita coisa. Extrair os itens. Somar, aplicar o desconto e conferir o resultado com o total da nota. Calcular o ICMS de cada item. Converter as datas. E checar se o CNPJ do emitente é válido.

A cada algumas centenas de notas, algo sai errado. A soma erra por alguns centavos. O imposto de um item é arredondado diferente. Ou um CNPJ inválido é marcado como válido.

O time não acha um padrão. Porque não existe. É o modelo fazendo conta. Nesta aula, você vai aprender a identificar esse smell, por que ele se esconde tão bem, e como dividir o trabalho para a conta sair certa sempre.

O diagnóstico

O que está acontecendo é isto. O documento chega.

O modelo faz duas coisas diferentes numa chamada só. Entender o documento, e fazer conta.

E a conta é gerada token a token, como texto, sem garantia de ser exata.

Quase sempre, o resultado bate. Esse quase é o problema todo.

Por que um modelo erraria uma conta simples? Porque ele não soma. Ele prevê o próximo token. Um número como mil duzentos e oitenta e quatro, com centavos, vira alguns tokens, e nem sempre cortados nos mesmos lugares. Para somar, o modelo escreve dígitos que parecem plausíveis depois do que veio antes.

Na maior parte das vezes, plausível e correto são a mesma coisa. Os modelos atuais acertam muito mais conta que os de alguns anos atrás. Mas muito mais não é sempre. E um sistema fiscal precisa de sempre.

Como identificar? O prompt pede para calcular, somar, converter, formatar ou validar algo que tem uma regra exata.

Os erros são raros, pequenos e sem padrão. Um centavo. Um dígito. Um dia.

O mesmo documento dá resultados diferentes em execuções diferentes.

E em algum lugar do sistema tem um código que refaz a conta para conferir, e às vezes discorda. Se você já escreveu a função, por que o modelo também está fazendo?

Por que acontece

Escrever uma frase no prompt é mais rápido que escrever uma função com testes.

O modelo acerta no teste. Com cinco notas de exemplo, a conta sai perfeita. O erro aparece na escala.

A linha entre entender e calcular é borrada. Extrair o total parece calcular o total. Não é. O primeiro é ler um número impresso. O segundo é produzir um número novo.

E regras que ninguém quer manter. Validar um CNPJ ou contar dias úteis exige código e teste. Jogar no prompt parece pular esse trabalho.

Quanto custa

O custo começa no dinheiro. Um centavo errado numa nota gera retrabalho contábil. Em escala, é problema com a Receita.

Depois, confiança. Quando o erro é raro e aleatório, ninguém confia em resultado nenhum, e tudo é conferido na mão.

Depois, tokens. Token de saída costuma custar várias vezes mais que o de entrada. Você está pagando por uma conta que uma linha de código faz de graça.

Depois, testes instáveis. O mesmo caso passa e falha em execuções diferentes, e o time aprende a ignorar o vermelho no pipeline.

E as regras mudam. Desde julho de 2026, CNPJs novos podem ter letras. Uma regra dessas precisa ser atualizada num lugar só, com teste. No prompt, você descobre a mudança quando o modelo começa a recusar CNPJs válidos.

Um desafio

Uma pergunta para você. O time trocou para um modelo maior. A soma das notas agora falha uma vez a cada duas mil, em vez de uma a cada trezentas. O gerente quer dar como resolvido. O que você responde?

Que a conta tem regra exata e deve sair do modelo. Uma taxa melhor não é garantia. O modelo maior erra menos, mas continua produzindo dígitos por previsão. Uma função de soma acerta sempre, e custa quase nada.

E um erro raro num valor fiscal é pior que um frequente, de certo modo. É mais caro de achar, justamente por ser raro. Pedir para o modelo conferir a própria soma também não ajuda. A conferência roda no mesmo mecanismo que errou.

O tratamento

O tratamento é uma refatoração chamada replace LLM call with code. E a regra para dividir o trabalho é simples. O modelo copia o que está escrito no documento. O código produz qualquer número novo.

Então a saída do modelo vira um dado estruturado só com os valores que ele leu. E repare que eles voltam como texto, exatamente como impressos, com a vírgula decimal brasileira. O CNPJ, a data, a quantidade de cada item, o preço unitário e a alíquota, o desconto e o total impresso.

Aí o código converte, multiplica, soma e compara.

Cento e vinte caixas a três e quinze dão trezentos e setenta e oito. Trinta e seis fitas a sete e noventa dão duzentos e oitenta e quatro e quarenta.

A soma, menos o desconto, dá seiscentos e trinta e sete e quarenta. Mas a nota imprime seiscentos e trinta e quatro e quarenta.

Antes, o modelo podia ter conferido e dito que batia. Agora a diferença é um fato calculado. A nota vai para revisão, com o motivo junto.

E dois detalhes importam. Para dinheiro, use um tipo decimal, nunca ponto flutuante. E a regra de arredondamento do imposto é decisão do time fiscal. Agora ela está escrita num lugar que dá para testar.

Aí um colega sugere: vamos pedir para o modelo devolver cada linha já multiplicada, para economizar código. Por que isso é um passo atrás? Porque a multiplicação volta a ser um número produzido pelo modelo. A divisão só funciona se o modelo nunca produz um número novo. Nem uma multiplicação simples.

Quando ignorar

Quando dá para ignorar? Estimativas. Mais ou menos quantas páginas tem esse relatório não precisa ser exato.

Julgamento, sem regra exata. Decidir se um comentário é ofensivo é trabalho do modelo. Se ele discorda de si mesmo em casos limítrofes, isso é esperado, não esse smell.

E protótipo. Para ver se a extração funciona, deixar o modelo somar tudo bem. Tire antes de produção.

E cuidado com o smell escondido dentro de uma conversa. Um assistente responde clientes sobre prazo de entrega. O prompt diz: some cinco dias úteis à data da compra. Às vezes ele conta um feriado. É um chat com o cliente, mas a conta lá dentro é determinística. Listar os feriados no prompt mantém a conta no modelo, só com mais texto. Uma ferramenta de datas resolve, e o modelo explica o resultado.

Fechamento

Então, a ideia para levar. Se a operação tem regra exata, ela não mora num prompt. Deixe o modelo fazer o que só ele faz, ler um documento bagunçado, e deixe o código produzir todo número novo. Aí uma diferença deixa de ser ruído e vira um alarme útil.

Na próxima aula, a gente faz essa refatoração passo a passo, com testes que fixam a regra: replace LLM call with code. Até lá.

SmellDispensáveis

LLM Fazendo Conta

LLM Doing Deterministic Work

LLM Fazendo Conta (LLM Doing Deterministic Work) é um smell de IA, ou seja, um sinal de problema em sistemas com LLM, do grupo Dispensáveis. O modelo calcula impostos, formata datas ou valida CPF, coisas que uma função faz sem errar.

Elemento
20/37
Nível
Iniciante
Leitura
4 min
Atualizado
Nesta página 7
  1. 01Como reconhecer
  2. 02Por que acontece
  3. 03Quanto custa ignorar
  4. 04Tratamento
  5. 05O que você ganha
  6. 06Quando ignorar
  7. 07É esse smell?
  8. ··Perguntas rápidas

Como reconhecer

O extrator de NF-e de uma distribuidora pede ao modelo os itens da nota, o valor total e se a soma dos itens bate com o total. Trecho do prompt (anonimizado):

Extraia os itens da nota fiscal com quantidade, valor unitário e valor
do item. Some os valores dos itens, aplique o desconto e confira se o
resultado bate com o valor total da nota. Calcule também o ICMS de cada
item com a alíquota indicada. Converta as datas para o formato AAAA-MM-DD.
Valide se o CNPJ do emitente é válido.

Uma vez a cada algumas centenas de notas, a soma vem errada por centavos, o ICMS de um item sai com arredondamento diferente, ou um CNPJ inválido é marcado como válido. O time não acha um padrão, porque não há padrão: é o modelo fazendo conta.

Sinais de LLM Fazendo Conta:

  • O prompt pede para calcular, somar, converter, formatar ou validar algo que tem regra exata.
  • Os erros são raros, pequenos e sem padrão: um centavo, um dígito, um dia.
  • O mesmo documento gera resultados diferentes em execuções diferentes.
  • Existe código no sistema que refaz a conta “para conferir” e às vezes discorda.
  • Datas, moedas e identificadores saem em formatos levemente diferentes.
flowchart LR
  D(["1. Documento"]):::io --> M(["2. Modelo extrai e calcula"]):::llm
  M --> C["3. Soma, imposto, validação"]:::tool
  C --> R(["4. Resultado quase sempre certo"]):::io
  1. O documento chega.
  2. O modelo faz duas coisas na mesma chamada: entender o documento e fazer contas.
  3. As contas são geradas token por token, como texto, sem garantia de exatidão.
  4. Quase sempre o resultado bate. O “quase” é o problema.

Por que o modelo erra uma conta simples

O modelo não soma. Ele prevê o próximo token. Um número como 1.284,37 vira alguns tokens, e o tokenizador nem sempre corta nos mesmos lugares. Para “somar”, o modelo escreve dígitos que parecem plausíveis depois do que veio antes.

Na maior parte das vezes, plausível e certo coincidem. Modelos atuais acertam muito mais contas do que os de alguns anos atrás. Mas “muito mais” não é “sempre”, e um sistema fiscal precisa de sempre. Uma soma de 40 itens com desconto e arredondamento é exatamente o tipo de conta em que um dígito escorrega.

Checagem +20 XP de primeiraSeu time trocou para um modelo maior e a soma da NF-e passou a errar uma vez a cada 2 mil notas, em vez de uma a cada 300. O gerente quer considerar o problema resolvido. O que você responde?

Por que acontece

  • É mais rápido escrever uma frase no prompt do que uma função com testes.
  • O modelo acerta no teste. Com cinco notas de exemplo, a conta sai certa. O erro aparece em escala.
  • O limite entre entender e calcular não fica claro. “Extrair o total” parece igual a “calcular o total”, e não é. O primeiro é ler o número impresso. O segundo é produzir um número novo.
  • Parece que o modelo sabe fazer tudo. E sabe fazer muita coisa, mas não com a garantia de uma função.
  • Regras que ninguém quer manter. Validar CNPJ ou calcular dias úteis exige código e testes. Jogar para o prompt parece evitar esse trabalho.

Quanto custa ignorar

  • Erros financeiros e fiscais. Um centavo errado numa nota fiscal gera retrabalho contábil e, em escala, problema com o fisco.
  • Desconfiança. Quando o erro é raro e aleatório, ninguém confia em nenhum resultado e tudo passa a ser conferido à mão.
  • Custo. Tokens de saída gastos em contas que uma linha de código faz de graça. Tokens de saída costumam custar várias vezes mais que os de entrada.
  • Testes instáveis. O mesmo caso passa e falha em execuções diferentes, e o time aprende a ignorar o vermelho no CI.
  • Regras que mudam sem aviso. Desde julho de 2026, novos CNPJs podem ter letras nas 12 primeiras posições (Instrução Normativa RFB 2.229/2024). Uma regra dessas precisa ser atualizada num lugar só, com teste. No prompt, você descobre a mudança quando o modelo começa a recusar CNPJs válidos.

Tratamento

Refatoração Escolha quando
Trocar Chamada de LLM por Código Sempre que a operação tem regra exata. O modelo extrai os dados brutos; o código calcula, formata e valida. Destino: Uso de Ferramentas, quando o modelo precisa do resultado no meio do raciocínio (por exemplo, para explicar um prazo ao cliente).

O mesmo extrator, dividido

A regra para dividir: o modelo copia o que está escrito no documento, e o código produz qualquer número novo. Na prática, a saída do modelo vira uma saída estruturada só com valores lidos:

{
  "emitente_cnpj": "12.ABC.345/01DE-35",
  "data_emissao": "03/09/2026",
  "itens": [
    { "descricao": "Caixa papelão 40x30", "qtd": "120", "valor_unit": "3,15", "aliquota_icms": "18" },
    { "descricao": "Fita adesiva 48mm", "qtd": "36", "valor_unit": "7,90", "aliquota_icms": "18" }
  ],
  "desconto": "25,00",
  "total_impresso": "634,40"
}

Repare que os valores vêm como texto, do jeito que estão impressos. O código converte, soma, valida e compara:

import re
from decimal import Decimal, ROUND_HALF_UP

def brl(s: str) -> Decimal:
    return Decimal(s.replace(".", "").replace(",", "."))

def dv(base: str) -> str:
    soma = sum((ord(ch) - 48) * (2 + i % 8) for i, ch in enumerate(reversed(base)))
    resto = soma % 11
    return "0" if resto < 2 else str(11 - resto)

def cnpj_valido(cnpj: str) -> bool:
    c = re.sub(r"[./-]", "", cnpj.upper())
    if not re.fullmatch(r"[0-9A-Z]{12}[0-9]{2}", c) or len(set(c)) == 1:
        return False
    return dv(c[:12]) == c[12] and dv(c[:13]) == c[13]

def conferir(nota: dict) -> dict:
    itens = [brl(i["qtd"]) * brl(i["valor_unit"]) for i in nota["itens"]]
    total = sum(itens) - brl(nota["desconto"])
    icms = [(v * brl(i["aliquota_icms"]) / 100).quantize(Decimal("0.01"), ROUND_HALF_UP)
            for v, i in zip(itens, nota["itens"])]
    return {
        "total_calculado": total,
        "bate_com_impresso": total == brl(nota["total_impresso"]),
        "icms_itens": icms,
        "cnpj_ok": cnpj_valido(nota["emitente_cnpj"]),
    }

Nesta nota, 120 vezes 3,15 dá 378,00 e 36 vezes 7,90 dá 284,40. A soma menos o desconto dá 637,40, e não os 634,40 impressos. Antes, o modelo talvez “conferisse” e dissesse que bate. Agora a divergência é um fato calculado, e a nota vai para revisão com o motivo anotado.

Use Decimal, nunca float, para dinheiro. A regra de arredondamento do ICMS (aqui, meio para cima com duas casas) é decisão do time fiscal, e agora ela está escrita num lugar que dá para testar.

Checagem +20 XP de primeiraNa nova versão, o modelo devolve valor_unit como texto lido da nota e o código calcula os totais. Um colega sugere pedir ao modelo para já devolver o valor de cada item multiplicado, para poupar código. Por que isso é um passo atrás?

O que você ganha

  • Contas exatas, sempre, e testáveis com testes unitários comuns.
  • O modelo concentrado no que só ele faz: ler um documento bagunçado.
  • Saídas menores e mais baratas.
  • Erros de extração separados de erros de cálculo, fáceis de diagnosticar.
  • Mudanças de regra (como o CNPJ alfanumérico) num lugar só, com teste.

Quando ignorar

  • Estimativas. “Mais ou menos quantas páginas tem este relatório?” não precisa de exatidão.
  • Conta que depende de interpretação. Decidir qual valor do documento é o total já é interpretação; a soma depois é conta.
  • Protótipo. Para validar se a extração funciona, deixar o modelo somar é aceitável. Antes de produção, tire.

É esse smell?

Checagem +20 XP de primeiraUm assistente responde dúvidas de clientes sobre prazos. O prompt diz 'calcule a data de entrega somando 5 dias úteis à data da compra'. Às vezes ele conta o feriado. É LLM Fazendo Conta?

Checagem +20 XP de primeiraUm classificador decide se um comentário é ofensivo. Não há regra exata, e o modelo às vezes discorda de si mesmo em casos limite. É LLM Fazendo Conta?

Checagem +20 XP de primeiraO modelo extrai o valor de cada item de uma nota e o código soma. O total do código às vezes não bate com o total impresso na nota. Onde está o problema?

Checagem +20 XP de primeiraUm agente de RH pede ao modelo para converter '3 de março' em 2026-03-03 antes de gravar no banco. O formato sai certo em 99% dos casos. Qual é o tratamento mais simples?

Perguntas rápidas

O que é LLM Fazendo Conta?

LLM Fazendo Conta (LLM Doing Deterministic Work) é um smell de IA, ou seja, um sinal de problema em sistemas com LLM, do grupo Dispensáveis. O modelo calcula impostos, formata datas ou valida CPF, coisas que uma função faz sem errar.

Como corrigir LLM Fazendo Conta?

Com Trocar Chamada de LLM por Código. Cada refatoração traz o passo a passo seguro, com eval antes e depois.

Onde LLM Fazendo Conta aparece na prática?

Nos cenários reais Extração de NF-e e contratos e Análise de planilhas com execução de código.

Para ir além

Relações

Refatorações que tratam 1
Aparece nas trilhas 1
Buscar