O caso de uso valioso e sem graça
Durante duas décadas, a extração de dados estruturados de documentos não estruturados era um projeto de um trimestre: pipeline de OCR, regras de regex, tratamento de casos extremos e templates de layout por fornecedor. Com um LLM limitado por um esquema JSON, são 30 linhas de código, precisão na primeira passagem e entrega em um dia. Os exemplos abaixo rodam no Kunavo, um gateway independente compatível com OpenAI, mas o padrão é dos modelos e funciona da mesma forma com qualquer um deles.
Extraindo faturas especificamente? Esta página é a visão geral entre documentos. O guia dedicado à extração de dados de faturas aprofunda esse único tipo de documento: como as abordagens antigas baseadas em templates e modelos se comparam a uma chamada de vision-LLM, o tutorial completo em Python com esquema restrito, a barreira de proteção aritmética, o roteamento de modelos em dois níveis e o custo por fatura.
Categorias em que isso funciona excepcionalmente bem:
- Faturas, recibos, ordens de compra
- Contratos, acordos jurídicos (extração de partes, datas e obrigações)
- Currículos / CVs (conversão para uma estrutura compatível com ATS)
- Enriquecimento de leads a partir de assinaturas de e-mail ou páginas da web
- Prontuários médicos, laudos laboratoriais (com tratamento de PII)
- Anúncios imobiliários, catálogos de produtos
- Triagem de e-mails e ingestão estruturada
O padrão central em 30 linhas
import json
from openai import OpenAI
client = OpenAI(api_key="sk-kn-...", base_url="https://api.kunavo.com/v1")
# The schema is the output contract. Claude enforces a json_schema
# response_format (json_object it does not), so the reply has this shape
# unless max_tokens cuts it off (finish_reason == "length").
STR = {"type": ["string", "null"]}
NUM = {"type": ["number", "null"]}
INVOICE = {
"type": "object",
"properties": {
"vendor": {"type": "string"},
"invoice_number": STR, "date_iso": STR, "due_date_iso": STR,
"currency": STR, "subtotal": NUM, "tax": NUM, "total": NUM,
"line_items": {"type": "array", "items": {
"type": "object",
"properties": {"description": {"type": "string"},
"qty": NUM, "unit_price": NUM, "amount": NUM},
"required": ["description", "qty", "unit_price", "amount"],
"additionalProperties": False,
}},
},
"required": ["vendor", "invoice_number", "date_iso", "due_date_iso",
"currency", "subtotal", "tax", "total", "line_items"],
"additionalProperties": False,
}
RESPONSE_FORMAT = {"type": "json_schema",
"json_schema": {"name": "invoice", "schema": INVOICE}}
RULES = "Extract the invoice. Use null for missing fields. Dates in ISO 8601."
# Extract structured fields from an invoice PDF (after OCR)
def extract_invoice(ocr_text: str) -> dict:
resp = client.chat.completions.create(
model="claude-haiku-4-5",
messages=[
{"role": "system", "content": RULES},
{"role": "user", "content": ocr_text},
],
response_format=RESPONSE_FORMAT,
max_tokens=1200,
)
return json.loads(resp.choices[0].message.content)
# Extract from an image directly (no OCR step needed)
def extract_invoice_from_image(image_url: str) -> dict:
resp = client.chat.completions.create(
model="claude-haiku-4-5", # vision + an enforced schema
messages=[
{"role": "system", "content": RULES},
{"role": "user", "content": [
{"type": "text", "text": "Extract this invoice:"},
{"type": "image_url", "image_url": {"url": image_url}},
]},
],
response_format=RESPONSE_FORMAT,
max_tokens=1200,
)
return json.loads(resp.choices[0].message.content)Dois fluxos: somente texto (após uma etapa de OCR separada) e visão direta (um modelo de visão lê a imagem e gera JSON em uma única chamada). O caminho de visão é mais rápido de desenvolver, mas um pouco mais caro por chamada; o caminho OCR e depois LLM é mais barato em escala porque o OCR tem custo único por página.
Benchmarks de precisão
Em um conjunto de dados público de faturas (1.000 faturas de 50 fornecedores), modo JSON com um prompt de sistema de 200 palavras:
- Claude Haiku 4.5: 96% de precisão no nível do campo
- Claude Sonnet 4.6: 98% de precisão no nível do campo
- Templating tradicional: 80–90% em fornecedores conhecidos, 0% em novos
O LLM lida com layouts de novos fornecedores sem exemplos prévios. Adicione 2–3 pares de exemplos ao prompt de sistema (few-shot), e o Haiku se aproxima da precisão do Sonnet por uma fração do custo.
Custo por documento
- Fatura (~2K tokens de entrada, ~500 de saída): Haiku ~US$ 0,003, Sonnet ~US$ 0,02
- Contrato de uma página (~5K de entrada): Haiku ~US$ 0,005, Sonnet ~US$ 0,04
- Contrato de 10 páginas (~50K de entrada, resumo estruturado na saída): Sonnet ~US$ 0,30
- Currículo (~3K de entrada): Haiku ~US$ 0,003
- Imagem de recibo com visão: Haiku, aproximadamente o custo de uma fatura — a imagem conta como cerca de 1,5K tokens de entrada
Processar 10.000 faturas/mês: ~US$ 30 com Haiku. A alternativa comercial mais próxima (Rossum, AWS Textract + pós-processamento) custa ~US$ 2.000–5.000/mês para o mesmo volume.
Os 5 padrões que mantêm a precisão alta
- Tratamento explícito de nulos: instrua o modelo a usar
nullpara campos ausentes, não "N/A" nem strings vazias. O código downstream pode distinguir "ausente" de "intencionalmente em branco" - Datas ISO 8601: declare isso explicitamente. Caso contrário, o modelo escolhe formatos regionais e o parsing downstream falha
- Moeda como código ISO: "USD", não "$"; "EUR", não "€". Evite ambiguidades ($ para USD, CAD ou AUD)
- Valide o JSON: use Pydantic / Zod para impor seu esquema. Se for inválido, faça um novo prompt com o erro
- Verificação manual de 1% por uma semana, depois 0,1% continuamente. Acompanhe a precisão no nível do campo, não apenas no nível do registro
Quando usar cada modelo
| Tipo de documento | Modelo recomendado |
|---|---|
| Estruturado simples (fatura, recibo) | Claude Haiku 4.5 |
| Contratos / acordos longos | Claude Sonnet 5 (lida com contexto longo) |
| Visão direta (PDF sem OCR) | Claude Haiku 4.5 ou Claude Sonnet 5 para páginas grandes |
| Alto risco (jurídico, médico) | Claude Sonnet 5 + verificação humana |
| Ingestão em massa (100K+/dia) | Haiku 4.5 + exemplos few-shot + cache |
Considerações de conformidade
Para documentos que contêm PII (faturas têm nomes e endereços; prontuários médicos têm tudo), pseudonimize antes da extração ou use Zero Data Retention upstream. Consulte o guia de conformidade para padrões específicos por região e o aprofundamento sobre DSGVO para o manual alemão.
Comece em: /app/signup — o modelo pay-as-you-go a partir de uma recarga de US$ 10 cobre ~3.000 extrações de faturas, e seu saldo nunca expira. Leia a documentação de chat em /docs/chat para saber o que response_format impõe a cada família de modelos e para conhecer os padrões de uso de ferramentas.
Perguntas frequentes
Quanto custa extrair dados de um documento com um LLM?
Cerca de US$ 0,003–US$ 0,005 por documento com Claude Haiku 4.5 e cerca de US$ 0,02–US$ 0,04 com Claude Sonnet 4.6. Processar 10.000 faturas por mês custa aproximadamente US$ 30, em comparação com US$ 2,000–US$ 5,000 por serviços comerciais de extração.
Qual é a precisão da extração de dados por LLM sem exemplos?
Precisão de 95–98% por campo sem exemplos, com cerca de 30 linhas de código — precisa o suficiente para substituir um fluxo de OCR mais regex.
Qual modelo devo usar para extração de documentos?
Documentos estruturados simples, como faturas e recibos, devem ser processados com Claude Haiku 4.5. Contratos longos devem ser processados com Claude Sonnet 4.6. Documentos lidos diretamente como imagens devem ser processados com Claude Haiku 4.5, ou Sonnet 4.6 para páginas grandes.
Como manter a precisão da extração em produção?
Cinco padrões: tratamento explícito de valores nulos, datas ISO 8601, códigos de moeda ISO, validação do esquema com um novo prompt quando a saída for inválida e verificação manual por amostragem — 1% das saídas na primeira semana e 0,1% continuamente. Acompanhe a precisão por campo, não por registro.