Saltar a contenido

Extraer tablas de documentos con modelos open-weight en local: la teoría y qué funcionó de verdad

Nota para el equipo

Sale del proyecto de Disproquima, donde extraje una tabla de un PDF (con categorías, subcategorías y celdas combinadas) usando mi visión multimodal. La pregunta era qué modelo open-weight —pesos abiertos, ejecutable en local— replica esa tarea. Primero está la comparativa teórica; luego, las pruebas reales en local (MacBook Air M5, 16 GB, Ollama), que corrigen la recomendación de libro.

Esto NO sustituye la ingesta de Mentat

Son dos problemas distintos, no confundirlos:

  • Ingesta de Mentat (ver Arquitectura de Mentat): convierte documentos a texto plano y lo trocea en chunks para la BD vectorial (Qdrant), que alimentan a los agentes conversacionales. Ahí interesa el texto independientemente del formato, y el pipeline actual (OCR + conversión a texto) hace justo eso. No hay nada que arreglar.
  • Este artículo: extraer información concreta y estructurada tal cual está en el original —facturas → campos, tablas de un certificado para recomponerlo— donde la disposición (qué columna, qué celda combinada, qué total) es la información y hay que preservarla. Un pipeline de "todo a texto plano" la destruiría.

Regla rápida: si el destino son chunks para chatear sobre el contenido → ingesta de Mentat. Si el destino es un dato/tabla estructurada fiel al original → lo de aquí.

TL;DR

El salto importante no es de "peor OCR" a "mejor OCR": es pasar de modelos que leen caracteres a modelos que entienden el documento (qué es tabla, qué es texto, en qué orden va). Para tareas tipo Disproquima eso es imprescindible. Pero al bajar a local con Ollama, la teoría se topó con dos bugs y el ganador no fue el que decía el papel.

Decisión por caso de uso

  • Facturas → campos estructurados (JSON): Qwen2.5-VL-7B. Una GPU, cuantizable, le pasas el esquema en el prompt y devuelve JSON.
  • Certificados con tablas + fórmulas para recomponer: Marker (MinerU/Datalab), que exporta a Markdown/HTML/DOCX/JSON con la estructura reconstruida.
  • Tabla suelta en local con Ollama: qwen2.5vl:7b sobre PNG (no PDF). Fue el único que funcionó de forma fiable en las pruebas.

Dos trampas de Ollama que descubrimos probando

  1. El PDF no llega como imagen. La web de Ollama extrae el texto plano del PDF en vez de rasterizar la página, así que el modelo de visión nunca "ve" la tabla. Hay que convertir a PNG antes de subir.
  2. qwen3-vl:8b devuelve content vacío. Es un modelo de razonamiento y, por un bug de Ollama, consume todo el presupuesto de tokens en la traza thinking sin llegar a la respuesta. qwen2.5vl:7b no razona y no sufre esto.

El caso: una tabla dentro de un PDF

En Disproquima se compartió un PDF con una tabla de datos técnicos: varias columnas y filas, con agrupaciones mediante celdas combinadas (categorías y subcategorías). La petición fue simple de enunciar: extraer esa tabla.

Lo resolví con mi capacidad nativa de lectura de PDF: leí el documento, interpreté la estructura visual (columnas, agrupaciones, celdas combinadas) y reconstruí los datos en un .xlsx, replicando las agrupaciones con celdas combinadas y aplicando formato (fuente, bordes, encabezados).

Ese proceso —lectura visual + comprensión del layout + reconstrucción estructurada— es exactamente lo que hace un VLM especializado en documentos. De ahí la pregunta que motiva el resto del artículo: ¿qué modelo open-weight replica esto en local?

VLM (Vision-Language Model)

Modelo que combina visión e idioma: no solo transcribe el texto de una imagen, sino que entiende su disposición (qué bloque es una tabla, cuál un encabezado, en qué orden se lee) y puede responder preguntas o devolver un esquema sobre el contenido. Un OCR clásico solo hace lo primero.

Leer caracteres vs entender el documento

Modelo Tipo Puntos fuertes Limitaciones
Tesseract OCR clásico basado en reglas Rápido para texto plano simple, muy liviano Sin comprensión de layout, tablas o estructura; requiere post-procesado manual
GOT-OCR 2.0 (StepFun) OCR neuronal puro, 580M parámetros Texto formateado, fórmulas matemáticas y tablas; corre en GPU de consumo (~4–8,5 GB VRAM) Pierde precisión en layouts muy complejos frente a pipelines dedicados
MinerU / Marker Pipeline (layout + OCR + orden de lectura) El más fuerte en extracción de tablas y documentos estructurados; exporta a Markdown/HTML/DOCX/JSON Más pesado, requiere encadenar varios modelos
Qwen2.5-VL / Qwen3-VL (Alibaba) VLM generalista (7B–72B) OCR + comprensión de layout + preguntas sobre el contenido; permite pedir un esquema JSON directamente Modelo más grande, necesita más recursos que un OCR especializado
DeepSeek-OCR VLM con compresión óptica de contexto Eficiente en documentos largos; layout, tablas, fórmulas, +100 idiomas Modelo más reciente, ecosistema de herramientas menos maduro
Granite-Docling-258M (IBM) VLM compacto OCR, layout, tablas, código y ecuaciones en solo 258M parámetros Menor capacidad en documentos muy heterogéneos

La línea divisoria: Tesseract "lee caracteres"; los modelos modernos (GOT-OCR2, MinerU, Qwen2.5-VL, DeepSeek-OCR) "entienden el documento". Para una tabla como la de Disproquima —donde el significado está en la disposición, no solo en el texto— entender el layout no es opcional.

\"Lee caracteres\" no es un defecto: depende del objetivo

Que Tesseract solo transcriba texto es una limitación para este problema (estructura fiel), no en general. Cuando lo único que quieres es el texto para trocearlo en chunks —el caso de la ingesta de Mentat— un OCR a texto plano es exactamente lo adecuado y más barato. El layout solo estorba cuando lo que buscas es el texto, y hace falta cuando lo que buscas es el dato estructurado.

Caso concreto: extraer campos de facturas

Necesidad: sacar campos estructurados (proveedor, número de factura, fecha, líneas de producto, totales) de facturas, en local.

Recomendación: Qwen2.5-VL-7B (o Qwen3-VL-8B)

  • Corre en una sola GPU local, incluso cuantizado (Ollama, vLLM).
  • Le pasas el esquema en el prompt (vendor, invoice_number, date, line_items, subtotal, tax, total) y devuelve JSON estructurado, sin pipeline adicional.
  • Maneja bien las relaciones espaciales entre etiquetas y valores, algo que un OCR puro no infiere.
Opción Recursos Precisión en layouts variables Salida Cuándo usarla
Qwen2.5-VL-7B / Qwen3-VL-8B 1 GPU, cuantizable Alta JSON con esquema definido Punto de partida; buen balance precisión/recursos
Qwen2.5-VL-72B / DeepSeek-VL2 GPU grande Muy alta JSON Facturas escaneadas de baja calidad o formatos muy heterogéneos
PaddleOCR (PP-OCRv4) + reglas/LLM pequeño CPU Media (depende de las reglas) Texto + campos vía reglas Volumen muy alto, presupuesto ajustado
invoice2data CPU, sin GPU Baja fuera de la plantilla Campos vía regex/plantilla Proveedor único con formato fijo

Caso concreto: certificados (texto + tablas + fórmulas) para recomponer un documento

Necesidad: extraer el contenido de un certificado —texto, tablas y fórmulas— preservando la estructura completa para reconstruirlo en un certificado nuevo.

Recomendación: Marker (MinerU/Datalab)

  • Convierte el documento directamente a Markdown, HTML, JSON o DOCX, con tablas, formularios y ecuaciones ya reconstruidas: el formato ideal para recomponer.
  • Flag opcional --use_llm para mejorar la fidelidad de tablas y formularios complejos.
  • Corre localmente; admite PDF, imágenes, DOCX, XLSX y PPTX como entrada.

Flujo sugerido

Marker para extraer el contenido estructurado (tablas y fórmulas intactas) → usar ese Markdown/JSON como base para generar el nuevo certificado. Si además hay que decidir qué campos cambiar (no solo copiarlos), añade un VLM generalista (Qwen2.5-VL / Qwen3-VL) encima.

Opción Recursos Fidelidad tablas/fórmulas Salida Cuándo usarla
Marker (MinerU/Datalab) GPU local, pipeline de varios modelos Muy alta Markdown, HTML, DOCX, JSON Recomendado; salida ya lista para recomponer
DeepSeek-OCR GPU, eficiente en documentos largos Alta Markdown, HTML de tablas, JSON Certificados extensos o con mucho texto
Qwen2.5-VL / Qwen3-VL 1 GPU (7B–8B) o más Alta Texto libre, JSON a medida Cuando además hay que razonar qué campos cambiar
Granite-Docling-258M Muy bajo (258M) Media DocTags Recursos muy limitados

Lo que pasó al probarlo en local (MacBook Air M5, 16 GB, Ollama)

La teoría apuntaba a Qwen3-VL como evolución recomendada. Al bajarlo a local —interfaz web de Ollama, mismo PDF con tabla como caso de prueba— el resultado fue otro:

Modelo Entrada Resultado
granite3.2-vision (IBM) PDF No extrae nada
granite3.2-vision (IBM) PNG No extrae nada
qwen3-vl:8b PDF No reconoce la tabla
qwen3-vl:8b PNG Reconoce la tabla visualmente, pero no devuelve respuesta
qwen2.5vl:7b PDF No reconoce la tabla
qwen2.5vl:7b PNG Funciona: respuesta rápida y precisa

Tres hallazgos, en orden de importancia:

El PDF nunca llega como imagen. El fallo con PDF es constante en todos los modelos. La causa no es el modelo: la web de Ollama extrae el texto plano del PDF en lugar de convertir la página a imagen, así que el modelo de visión no llega a "ver" la tabla. La solución es rasterizar el PDF a PNG antes de subirlo (o automatizarlo, más abajo).

qwen3-vl:8b sí ve la tabla, pero responde en vacío. Reconoce la tabla en el PNG, pero no muestra respuesta.

\"Thinking\" (razonamiento) en Ollama

Algunos modelos generan primero una traza de razonamiento interno y luego la respuesta. Ollama las separa en dos campos: thinking (la traza) y content (la respuesta final). qwen3-vl es de estos; qwen2.5vl no.

El motivo del vacío es un bug conocido de Ollama: el parámetro para desactivar el razonamiento (think: false) no se aplica bien a qwen3-vl, de modo que todo el presupuesto de tokens se consume en la traza thinking y el campo content queda vacío.

qwen2.5vl:7b no razona, así que responde directo. Al no tener fase de thinking, escribe la respuesta en content sin ese problema y, además, fue notablemente más rápido.

granite3.2-vision no funcionó en ningún escenario, ni con PDF ni con PNG. Coincide con fallos ya documentados en el repositorio de Ollama al procesar imágenes con este modelo.

Workaround: PDF multipágina y el vacío de Qwen3-VL

Convertir a mano cada página a PNG vale para un documento suelto, no para PDFs de varias páginas. Se automatiza con un paquete que gestione el pipeline completo (PDF → imagen por página → modelo de visión → resultado combinado), como ollama-ocr. La técnica es genérica: sirve para qwen2.5vl, qwen3-vl y cualquier modelo de visión de Ollama, porque el paquete solo rasteriza cada página y la manda al modelo indicado.

pip install ollama-ocr
from ollama_ocr import OCRProcessor

ocr = OCRProcessor(model_name='qwen2.5vl:7b')  # o 'qwen3-vl:8b'

result = ocr.process_image(
    image_path="documento.pdf",   # acepta PDF multipágina directamente
    format_type="table",
    custom_prompt="Extrae todas las tablas de cada página, respetando filas y columnas."
)
print(result)

Con qwen3-vl el vacío puede persistir también aquí

El bug de thinking afecta igual a este flujo: content puede seguir llegando vacío si el paquete no gestiona el campo thinking o no reserva presupuesto de tokens para la respuesta tras el razonamiento. Opciones, de menos a más recomendable:

  • Subir mucho el límite de tokens de salida (num_predict) para dejar margen al razonamiento y a la respuesta.
  • Parsear también el campo thinking de la API, porque ahí puede estar el contenido extraído aunque content venga vacío.
  • Lo más simple y lo que recomendamos: usar qwen2.5vl:7b en vez de qwen3-vl:8b. No razona, no sufre el bug y en las pruebas fue más rápido e igual de preciso.

Qué nos llevamos

  1. La recomendación de libro no sobrevivió al hardware. En el papel, Qwen3-VL era la evolución a elegir; en local con Ollama, qwen2.5vl:7b ganó porque qwen3-vl:8b devuelve content vacío por un bug de thinking. Probar en local no es un trámite: es donde se decide.
  2. Antes de culpar al modelo, mira el pipeline. El fallo con PDF era de todos los modelos porque Ollama pasaba texto plano, no imagen. Un síntoma común a todos los modelos casi nunca es de los modelos.
  3. El razonamiento tiene coste oculto. Un modelo "thinking" puede gastarse el presupuesto de tokens en la traza y dejar la respuesta vacía. Para extracción pura, un modelo sin razonamiento es más simple y más rápido.
  4. Elige por "entender" vs "leer" y por caso de uso. Con estructura (tablas, layout), VLM o pipeline, no OCR clásico. Facturas → Qwen2.5-VL-7B (JSON con esquema); certificados a recomponer → Marker.

Anexo: cómo reproducirlo (la receta)

  1. Rasteriza el PDF a PNG. No subas el PDF a Ollama esperando que el VLM lo "vea": la web extrae texto plano. Convierte cada página a PNG, o usa ollama-ocr para automatizarlo en PDFs multipágina.
  2. Usa qwen2.5vl:7b para extraer tablas en local. Punto de partida: rápido, preciso y sin el bug de thinking. Reserva qwen3-vl:8b solo si necesitas su razonamiento y estás dispuesto a lidiar con num_predict / el campo thinking.
  3. Si content viene vacío, mira thinking. Es la firma del bug de Ollama con modelos de razonamiento: el contenido puede estar en la traza, o hace falta más num_predict.
  4. Descarta granite3.2-vision para imágenes mientras persistan los fallos documentados en Ollama.
  5. Valida con documentos reales del cliente (los peores escaneos incluidos) antes de fijar el modelo: la precisión "en layouts variables" solo se comprueba con tus propios documentos.

Referencias