Quase toda empresa tem alguém digitando dado de documento em sistema. Nota de fornecedor, contrato, laudo, guia, boleto, ficha de cadastro. É o trabalho mais fácil de automatizar com IA e, ao mesmo tempo, o que mais dá errado quando feito de forma ingênua.

A abordagem antiga — regras e expressões regulares sobre o texto do OCR — funciona muito bem até chegar o documento do fornecedor número 12, que põe o valor total em outro canto da página. Aí a regra quebra em silêncio e alguém descobre no fechamento do mês.

A arquitetura em quatro camadas

Não existe "mandar o PDF para a IA e pronto". O pipeline que aguenta produção tem quatro etapas, e pular qualquer uma cobra depois.

CamadaO que fazFalha típica se pular
1. Extração de textoPDF ou imagem vira texto com posiçãoDocumento escaneado vira página em branco
2. Extração estruturadaLLM devolve JSON com esquema fixoResposta em prosa que ninguém consegue processar
3. ValidaçãoRegras determinísticas conferem o que dá para conferirCNPJ inválido entra no sistema
4. Fila de revisãoSó o duvidoso vai para uma pessoaOu ninguém revisa, ou revisam tudo — os dois são ruins

Camada 1 — tirar o texto direito

Metade dos problemas de extração são, na verdade, problemas de leitura. Três casos bem diferentes:

💡 Teste que economiza dias

Antes de acusar o modelo de errar, olhe o texto que ele recebeu. Numa boa parte dos casos o valor que "a IA não encontrou" simplesmente não estava no texto extraído — a coluna da direita colou na da esquerda, ou o número saiu com o dígito trocado no OCR.

Camada 2 — obrigar a saída estruturada

Pedir "me devolva o JSON com os campos" e torcer é a origem de metade dos incidentes. O modelo devolve JSON quase sempre — e no "quase" mora um ```json na frente, uma vírgula sobrando ou um comentário explicativo antes da chave.

A forma certa é usar saída estruturada por esquema: você declara o formato e o servidor garante que a resposta obedece. Não é prompt, é restrição na geração.

import json, requests

ESQUEMA = {
    "type": "object",
    "properties": {
        "emitente_cnpj":  {"type": "string", "description": "só dígitos"},
        "emitente_nome":  {"type": "string"},
        "numero":         {"type": "string"},
        "data_emissao":   {"type": "string", "description": "AAAA-MM-DD"},
        "valor_total":    {"type": "number", "description": "em reais, ponto decimal"},
        "itens": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "descricao":  {"type": "string"},
                    "quantidade": {"type": "number"},
                    "valor_unit": {"type": "number"},
                },
                "required": ["descricao", "quantidade", "valor_unit"],
            },
        },
        "campos_incertos": {
            "type": "array",
            "items": {"type": "string"},
            "description": "nomes dos campos que você NÃO conseguiu ler com certeza",
        },
    },
    "required": ["emitente_cnpj", "numero", "data_emissao",
                 "valor_total", "itens", "campos_incertos"],
    "additionalProperties": False,
}

def extrair(texto_documento, api_key):
    r = requests.post(
        "https://gpubrasil.com.br/v1/chat/completions",
        headers={"Authorization": f"Bearer {api_key}"},
        json={
            "model": "gpub-plus",
            "temperature": 0,
            "messages": [
                {"role": "system", "content":
                 "Você extrai campos de documentos fiscais brasileiros. "
                 "Nunca invente: se um campo não estiver legível no texto, "
                 "deixe-o vazio e liste o nome dele em campos_incertos."},
                {"role": "user", "content": texto_documento},
            ],
            "response_format": {
                "type": "json_schema",
                "json_schema": {"name": "nota", "schema": ESQUEMA, "strict": True},
            },
        },
        timeout=120,
    )
    r.raise_for_status()
    return json.loads(r.json()["choices"][0]["message"]["content"])
✅ O campo que muda tudo

Repare no campos_incertos. Sem ele, o modelo preenche alguma coisa em todo campo, porque é isso que ele faz. Com ele, você dá uma saída honesta para a incerteza — e ganha, de graça, o critério de quem vai para revisão humana.

Combinado com "nunca invente" no comando de sistema, esse par reduz drasticamente o pior tipo de erro: o valor plausível e errado.

Camada 3 — validar o que é validável

Esta é a camada que mais gente esquece e a que dá mais retorno. Muita coisa em documento brasileiro tem verificação matemática ou aritmética:

def validar(nota):
    problemas = []

    if not cnpj_valido(nota["emitente_cnpj"]):
        problemas.append("cnpj_invalido")

    soma = sum(i["quantidade"] * i["valor_unit"] for i in nota["itens"])
    if abs(soma - nota["valor_total"]) > 0.05:
        problemas.append(f"soma_itens_diverge: {soma:.2f} vs {nota['valor_total']:.2f}")

    if not (2020 <= int(nota["data_emissao"][:4]) <= 2030):
        problemas.append("data_fora_da_faixa")

    if nota["valor_total"] <= 0:
        problemas.append("valor_nao_positivo")

    return problemas

A verificação da soma dos itens contra o total é a mais poderosa de todas: ela pega, de uma vez, erro de OCR em dígito, item que ficou de fora e vírgula lida como ponto. Se você fizer só uma validação, faça essa.

O dígito verificador de CNPJ e CPF pega o resto. Documento brasileiro é generoso nesse aspecto — aproveite.

Camada 4 — a fila de revisão

Automatizar não significa remover a pessoa. Significa mudar o que a pessoa faz: em vez de digitar cem documentos, ela confere oito.

Uma regra de roteamento que funciona bem:

SituaçãoDestino
Sem problemas de validação e campos_incertos vazioAutomático — segue para o sistema
campos_incertos com algum campo não críticoAutomático, com marca para auditoria por amostragem
Qualquer problema de validaçãoRevisão humana, com o campo destacado
Valor acima do teto que você definirRevisão humana sempre, mesmo sem problema detectado

Essa última linha é política, não técnica: uma nota de R$ 800 mil merece dois olhos independentemente do que o modelo achou. Defina o teto pelo que dói perder.

⚠️ Meça a taxa de acerto por campo, não do documento

"92% de acerto" não quer dizer nada se o campo que erra sempre é o valor total. Monte uma planilha com 200 documentos conferidos à mão e calcule o acerto por campo.

É normal ver 99% em CNPJ, 97% em data e 88% em descrição de item. Com esse detalhe você sabe onde investir — e descobre que às vezes o problema é do OCR, não do modelo.

A conta

Uma nota fiscal típica em texto tem entre 800 e 2.000 tokens. Com resposta estruturada de umas 400:

Some o OCR quando o documento for escaneado: numa GPU de R$ 1,07 por hora, um modelo moderno de OCR processa alguns milhares de páginas por hora, o que mantém o custo por página na casa dos centésimos de centavo.

Compare com o custo de digitação manual e a conclusão se escreve sozinha. O que precisa de atenção não é o preço — é a taxa de erro e o que ela custa quando passa.

Do OCR à extração, no mesmo saldo

GPU por hora para a leitura de documentos escaneados e API por token para a extração estruturada, cobrados em reais, sem assinatura.

Criar conta →

Quando usar modelo de visão em vez de OCR + texto

Modelos que enxergam a página podem pular a camada 1. Vale quando o layout carrega significado — formulário com caixas, tabela com células mescladas, documento com carimbo e assinatura importando.

Não vale como padrão: sai mais caro por documento, é mais lento, e em documento com texto denso o caminho OCR + modelo de texto costuma ser mais exato. Use visão como exceção deliberada para as famílias de documento que você identificou como problemáticas.

O plano de duas semanas

  1. Dias 1–2: junte 200 documentos representativos — inclua os feios, os escaneados tortos, os de fornecedor esquisito.
  2. Dia 3: confira à mão os campos desses 200. Esse é o seu gabarito, e é o ativo mais valioso do projeto.
  3. Dias 4–6: monte extração e validação. Meça acerto por campo contra o gabarito.
  4. Dias 7–8: ataque o pior campo. Quase sempre é problema de leitura, não de modelo.
  5. Dias 9–10: monte a fila de revisão e defina o teto de valor.
  6. Dias 11–14: rode em paralelo com o processo atual, sem desligar nada, e compare.

Conclusão

Extração de documentos é o caso de uso de IA com melhor retorno em empresa média — e o que mais se beneficia de rigor. Obrigue a saída a seguir um esquema, peça ao modelo que declare o que não conseguiu ler, valide o que a matemática permite validar e mande para revisão só o que sobrou.

O erro que dói não é o modelo dizer "não sei". É ele dizer um número plausível que ninguém conferiu.

Continue: OCR em português · PDF para markdown · medir a qualidade