Voltar aos guias
Arquitetura·17 de julho de 2026·Atualizado em 30 de setembro de 2026·13 min de leitura

Extração de dados de faturas: deep learning vs machine learning vs LLM (guia de 2026)

A extração de faturas passou por quatro gerações de técnicas — templates, machine learning clássico, deep learning ajustado e agora uma única chamada de vision-LLM. Veja como elas se comparam e o padrão completo e funcional de LLM: código, saída estruturada, proteções e economia por fatura.

Última revisão em .

Há cinco anos, extrair dados estruturados de faturas significava um pipeline de aprendizado profundo: uma etapa de OCR, um modelo ciente de layout (LayoutLM, Donut) ajustado com milhares de documentos rotulados manualmente e uma carga de manutenção sempre que um fornecedor alterava seu modelo. Em 2026, todo o pipeline se reduz a uma chamada de API a um LLM de visão: imagem na entrada, JSON validado pelo esquema na saída — zero dados de treinamento, zero modelos hospedados e novos layouts tratados sem exemplos. Este guia da Kunavo — um gateway independente e compatível com OpenAI para os modelos de visão que executam esse padrão — mostra o padrão completo em funcionamento, quanto ele custa por fatura medido em relação às nossas tarifas publicadas e como manter a precisão em nível de produção.

Comparação das abordagens de extração de faturas: regras, aprendizado de máquina, aprendizado profundo, LLM

Quatro gerações de técnicas foram usadas para obter dados estruturados de uma fatura. Vale colocá-las lado a lado, porque o fator decisivo entre elas durante duas décadas — precisão obtida com dados rotulados — foi justamente o que deixou de se aplicar.

AbordagemComo funcionaCusto de configuraçãoLida com um novo layout de fornecedor
Modelos / regras (década de 1990–)OCR, seguido de zonas de coordenadas por fornecedor e expressões regulares (“o total é o número à direita de ‘TOTAL’”)Horas por fornecedor, para sempreNão — precisa de um novo modelo
Aprendizado de máquina clássico (década de 2010)OCR, seguido de recursos criados manualmente (posição, tamanho da fonte, palavras vizinhas) inseridos em um CRF ou SVM que identifica cada tokenEngenharia de recursos + alguns milhares de rótulosParcialmente — degrada em layouts não vistos
Aprendizado profundo (década de 2020–)Transformadores cientes do layout (LayoutLM, Donut, DocTR) ajustados para ler texto, posição e pixels em conjunto3.000–50.000 faturas rotuladas + serving em GPUFrequentemente não — geralmente requer nova rotulagem e novo treinamento
LLM de visão (2024–)Uma chamada de API: imagem da fatura mais um esquema JSON, com saída estruturada restrita a esse esquemaNenhum — um esquema e um prompt; $0.00248–$0.00497 por faturaSim, zero-shot

Os três primeiros compartilham uma propriedade: a precisão é comprada com dados rotulados. Cada template de fornecedor, cada recurso de CRF, cada ajuste fino do LayoutLM é um projeto de anotação. Um LLM de visão já pagou esse custo durante o pré-treinamento, então o custo marginal de um novo layout é zero. Essa é toda a mudança — não que os métodos antigos tenham deixado de funcionar, mas que aquilo em que gastavam seu orçamento ficou gratuito.

Aprendizado profundo ajustado versus LLM de visão, em detalhes

Modelo de layout ajustado (2021)LLM de visão (2026)
Dados de treinamento3.000–50.000 faturas rotuladasNenhum (zero-shot) — alguns exemplos ajudam nos casos extremos
Novo layout de fornecedorFrequentemente requer nova rotulagem + novo treinamentoTratado com zero-shot
InfraestruturaServing em GPU + etapa de OCRUma chamada HTTPS
Formato da saídaTags de tokens → decodificação personalizadaJSON restrito por esquema
Custo por faturaO tempo de engenharia domina$0.00248–$0.00497

Um extrator ajustado ainda pode vencer em um único layout congelado e de alto volume, mas para a cauda longa das faturas do mundo real — diferentes fornecedores, idiomas e qualidade de digitalização — o LLM de visão zero-shot é mais preciso na prática e radicalmente mais barato de manter. Mais padrões para essa classe de carga de trabalho estão no caso de uso de extração de dados.

O padrão completo: imagem → JSON validado pelo esquema

Tudo abaixo é executado no endpoint compatível com OpenAI da Kunavo — aponte base_url para https://api.kunavo.com/v1 e o mesmo código poderá chamar Claude ou GPT alterando uma única string:

extract_invoice.py
from openai import OpenAI
import base64, json

client = OpenAI(
    base_url="https://api.kunavo.com/v1",
    api_key="sk-kn-...",
)

SCHEMA = {
    "name": "invoice",
    "schema": {
        "type": "object",
        "properties": {
            "vendor_name":    {"type": "string"},
            "vendor_tax_id":  {"type": ["string", "null"]},
            "invoice_number": {"type": "string"},
            "invoice_date":   {"type": "string", "description": "ISO 8601"},
            "due_date":       {"type": ["string", "null"]},
            "currency":       {"type": "string", "description": "ISO 4217"},
            "line_items": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "description": {"type": "string"},
                        "quantity":    {"type": "number"},
                        "unit_price":  {"type": "number"},
                        "amount":      {"type": "number"},
                    },
                    "required": ["description", "amount"],
                },
            },
            "subtotal":  {"type": ["number", "null"]},
            "tax":       {"type": ["number", "null"]},
            "total":     {"type": "number"},
        },
        "required": ["vendor_name", "invoice_number", "invoice_date",
                     "currency", "line_items", "total"],
    },
}

def extract(path: str) -> dict:
    image_b64 = base64.b64encode(open(path, "rb").read()).decode()
    resp = client.chat.completions.create(
        model="claude-haiku-4-5",   # the cheapest capable model for clean invoices
        response_format={"type": "json_schema", "json_schema": SCHEMA},
        messages=[
            {"role": "system", "content":
                "Extract the invoice into the schema. Copy values exactly as "
                "printed; use null when a field is absent. Never invent data."},
            {"role": "user", "content": [
                {"type": "image_url",
                 "image_url": {"url": f"data:image/png;base64,{image_b64}"}},
            ]},
        ],
    )
    return json.loads(resp.choices[0].message.content)

inv = extract("invoice_0231.png")

# Cheap arithmetic guardrail: reject when the line items don't add up.
delta = abs(sum(li["amount"] for li in inv["line_items"])
            + (inv.get("tax") or 0) - inv["total"])
if delta > 0.02:
    raise ValueError(f"line items disagree with total by {delta:.2f}")

print(inv["vendor_name"], inv["total"], inv["currency"])

Três detalhes fazem a maior parte do trabalho: o esquema JSON em response_format (no Claude, o modelo não pode emitir mais nada — consulte a observação sobre GPT na referência vinculada abaixo), a regra do prompt do sistema “copie os valores exatamente; use null quando ausente; nunca invente” (elimina IDs fiscais alucinados) e a barreira aritmética — itens + imposto devem ser iguais ao total, ou o documento é encaminhado para um modelo mais robusto ou para uma pessoa. Consulte a referência de conclusões de chat para saber o que response_format impõe em cada família de modelos.

O mesmo esquema, como um modelo Pydantic tipado

Um dicionário de esquema JSON bruto é adequado para um endpoint e trabalhoso para dez. Em produção, a maioria das equipes define o esquema uma vez como um modelo Pydantic e deriva dele tanto a restrição quanto o objeto analisado, para que o extrator e o restante da base de código nunca possam discordar sobre a estrutura:

schema_pydantic.py
from pydantic import BaseModel, Field
from typing import Literal
from openai import OpenAI

client = OpenAI(base_url="https://api.kunavo.com/v1", api_key=KEY)

class LineItem(BaseModel):
    description: str
    quantity: float | None = None
    unit_price: float | None = None
    amount: float

class Invoice(BaseModel):
    vendor_name: str
    vendor_tax_id: str | None = None
    invoice_number: str
    invoice_date: str = Field(description="ISO 8601")
    currency: str = Field(description="ISO 4217")
    line_items: list[LineItem]
    tax: float | None = None
    total: float
    # A confidence field the model fills in itself is a cheap, surprisingly
    # reliable router: low self-reported confidence correlates well with the
    # documents a human should see.
    confidence: Literal["high", "medium", "low"]

resp = client.chat.completions.create(
    model="claude-haiku-4-5",
    response_format={
        "type": "json_schema",
        "json_schema": {"name": "invoice", "schema": Invoice.model_json_schema()},
    },
    messages=[...],
)

invoice = Invoice.model_validate_json(resp.choices[0].message.content)

Vale copiar duas coisas aqui. Campos tipados como float | None em vez de float dão ao modelo uma forma válida de dizer “ausente” — sem isso, uma linha de imposto ausente induz fortemente à invenção de um zero. E o campo confidence autodeclarado custa três tokens de saída e direciona surpreendentemente bem; ele não é calibrado, mas “baixo” é um sinal confiável de que uma pessoa deve analisar.

Roteamento em dois níveis: o que realmente é executado em produção

Um único modelo para todos os documentos é a estrutura errada. Faturas impressas e limpas — a esmagadora maioria — são tratadas pelo modelo de visão mais barato disponível; a cauda difícil (manuscritos, digitalizações ruins, layouts incomuns) é onde um modelo mais robusto justifica seu preço. Escalone com base em falha de validação, não em uma suposição:

two_tier_routing.py
CHEAP, STRONG = "claude-haiku-4-5", "claude-sonnet-5"

def valid(inv: dict) -> bool:
    """Arithmetic is the guardrail no confidence score replaces."""
    items = sum(li["amount"] for li in inv["line_items"])
    return abs(items + (inv.get("tax") or 0) - inv["total"]) <= 0.02

def extract_routed(path: str) -> tuple[dict, str]:
    inv = extract(path, model=CHEAP)
    if valid(inv) and inv.get("confidence") != "low":
        return inv, CHEAP

    # Escalate: same prompt, same schema, stronger model. Only the failures
    # pay the higher rate, which is what keeps the blended cost near the
    # cheap tier's.
    inv = extract(path, model=STRONG)
    if not valid(inv):
        raise NeedsHumanReview(path, inv)
    return inv, STRONG

# Blended cost at a 90/10 split, per 10,000 invoices:
#   9,000 x $0.00248 + 1,000 x $0.00497
#   = $27.29

A verificação aritmética faz o trabalho real: é o único sinal independente da própria opinião do modelo sobre si mesmo. Um documento cujos itens somam o total declarado quase nunca está errado de uma forma relevante; um que falha vale o modelo mais robusto ou uma pessoa, independentemente do que o campo de confiança afirmou.

Custo por fatura, por modelo

Uma fatura de uma página ≈ 1.800 tokens de entrada (enviada como imagem) + ~350 tokens de saída de JSON:

ModeloPor faturaPor 10.000 faturasUse para
claude-haiku-4-5$0.00248$24.80Padrão: faturas impressas e limpas e execuções em massa mais baratas
claude-sonnet-5$0.00497$49.70Nível de escalonamento: digitalizações, manuscritos, falhas

As tarifas são atualizadas na página de preços (cerca de 30% abaixo dos preços de tabela dos provedores), e solicitações com falha não são cobradas. Com roteamento em dois níveis — tudo pelo Haiku, falhas na verificação aritmética escaladas para o Sonnet — 10.000 faturas/mês normalmente ficam abaixo de $27.29.

Precisão: a lista de verificação que leva você à produção

  1. Comece pelo esquema. Marque os campos realmente obrigatórios como required, permita null em todos os demais — forçar um valor força uma alucinação.
  2. Envie a imagem, não o texto do OCR. O layout carrega significado (colunas, caixas de totais); os modelos de visão o leem diretamente. Só recorra ao texto para PDFs digitais nativos nos quais seja possível extrair uma camada de texto limpa.
  3. Valide a aritmética no código. Itens + imposto = total detecta gratuitamente a maioria dos erros de extração.
  4. Escale, não repita cegamente. As falhas vão para o Sonnet com o erro de validação incluído no prompt; falhas persistentes vão para uma fila humana.
  5. Use few-shot nos verdadeiros casos extremos. Dois ou três exemplos dos seus piores layouts (notas de crédito, múltiplas moedas) no prompt do sistema superam qualquer quantidade de ajuste de instruções.

Além das faturas

O mesmo padrão restrito por esquema abrange recibos, ordens de compra, notas de entrega, formulários alfandegários e extratos bancários — troque o esquema e mantenha as barreiras. Explore o caso de uso mais amplo de extração de dados estruturados para padrões adjacentes a RAG, ou o guia de otimização de custos para estratégias de roteamento quando o volume crescer. Uma chave Kunavo cobre todos os níveis de modelo usados aqui — cadastre-se gratuitamente e crie uma chave para executar o snippet como está.

Perguntas frequentes

Preciso de um modelo de aprendizado profundo para extrair dados de faturas?

Não mais. O pipeline clássico — OCR, seguido de um modelo de layout como o LayoutLM ajustado com milhares de faturas rotuladas — foi substituído, para a maioria das equipes, por uma única chamada a um LLM de visão: envie a imagem da fatura junto com um esquema JSON e receba de volta dados estruturados validados. Não há conjunto de treinamento para rotular, nenhum modelo para hospedar e as mudanças de layout que quebravam modelos ajustados são tratadas sem exemplos.

Como a extração de faturas por aprendizado de máquina se compara ao uso de um LLM?

Os extratores clássicos de aprendizado de máquina (CRF ou SVM sobre a saída do OCR, além de recursos de posição e fonte criados manualmente) e seus sucessores de aprendizado profundo (LayoutLM, Donut) compram precisão com dados rotulados — milhares de faturas anotadas por implantação, rotuladas novamente quando os layouts mudam. Um LLM de visão pagou esse custo durante o pré-treinamento, portanto lê sem exemplos um layout de fornecedor que nunca viu e retorna JSON limitado pelo esquema em uma única chamada de API. O aprendizado de máquina ainda vence em um único layout estável e de volume muito alto, quando o custo de inferência domina; para a cauda longa das faturas reais, o LLM é mais preciso na prática e muito mais barato de manter.

Ainda posso usar LayoutLM ou Donut para extração de faturas?

Sim, e eles continuam sendo razoáveis quando você processa milhões de documentos em um único layout estável e consegue amortizar a rotulagem e o atendimento em GPU. O que mudou é o padrão: para um projeto novo, um LLM de visão alcança precisão de produção em uma tarde, sem conjunto de treinamento, e o custo por documento é pequeno o suficiente para que a economia do ajuste fino raramente compense. Um caminho intermediário comum é executar primeiro o LLM e só fazer o ajuste fino depois, usando as próprias saídas aceitas do LLM como corpus rotulado.

Quanto custa a extração de faturas por documento?

Uma fatura de uma página tem aproximadamente 1.800 tokens de entrada (como imagem) mais ~350 tokens de saída em JSON. Na Kunavo, isso custa cerca de $0.00248 por fatura com claude-haiku-4-5 e $0.00497 com claude-sonnet-5 — ou seja, mesmo com a qualidade do Sonnet, mil faturas custam alguns dólares. Solicitações com falha não são cobradas.

Qual modelo devo usar para extrair dados de faturas?

Comece com claude-haiku-4-5: ele processa faturas impressas limpas quase perfeitamente pelo menor preço. Encaminhe apenas as falhas — escrita manual, digitalizações de baixa resolução, layouts exóticos ou documentos que falhem na verificação aritmética — para claude-sonnet-5. Esse roteamento em dois níveis normalmente mantém mais de 90% do volume na faixa barata.

Como garanto que a saída é um JSON válido?

Use saídas estruturadas: envie response_format com um esquema JSON, e um modelo Claude será restringido a emitir exatamente esse formato — sem pós-processamento com regex. Adicione uma proteção barata no nível da aplicação: verifique se os itens de linha mais o imposto equivalem ao total e envie as divergências para o modelo mais forte ou para uma fila humana.

Posso extrair dados de faturas em PDF, não apenas de imagens?

Sim — renderize cada página do PDF como PNG (por exemplo, com pdf2image) e envie-a conforme descrito acima. Para PDFs digitais, você também pode extrair a camada de texto e enviá-la como texto simples, o que é mais barato; mantenha o caminho da imagem para digitalizações.

Qual é a precisão da extração de faturas por LLM?

Em faturas impressas limpas, a extração visual limitada por esquema, com a proteção aritmética, alcança rotineiramente mais de 98% de precisão em nível de campo — e, ao contrário de um modelo ajustado, mantém a precisão em layouts que nunca viu. Meça em seus próprios documentos: 100 faturas rotuladas formam um conjunto de avaliação sólido.

Meus dados de fatura são usados para treinamento?

Não — as solicitações feitas pela Kunavo são encaminhadas aos provedores de modelos sob termos de uso de API (não termos de aplicativos para consumidores) e não são usadas para treinar modelos. Consulte a documentação de cobrança e dados para obter detalhes sobre retenção.