Extrair valores de uma tabela parece a tarefa mais simples para um modelo de linguagem: ache a linha, ache a coluna, leia o número. O problema aparece quando a tabela tem notas de rodapé. A célula diz R$ 1.240,00, mas um asterisco manda o leitor para a nota “valores sujeitos a alteração sem aviso” ou “exceto imposto”. O modelo, na maioria das vezes, devolve só o número puro, ignora a nota e entrega uma extração que parece certa e está incompleta.
Este guia mostra como avaliar esse comportamento de forma sistemática: por que o modelo tende a ignorar notas de rodapé, como montar um conjunto de testes com tabelas realistas brasileiras (preço com ICMS, frete com taxa por região), como pedir pelo prompt que a nota seja citada junto do valor e como validar o resultado por código, comparando com um gabarito conferido à mão.
Resumo rápido
- Nota de rodapé muda o significado do número: “exceto imposto” ou “sujeito a alteração” não é detalhe decorativo, é parte do dado.
- O modelo ignora a nota porque o treino premia responder o “valor principal” e porque o asterisco é um símbolo solto, sem ligação explícita com a célula.
- Só avalie extração com gabarito: você escreve a resposta certa à mão para cada célula, incluindo a nota que a acompanha.
- No prompt, exija o número e a nota juntos, em um campo separado, com o texto literal da nota.
- Valide por código com comparação exata de string e de valor decimal, nunca com “parece certo”.
- Ponto flutuante erra centavos. Para dinheiro, use aritmética decimal, não float.
Por que a nota de rodapé importa
Uma tabela de preços sem notas é um conjunto de fatos fechados. Com notas, ela vira um conjunto de fatos condicionais. O número sozinho pode estar errado em três frentes:
- O valor não é final. Notas como “exceto imposto”, “não inclui frete” ou “sujeito a alteração” dizem que o número precisa de mais um passo antes de virar preço cobrado.
- O valor vale só para parte dos casos. Um asterisco em uma linha pode indicar “válido apenas para a região Sul” ou “apenas para pedidos acima de determinado volume”.
- O valor tem data de validade. “Preços válidos até 30/06” transforma o número em algo que expira.
Se o modelo devolve só o número, quem consome essa extração (uma planilha, um sistema de orçamento, um agente que fecha pedido) trata um valor condicional como se fosse absoluto. O erro não aparece na tela de extração. Aparece depois, na conta errada.
Por que o modelo tende a devolver o número puro
Três motivos explicam o comportamento, e entender cada um ajuda a montar o teste certo.
O número é o “resposta óbvia”
Pergunte “qual o valor desta linha?” e o modelo entrega o que está mais perto da palavra “valor”. O asterisco é um sinal fraco, um caractere solto que não aparece dentro da célula. Ferramentas de extração por padrão tratam a nota como rodapé, não como parte do dado, e o modelo aprende esse padrão de contexto.
A ligação entre asterisco e nota exige um salto
A célula tem um “*”. A nota, lá embaixo, começa com “*”. Ligar os dois é raciocínio sobre estrutura do documento, não leitura direta. É aí que a extração costuma falhar: o modelo lê a célula e a nota como blocos separados.
O prompt não pediu a nota
Na maioria dos casos o modelo devolve só o número porque foi isso que foi pedido. Se o prompt diz “extraia os preços”, ele devolve preços. A nota só entra na resposta se o formato de saída tiver um campo para ela. Isso conecta com dois temas já tratados no site: modelos tendem a preencher a resposta mais provável, sem sinalizar o que ignoraram, e a forma como você estrutura o pedido controla o que volta. Veja alucinação em IA: como reduzir e engenharia de prompts avançada.
Como montar o conjunto de testes
Você não avalia notas de rodapé com uma tabela só. Precisa de um conjunto pequeno e variado, montado à mão, cobrindo os padrões brasileiros mais comuns. Regra de ouro: cada caso tem um gabarito escrito por você, com a resposta exata esperada.
Casos mínimos que o conjunto deve cobrir
- Valor com nota que muda o cálculo: “exceto ICMS”, “acrescido de frete”.
- Valor com nota de validade: “preços válidos até a data X”.
- Valor com asterisco em apenas uma linha da mesma coluna, para testar se o modelo associa o símbolo à célula certa.
- Tabela com mais de uma nota (asterisco e outro marcador), para testar se ele distingue.
- Célula com “sob consulta” no lugar de número, para ver se ele inventa valor ou devolve vazio.
- Tabela sem nota nenhuma, como controle. Se ele erra aqui também, o problema não é a nota, é a extração básica.
Exemplo de tabela de teste: preço com ICMS
Tabela de preços de uma distribuidora, com nota que muda o valor final:
| Produto | Código | Preço (R$) | Observação |
|---|---|---|---|
| Caixa plástica 30 L | CX30 | 48,90 | valor sem ICMS* |
| Caixa plástica 50 L | CX50 | 67,40 | valor sem ICMS* |
| Palete PBR 1m | PL-100 | 92,00 |
* Preços de caixas não incluem ICMS. Paletes têm tributação própria. Valores sujeitos a alteração sem aviso.
Note a armadilha: só duas linhas têm o asterisco. O palete não tem. Uma extração boa devolve o preço do palete como valor direto e os das caixas com a nota colada. O gabarito esperado para a primeira linha, por exemplo, seria o número 48,90 mais o texto da nota associada.
Como pedir a nota no prompt
A correção mais eficaz é transformar a nota em um campo obrigatório da saída. Peça a extração em uma estrutura com campos separados: valor numérico, texto da nota e um indicador de que a nota existe.
Extraia cada linha da tabela em JSON. Para cada item retorne:
- “produto”: nome exatamente como aparece
- “codigo”: código da coluna
- “valor”: número apenas, com ponto decimal (ex.: 48.90), ou null se a célula não tiver número
- “tem_nota”: true se a linha tiver asterisco ou marca de nota, senão false
- “nota”: o texto completo da nota associada, copiado literalmente, ou “” se não houver
Não junte a nota ao valor. Não invente valor quando a célula estiver vazia ou disser “sob consulta”. Se houver dúvida sobre qual nota se aplica à linha, marque “tem_nota”: true e explique em “nota”.
Três decisões aqui fazem diferença. Primeiro, o campo nota existe, então o modelo tem onde colocar o texto e não precisa escolher entre número e nota. Segundo, o pedido de “copiar literalmente” força a fidelidade em vez de um resumo que pode perder “sem” ou “exceto”. Terceiro, a instrução de marcar dúvida evita que o modelo chute silenciosamente. Saída estruturada com campos fixos é a forma mais confiável de obter isso dos provedores atuais. Veja function calling e structured outputs.
Validar a extração por código
Comparar “na mão” não escala e não pega erro sutil. Valide por código contra o gabarito.
Regra um: compare o valor como decimal, não como float
Dinheiro não se compara com ponto flutuante. Em Python, some 0.1 com 0.2 e o resultado não é 0.3, é 0.30000000000000004. Arredonde 2,675 para duas casas com a função comum e você recebe 2,67, não 2,68. Esses desvios aparecem quando duas formas equivalentes de calcular o mesmo total divergem em centavos, e o teste acusa erro onde não há.
from decimal import Decimal, ROUND_HALF_UP
def to_dec(v): return Decimal(str(v)).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
assert to_dec("48.90") == to_dec("48.9")
Regra dois: compare a nota em texto limpo
Normalize antes de comparar: tire espaços extras, diminua para minúsculas, remova pontuação de borda. Mas cuidado: não remova o “sem” nem o “exceto”, porque é justamente isso que muda o significado.
def norm(s): return " ".join(str(s).lower().split())
esperado = norm("valor sem ICMS*")
obtido = norm(resposta["itens"][0]["nota"])
assert esperado in obtido or obtido in esperado
Regra três: teste o controle negativo
Verifique que a linha sem nota devolve tem_nota: false e nota: "". Um modelo que marca nota em toda linha é tão inútil quanto um que não marca nenhuma. Rode as três verificações em um for sobre o gabarito e conte acertos por tipo de caso (nota que altera cálculo, validade, controle). Assim você vê onde o modelo erra mais. Para um roteiro completo de avaliação de agentes e modelos, veja como testar um agente de IA.
Exemplo: distribuidora de embalagens em Goiânia
Uma distribuidora de embalagens em Goiânia recebia pedidos por WhatsApp e queria automatizar a leitura da tabela de preços para gerar orçamentos. A tabela de preços era um PDF com duas notas: uma de ICMS aplicada só a parte dos itens e outra de frete calculado por região de entrega.
Na primeira tentativa, o prompt pedia só “os preços de cada produto”. O modelo devolveu a coluna de valores pura, sem as notas. O orçamento saía com preço sem ICMS para os itens que deveriam tê-lo, e o frete entrava como um número fixo, ignorando a nota que dizia “frete por região, conforme tabela anexa”. Os orçamentos ficavam baixos e o cliente reclamava do valor final.
O ajuste não foi trocar de modelo. Foi mudar o teste e o formato de saída. O time montou dez tabelas de amostra com gabarito, incluindo casos com e sem nota, pediu a extração em campos separados (valor, tem_nota, nota) e passou a medir a taxa de acerto por tipo de caso. Com o conjunto de teste no lugar, ficou visível quais notas o modelo lia bem e quais ele pulava, e o prompt foi refinado até a extração acertar o gabarito. O resultado concreto foi previsibilidade: dá para dizer quantos casos o sistema acerta antes de colocá-lo para gerar orçamento de verdade.
Erros comuns
- Avaliar com uma tabela só. Um caso não mostra padrão. Use várias tabelas e tipos de nota diferentes.
- Não ter gabarito. Sem a resposta certa escrita à mão, você julga “parece certo” e aprova erro.
- Juntar valor e nota em um campo só. Se o número e o texto vêm juntos, a planilha de destino não consegue separar na hora de calcular.
- Comparar centavos com float. Diferenças de arredondamento viram falso erro ou falso acerto. Use decimal.
- Aceitar resumo no lugar da nota literal. “sem imposto” e “sujeito a imposto” viram a mesma coisa depois de um resumo descuidado.
- Não testar o caso sem nota. Sem controle negativo, você não sabe se o modelo está lendo ou apenas marcando tudo.
- Confiar na extração sem revisão em valores altos. Para decisões de preço, mantenha aprovação humana enquanto o conjunto de teste não provar acerto consistente.
Perguntas frequentes
Por que o modelo ignora a nota de rodapé?
Porque o número é a resposta mais provável para a pergunta “qual o valor”, e o asterisco é um sinal solto, fora da célula. Sem um campo explícito para a nota na saída, o modelo não tem onde colocá-la e tende a descartá-la.
Preciso trocar de modelo para resolver isso?
Quase nunca. Na maior parte dos casos o problema está no formato de saída e na falta de teste, não no modelo. Defina campos separados para valor e nota, exija o texto literal e valide contra um gabarito antes de culpar o modelo.
Como lidar com notas que mudam o cálculo, como “exceto ICMS”?
Extraia o número e a nota em campos distintos, e trate o cálculo do imposto em código, fora do modelo. O modelo identifica e reporta a condição; a sua lógica de negócio aplica a alíquota. Não peça ao modelo para calcular o preço final quando você tem a regra tributária no sistema.
Dá para usar isso com tabelas em PDF e imagem?
Sim, mas o risco sobe. PDFs digitalizados e imagens podem embaralhar a ordem das notas. Nesses casos, peça ao modelo o texto da nota e a linha a que ela se refere, e mantenha o conjunto de teste exatamente os arquivos reais que você vai processar.
Quantos casos preciso no conjunto de teste?
Comece com dez a vinte casos que cubram cada tipo de nota que aparece no seu material. O objetivo não é volume, é cobertura. Cada tipo de nota distinto merece pelo menos um caso com nota e um sem nota.
Como sei se a extração está pronta para produção?
Quando ela acerta o gabarito de forma consistente por tipo de caso, incluindo o controle negativo. Enquanto houver um tipo de nota com acerto baixo, mantenha revisão humana nos valores que dependem dela.
Fontes e leitura recomendada
- Python: módulo decimal, para aritmética exata em dinheiro e arredondamento controlado.
- Python: aritmética de ponto flutuante, que explica por que 0.1 + 0.2 não dá 0.3.
- OpenAI: structured outputs, para forçar campos fixos como valor, tem_nota e nota.
- Anthropic: visão geral de uso de ferramentas (tool use), sobre como o modelo devolve dados em estrutura definida.
- Google Gemini API: structured output, para saída em JSON com esquema.
- Receita Federal, para consulta de regras e tributos na fonte oficial.
- Portal Nacional da NF-e, para documentos fiscais eletrônicos e seus campos.
Veja também, aqui no site: IA para planilhas: fórmulas e análises e modelos de raciocínio: como funcionam.