RAG & Documentos
¿Qué parser de PDF usar para RAG en español? 6 librerías medidas con facturas y dos columnas
Solo PyMuPDF4LLM y Docling dejan el 100 % de las filas de factura en una línea; pypdf y PyMuPDF, el 0 %. Docling es el único que quita los pies de página, a 471,7 ms por página.
- Fecha
- 22 oct 2026
- Lectura
- 8 min
- Resultado
- 100 % de filas de factura íntegras con PyMuPDF4LLM y Docling • 0 % con pypdf y PyMuPDF • de 2,1 a 471,7 ms por página
Para un RAG en español con facturas y tablas, PyMuPDF4LLM y Docling son los únicos de los 6 parsers probados que dejan el 100 % de las filas (concepto, precio y total) en una sola línea; pypdf y PyMuPDF, el 0 %. Docling es además el único que elimina los pies de página (los demás dejan el 100 % dentro del texto), pero tarda 471,7 ms por página frente a los 230,5 ms de PyMuPDF4LLM y los 2,1 ms de PyMuPDF. Ninguno pierde tildes, eñes, ¿ ¡, « » ni €. Medido el 22 de octubre de 2026 con 36 PDF (60 páginas) generados con su texto de referencia exacto.
La pregunta «¿qué parser de PDF uso para RAG?» se repite en foros, issues y blogs, casi siempre con documentos en inglés, una captura de una página o el benchmark de un proveedor que vende su propio parser. Aquí está la medida en español, con corpus, código y salidas publicados.
Definiciones
- Parser de PDF: la librería que convierte el PDF en texto (o Markdown) antes de trocearlo en fragmentos para el RAG. Lo que el parser rompe, el buscador ya no lo puede recuperar.
- Fila íntegra: el concepto, el precio unitario y el total de una línea de factura salen juntos, en la misma línea y en orden. Si salen en líneas separadas, un fragmento puede quedarse con el concepto y otro con el importe.
- Párrafo íntegro: el párrafo de la referencia aparece entero y seguido en la salida (ignorando espacios, saltos de línea y marcas de Markdown).
- Pie colado: el pie «Página N» aparece en la salida y acaba en mitad del texto que se trocea.
Hipótesis
- Los parsers simples (pypdf, PyMuPDF) pierden la estructura de las tablas.
- Los que reconstruyen la maquetación (PyMuPDF4LLM, Docling) la conservan, a cambio de tiempo y memoria.
- Los caracteres del español (tildes, ñ, ¿ ¡, « », €) se pierden o se corrompen en alguno.
- Las dos columnas confunden a los parsers que leen línea a línea.
Montaje
- Corpus: 36 PDF digitales generados con ReportLab y semilla fija, con el texto exacto guardado como referencia: 12 informes a una columna, 12 a dos columnas y 12 facturas con importes en formato español (1.234,56 €); en 6 de ellas los conceptos ocupan varias líneas dentro de la celda. Cada página lleva el pie «Página N». En total, 60 páginas.
- Parsers (6): pypdf, pdfplumber, PyMuPDF (
get_text), PyMuPDF4LLM (to_markdown), MarkItDown y Docling, cada uno con su llamada más sencilla y su configuración por defecto (Docling con OCR automático y TableFormer en modo preciso). - Repeticiones: 5 por parser, cada una en un proceso nuevo y en orden intercalado, tras una pasada de calentamiento. Tiempo del corpus completo y pico de memoria del proceso; el tiempo de importación se mide aparte.
- Equipo: portátil Apple M1 Max con 64 GB, macOS 26.6.2, Python 3.12.4.
Resultados
Calidad del texto extraído
| Parser | Filas íntegras (facturas) | Filas íntegras (conceptos largos) | Párrafos íntegros (1 columna) | Párrafos íntegros (2 columnas) | Pies colados |
|---|---|---|---|---|---|
| Docling | 100 % | 100 % | 100 % | 97,13 % | 0 % |
| PyMuPDF4LLM | 100 % | 100 % | 96,34 % | 93,13 % | 100 % |
| pdfplumber | 74,16 % | 48,32 % | 96,34 % | 20,75 % | 100 % |
| MarkItDown | 74,16 % | 48,32 % | 96,34 % | 12,46 % | 100 % |
| PyMuPDF | 0 % | 0 % | 96,34 % | 95,29 % | 100 % |
| pypdf | 0 % | 0 % | 96,34 % | 95,29 % | 100 % |
Los seis conservan el 100 % de los caracteres especiales del español y el 100 % de las celdas de concepto, precio y total en las facturas con conceptos cortos. La diferencia está en cómo los colocan:
- pypdf y PyMuPDF sacan cada celda en su propia línea: «Concepto», «Cantidad», «Precio unitario»… uno debajo de otro. Están todos los datos (100 % de celdas), pero ninguna fila queda junta.
- pdfplumber y MarkItDown juntan la fila en una línea, pero cuando el concepto ocupa dos líneas en la celda, la segunda mitad sale en una línea aparte, sin importes: el 48,32 % de filas íntegras en esas facturas. En dos columnas mezclan las líneas de una columna con las de la otra: solo el 20,75 % y el 12,46 % de los párrafos salen enteros, y la similitud con el texto original cae al 46,79 % y al 43,09 %.
- PyMuPDF4LLM y Docling devuelven las facturas como tablas de Markdown con una fila por línea, también con conceptos largos.
- El 96,34 % de una columna no es un fallo de lectura: es el párrafo que cruza el salto de página, partido por el pie «Página N». Docling lo reconoce como pie y lo quita; los otros cinco lo dejan dentro.
- Docling tampoco es perfecto en dos columnas: en 5 de los 12 informes cambió de orden trozos de línea en el salto de columna (97,13 % de párrafos íntegros).
Tiempo y memoria (mediana de 5 repeticiones)
| Parser | Corpus completo (60 páginas) | Por página | Importación | Pico de memoria |
|---|---|---|---|---|
| PyMuPDF | 0,13 s | 2,1 ms | 0,97 s | 313 MB |
| pypdf | 0,25 s | 4,2 ms | 0,21 s | 89,7 MB |
| pdfplumber | 2,39 s | 39,8 ms | 0,15 s | 95,6 MB |
| MarkItDown | 3,17 s | 52,8 ms | 1,46 s | 193,3 MB |
| PyMuPDF4LLM | 13,83 s | 230,5 ms | 0,97 s | 712,4 MB |
| Docling | 28,3 s | 471,7 ms | 5,97 s | 1298,7 MB |
La dispersión es baja: el tiempo por página de Docling va de 466,3 a 484,8 ms entre repeticiones y el de PyMuPDF4LLM, de 229,6 a 241 ms. Los seis dieron una salida idéntica (misma huella SHA-256) en las 5 repeticiones.
PyMuPDF ya no es ligero en memoria. PyMuPDF 2.0 declara como dependencias pymupdf-layout, onnxruntime y pymupdf4llm, y import pymupdf los carga. Repetido en un entorno donde solo se instaló PyMuPDF, el pico fue de 317,9 MB (mediana), así que no es efecto de compartir entorno con los demás.
Qué significa
- Hipótesis 1 y 2: se cumplen. Con pypdf o PyMuPDF, una factura troceada para RAG separa conceptos e importes; con PyMuPDF4LLM o Docling, cada línea de factura viaja entera en el mismo fragmento.
- Hipótesis 3: no se cumple. En PDF digitales, ninguno pierde tildes, ñ, ¿ ¡, « » ni €. El problema del español no está en los caracteres, está en la estructura.
- Hipótesis 4: se cumple a medias. Las dos columnas solo hunden a pdfplumber y MarkItDown; pypdf y PyMuPDF siguen el orden de los bloques y aguantan.
- Los pies de página son el fallo silencioso. Cinco de seis parsers meten «Página N» en mitad de los párrafos. Si no los filtras, ensucian los fragmentos y los embeddings.
Cuándo usar cada opción
- Facturas, presupuestos o cualquier PDF con tablas: PyMuPDF4LLM. Mismas filas íntegras que Docling a menos de la mitad del tiempo por página y con 712,4 MB frente a 1298,7 MB. Añade un filtro de pies y cabeceras.
- Documentos donde importa la maquetación (pies, cabeceras, varias columnas) y el volumen es moderado: Docling. Es el único que quita los pies sin ayuda; cuenta con casi medio segundo por página en un portátil y 5,97 s de arranque.
- Texto corrido a una columna, volumen alto y sin tablas: PyMuPDF (2,1 ms por página) o pypdf (4,2 ms por página y 89,7 MB). Ojo a la licencia: PyMuPDF y PyMuPDF4LLM son AGPL o comercial; pypdf es BSD.
- pdfplumber: para sacar tablas con su API de tablas, no con
extract_texten documentos a dos columnas. - MarkItDown: en PDF se comporta como pdfplumber en este corpus; su ventaja es convertir muchos formatos (Word, Excel, HTML) con una sola llamada, no la calidad en PDF.
Limitaciones
- Corpus sintético: 36 PDF generados con ReportLab, limpios y digitales. PDF escaneados, facturas de proveedores reales, tablas sin bordes o celdas combinadas pueden dar otro resultado. A cambio, la referencia es exacta y el corpus se puede publicar.
- Las frases «con un coste de …» llevan el símbolo € duplicado por un error del generador. Está igual en el PDF y en la referencia, así que no cambia la comparación.
- Cada parser se probó con su configuración por defecto. pdfplumber tiene
extract_tables, PyMuPDF tienefind_tablesy Docling permite desactivar el OCR o usar el modo rápido de TableFormer: no se midieron. - No se probaron parsers de pago ni servicios en la nube (LlamaParse, Azure Document Intelligence, Unstructured en la API), ni modelos de visión.
- La métrica de filas íntegras exige concepto, precio y total en la misma línea. Un parser que separa celdas con otro criterio coherente puntuaría 0 % aunque un chunker por tablas pudiera recomponerlas.
- Un solo portátil Apple Silicon con otras apps abiertas. Docling usa PyTorch y su tiempo cambia mucho con la GPU disponible; las cifras sirven para el orden de magnitud.
Cómo repetirlo
Código, corpus, salidas de cada parser y resultados en bruto (tiempos por documento, memoria por repetición y calidad por PDF): yeswelab-laboratorio/parsers-pdf-rag-espanol-tablas en GitHub. Se ejecuta en menos de 10 minutos sin cuentas ni claves; Docling descarga sus modelos de Hugging Face la primera vez.
Relacionado
- ¿Cuántos tokens más gasta el español que el inglés?
- Structured outputs con salidas reales: qué errores de JSON cometen los LLM
- Context engineering y context bloat en agentes de IA
¿Tienes un RAG que responde mal con tus PDF y no sabes si el problema es el parser, el troceo o el modelo? Encárganos el experimento con tus documentos.