Volver a los casos de uso
Procesamiento de datos

Extracción de datos con IA — resultados estructurados a partir de PDF, facturas y texto no estructurado

El caso de uso aburrido pero valioso. Facturas, recibos, contratos, clientes potenciales, currículos: allí donde antes habrías creado un analizador, un LLM limitado a un esquema JSON lo hace en 30 líneas, con mayor precisión, y puedes lanzarlo en un día en lugar de un trimestre.

Última revisión: .

El caso de uso valioso y poco llamativo

Durante dos décadas, extraer datos estructurados de documentos no estructurados era un proyecto de un trimestre: una canalización de OCR, reglas regex, gestión de casos límite y plantillas de diseño por proveedor. Con un LLM sujeto a un esquema JSON, son 30 líneas de código, ofrece precisión desde el primer intento y puede ponerse en producción en un día. Los ejemplos siguientes se ejecutan en Kunavo, una puerta de enlace independiente compatible con OpenAI, pero el patrón pertenece a los modelos y funciona igual con cualquiera de ellos.

¿Quiere extraer facturas específicamente? Esta página ofrece una visión general entre documentos. La guía dedicada a la extracción de datos de facturas profundiza en ese único tipo de documento: compara los enfoques antiguos basados en plantillas y modelos con una llamada a un LLM con visión, incluye el tutorial completo de Python con restricciones de esquema, la protección aritmética, el enrutamiento de modelos en dos niveles y el coste por factura.

Categorías en las que esto funciona especialmente bien:

  • Facturas, recibos y órdenes de compra
  • Contratos y acuerdos legales (extraer partes, fechas y obligaciones)
  • Currículos / CV (convertirlos a una estructura compatible con ATS)
  • Enriquecimiento de leads a partir de firmas de correo electrónico o páginas web
  • Historias clínicas e informes de laboratorio (con gestión de PII)
  • Anuncios inmobiliarios y catálogos de productos
  • Clasificación y entrada estructurada de correos electrónicos

El patrón central en 30 líneas

extract.py
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)

Dos flujos: solo texto (después de un paso de OCR separado) y visión directa (un modelo de visión lee la imagen y devuelve JSON en una sola llamada). La ruta de visión es más rápida de construir, pero ligeramente más cara por llamada; la ruta OCR y después LLM es más barata a escala porque el OCR solo se paga una vez por página.

Pruebas de precisión

En un conjunto de datos público de facturas (1.000 facturas de 50 proveedores), con modo JSON y un prompt de sistema de 200 palabras:

  • Claude Haiku 4.5: 96 % de precisión a nivel de campo
  • Claude Sonnet 4.6: 98 % de precisión a nivel de campo
  • Plantillas tradicionales: 80-90 % con proveedores conocidos, 0 % con proveedores nuevos

El LLM gestiona diseños de nuevos proveedores sin ejemplos previos. Añada 2-3 pares de ejemplos al prompt del sistema (few-shot) y Haiku se aproxima a la precisión de Sonnet por una fracción del coste.

Coste por documento

  • Factura (~2K tokens de entrada, ~500 de salida): Haiku ~$0.003, Sonnet ~$0.02
  • Contrato de una página (~5K de entrada): Haiku ~$0.005, Sonnet ~$0.04
  • Contrato de 10 páginas (~50K de entrada, resumen estructurado de salida): Sonnet ~$0.30
  • Currículum (~3K de entrada): Haiku ~$0.003
  • Imagen de recibo con visión: Haiku, aproximadamente el coste de una factura; la imagen cuenta como unos 1.5K tokens de entrada

Procesar 10.000 facturas al mes: ~$30 con Haiku. La alternativa comercial más cercana (Rossum, AWS Textract + posprocesamiento) cuesta ~$2.000-5.000 al mes para el mismo volumen.

Los 5 patrones que mantienen una precisión alta

  • Gestión explícita de valores nulos: indique al modelo que use null para los campos ausentes, no "N/A" ni cadenas vacías. El código posterior puede distinguir entre "ausente" y "intencionadamente vacío"
  • Fechas ISO 8601: indíquelo explícitamente. De lo contrario, el modelo elige formatos regionales y el análisis posterior falla
  • Moneda como código ISO: "USD", no "$"; "EUR", no "€". Evite ambigüedades ($ puede significar USD, CAD o AUD)
  • Valide el JSON: use Pydantic / Zod para imponer su esquema. Si no es válido, vuelva a solicitarlo con el error
  • Compruebe manualmente el 1 % durante una semana y después el 0,1 % de forma continua. Realice un seguimiento de la precisión a nivel de campo, no solo a nivel de registro

Qué modelo usar en cada caso

Tipo de documentoModelo recomendado
Estructurado simple (factura, recibo)Claude Haiku 4.5
Contratos y acuerdos largosClaude Sonnet 5 (gestiona contextos largos)
Visión directa (PDF sin OCR)Claude Haiku 4.5, o Claude Sonnet 5 para páginas grandes
Alto riesgo (legal, médico)Claude Sonnet 5 + verificación humana
Entrada masiva (100K+/día)Haiku 4.5 + ejemplos few-shot + almacenamiento en caché

Consideraciones de cumplimiento

Para documentos que contienen PII (las facturas tienen nombres y direcciones; las historias clínicas lo contienen todo), seudonimice los datos antes de la extracción o use Zero Data Retention en el nivel superior. Consulte la guía de cumplimiento para patrones específicos por región y el análisis detallado del DSGVO para el manual alemán.

Empiece en /app/signup: con el pago por uso, una recarga de $10 cubre unas 3.000 extracciones de facturas y su saldo nunca caduca. Lea la documentación de chat en /docs/chat para saber qué restricciones impone response_format en cada familia de modelos y para consultar patrones de uso de herramientas.

Preguntas frecuentes

How much does it cost to extract data from a document with an LLM?

About $0.003–$0.005 per document on Claude Haiku 4.5 and about $0.02–$0.04 on Claude Sonnet 4.6. Processing 10,000 invoices a month costs roughly $30, against $2,000–$5,000 for commercial extraction services.

How accurate is zero-shot LLM data extraction?

95–98% field-level accuracy zero-shot, in about 30 lines of code — accurate enough to replace an OCR-plus-regex pipeline.

Which model should I use for document extraction?

Simple structured documents such as invoices and receipts go to Claude Haiku 4.5. Long contracts go to Claude Sonnet 4.6. Documents read directly as images go to Claude Haiku 4.5, or Sonnet 4.6 for large pages.

How do I keep extraction accurate in production?

Five patterns: explicit null handling, ISO 8601 dates, ISO currency codes, schema validation with a re-prompt on invalid output, and a manual spot-check — 1% of outputs in the first week, 0.1% ongoing. Track field-level accuracy rather than record-level.