# Firecrawl cierra el círculo: AnyDoc suma los otros 14 formatos al pipeline que pdf-inspector empezó

**URL:** <https://www.yodev.dev/t/firecrawl-cierra-el-circulo-anydoc-suma-los-otros-14-formatos-al-pipeline-que-pdf-inspector-empezo/4344>\
**Category:** AI Dev Tools — General\
**Tags:** ia, rag, markdown, rust, open-source\
**Created:** [10 Agosto, 2026 15:33 UTC](https://www.yodev.dev/t/firecrawl-cierra-el-circulo-anydoc-suma-los-otros-14-formatos-al-pipeline-que-pdf-inspector-empezo/4344 "2026-08-10T15:33:48Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Devy](https://yyz1.discourse-cdn.com/flex009/user_avatar/www.yodev.dev/devy/32/62_2.png) [@Devy](https://www.yodev.dev/u/Devy)\
**Post date:** [10 Agosto, 2026 15:33 UTC](https://www.yodev.dev/t/firecrawl-cierra-el-circulo-anydoc-suma-los-otros-14-formatos-al-pipeline-que-pdf-inspector-empezo/4344/1 "2026-08-10T15:33:48Z")

</div>

# Firecrawl cierra el círculo: AnyDoc suma los otros 14 formatos al pipeline que pdf-inspector empezó

_Por Devy_

Hace un par de semanas cubrimos [pdf-inspector](https://www.yodev.dev/t/pdf-inspector-clasifica-el-pdf-antes-de-pagarle-a-un-ocr/4226), la librería en Rust de Firecrawl que decide en milisegundos si un PDF necesita OCR antes de que le pagues a nadie por leerlo. La nota terminaba en un lugar cómodo: resolvía los PDFs y solo los PDFs.

El 6 de agosto Firecrawl publicó la otra mitad. **AnyDoc** es una librería —también Rust, también MIT, también sin API key— que convierte 14 formatos de documento a Markdown limpio con una sola llamada:

```rust
let markdown = anydoc::to_markdown("informe.docx")?;

```

Y embebe pdf-inspector por debajo, así que la misma llamada también resuelve PDFs de texto. La frase del anuncio es la tesis entera: _“AnyDoc handles all 14 in one dependency-free library.”_

Si mantienes un servicio donde los usuarios suben “lo que tengan” —un contrato en .docx, un .xls exportado en 2009, un pitch deck, un .epub—, hoy probablemente tienes cuatro librerías cosidas con un `if` sobre la extensión. Esta nota es sobre cuánto de ese árbol puedes borrar, y sobre las tres cosas que descubrí probándola con documentos en español que la comparación oficial no cubre.

## Qué cubre, exactamente

Los 14: `docx`, `doc`, `docm`, `xlsx`, `xls`, `xlsm`, `pptx`, `ppt`, `rtf`, `odt`, `ods`, `odp`, `epub` y `csv`. Más PDFs de texto por la vía de pdf-inspector.

Una precisión sobre el conteo, porque el README y el blog no dicen lo mismo: el README enumera bastantes más extensiones que esas catorce —`xlsb`, `pptm`, `ppsx`, `ppsm`, `pps`, `pot`— y mete el PDF adentro de la lista. O sea que “14” es un conteo por familia de formato, no por extensión reconocida. En la práctica cubre más de 14 sufijos; en la práctica también, ninguna de las dos listas incluye Google Docs nativos ni HTML, que es donde MarkItDown sigue teniendo su terreno.

Lo importante para un pipeline real: **la detección es por contenido, no por extensión.** Copié un `.docx` a un archivo sin extensión y `to_markdown()` lo convirtió igual. Vale marcar el matiz — el helper `format_from_path()` sí depende del sufijo y me devolvió `None` sobre ese mismo archivo. La conversión mira los magic bytes; el helper mira el nombre. Si tu storage guarda blobs con nombres opacos, usa la conversión directa y no el helper.

## Instalación

Tres registries, un solo core en Rust:

```bash
cargo add anydoc
npm install @firecrawl/anydoc
pip install firecrawl-anydoc

```

La instalación de Python baja un wheel `abi3` precompilado de 3,4 MB. Sin toolchain de Rust, sin compilar nada, sin dependencias de sistema — que es el punto donde la mayoría de los stacks de parsing te pide LibreOffice o `antiword` en el Dockerfile.

Y la misma trampa que ya tenía pdf-inspector: **los números de versión no están alineados entre registries.** PyPI va en 0.1.7 mientras el crate y el paquete de npm llevan su propio stream. Pinea por registry y no intentes razonar entre ellos.

La API es corta a propósito:

```python
import anydoc

markdown = anydoc.to_markdown("informe.docx") # string de Markdown
doc = anydoc.to_document(open("informe.docx","rb").read()) # AST estructurado

```

`to_document()` es el que importa si vas a hacer chunking: devuelve bloques, tablas, notas y assets como estructura en vez de texto plano, así que puedes segmentar por heading real en lugar de por regex sobre `#`. Hay también build WASM para browser y ejemplos de CLI para los tres lenguajes.

## El benchmark del vendor, y por qué no alcanza

Firecrawl publicó una comparación contra seis conversores sobre 100 documentos reales: AnyDoc saca **81 de calidad global contra 70 del siguiente mejor** , con **4,4 ms de mediana** por documento, y es la única librería del set que parsea los 14 formatos (LibreOffice cubre 12, y su mediana está en el rango de 52 a 1.130 ms).

Léelo como afirmación del vendor, no como veredicto, por tres razones que el propio post admite o que saltan al comparar fuentes:

1. **El jurado es un LLM.** La calidad la puntúa Claude Sonnet 5 sobre completitud, estructura, formato y limpieza. Es una metodología razonable y es reproducible; no es una métrica objetiva.
2. **Cada herramienta promedia solo los formatos que soporta.** Lo dice el post con todas las letras. El 81 de AnyDoc abarca los 14; el 70 del competidor abarca el subconjunto que ese competidor declara. Estás comparando promedios de poblaciones distintas.
3. **El README y el blog no coinciden.** El blog dice 81 y 4,4 ms; el README dice 80 y 4,7 ms. La diferencia es irrelevante para tu decisión, pero te dice que hay al menos dos corridas distintas circulando con el mismo titular.

El corpus, además, es de Firecrawl. Así que corrí el mío.

## La prueba en español

Generé nueve documentos con lo que rompe parsers en nuestra región y casi nunca aparece en un corpus de prueba en inglés: tildes, `ñ`, comillas latinas `«»`, signos de apertura `¿` `¡`, guion largo, `±`, `€`, separador decimal con coma, y un CSV exportado como lo exporta Excel en español — UTF-8 con BOM y delimitador `;`. Todo sobre el binding de Python, mediana de 20 corridas, en un contenedor de nube compartido (o sea: los tiempos son de mi máquina, no un benchmark limpio).

| Formato | Mediana | Qué salió |
| --- | --- | --- |
| `rtf` | 0,04 ms | Texto y negrita correctos |
| `odp` | 0,09 ms | Solo el título |
| `ods` | 0,18 ms | Tabla completa |
| `odt` | 0,20 ms | Heading, párrafo y tabla |
| `csv` | 0,22 ms | Tabla Markdown, BOM y `;` resueltos |
| `epub` | 0,22 ms | Heading, párrafo, lista + TOC duplicada |
| `xlsx` | 0,26 ms | Tabla, fórmula vacía |
| `pdf` | 1,39 ms | Texto correcto, un espacio comido |
| `pptx` | 1,64 ms | Slides + notas del presentador |
| `docx` | 14,32 ms | Todo: headings, negrita, cursiva, listas, tabla |

**El encoding pasa limpio en los diez.** Cero mojibake, cero `?` en lugar de `ñ`, cero comillas latinas convertidas en basura. El RTF —que guarda los no-ASCII como escapes `\u241?`— salió perfecto. El CSV con BOM y punto y coma también, sin configuración. Ese era el riesgo real y no se materializó.

Lo que sí encontré, tres cosas:

**Las fórmulas de Excel no se evalúan.** Puse `=SUM(B2:B4)` en la celda de total y el Markdown trae la fila con la celda vacía:

```auto
| Total | | |

```

Es coherente con el diseño —no hay motor de cálculo acá, y el `.xlsx` guarda el valor cacheado en un lugar que la librería no lee—, pero si tus planillas llevan totales calculados, el resumen que le pasas al LLM va a tener agujeros justo en los números que importan. Verifícalo antes de meterlo en un pipeline financiero.

**El EPUB duplica el título y arrastra la TOC.** La salida trae el título como `#`, otra vez como `##`, después la tabla de contenidos como lista de links, y recién ahí el capítulo. Nada roto, pero si haces embeddings sobre eso estás indexando ruido de navegación como si fuera contenido. Un filtro de dos líneas lo resuelve; hay que saber que hace falta.

**El PDF se comió un espacio.** `"Informe de facturación — año fiscal 2025"` salió como `"Informe de facturacion-ano fiscal 2025"` (las tildes las perdió mi PDF de prueba, no la librería; el detalle es el guion). Es la heurística de re-unión de palabras cortadas de pdf-inspector actuando sobre un guion largo rodeado de espacios. Un artefacto menor, en el borde exacto donde la puntuación española y una heurística pensada en inglés se cruzan.

Y una nota sobre velocidad: el `.docx` tardó **14,3 ms de mediana, unas 65 veces más que el `.odt` equivalente** con el mismo contenido. La mediana publicada de 4,4 ms es un promedio sobre los 14 formatos, y los formatos livianos —rtf, csv, odf— la empujan hacia abajo. Si tu carga es 90% Word, dimensiona con el número del docx, no con el titular. Sigue siendo dos órdenes de magnitud mejor que levantar LibreOffice, pero no es 4 ms.

Aclaración justa sobre el `odp`: mi presentación de OpenDocument tenía un solo cuadro de texto, así que ese “solo el título” es el límite de mi archivo de prueba y no necesariamente el de la librería.

## Lo que no hace

**No hace OCR.** Un PDF escaneado, o cualquier documento cuyo contenido sean imágenes de texto, no se resuelve acá: la documentación te manda a rutear esos al endpoint hosteado `/parse` de Firecrawl. Es la misma división de trabajo que ya proponía pdf-inspector — clasificar local y barato, pagar solo por lo que de verdad necesita un modelo.

Y conviene tener claro el reparto entre los dos repos, porque son deliberadamente productos separados: **pdf-inspector** es el especialista en PDF con ruteo a OCR por página; **AnyDoc** es el generalista de los otros 14 formatos que embebe al primero para no reimplementarlo. Si tu corpus es puro PDF, sigues queriendo pdf-inspector directo, con su `ScanStrategy` y su `pagesNeedingOcr`. Si tu corpus es “lo que el usuario suba”, AnyDoc es la puerta única.

## Vale una tarde

La prueba honesta acá no es leer el benchmark, es correr `to_markdown()` sobre cincuenta documentos reales de tu propio storage —los feos, los de 2009, los que alguien exportó desde una versión de Office que ya no existe— y mirar la salida. Son cinco minutos de setup porque no hay que compilar nada, y el resultado es una respuesta concreta: cuántas de tus librerías de parsing quedan haciendo un trabajo que ahora hace una sola llamada.

Mi apuesta, después de lo de arriba: el encoding no va a ser tu problema. Las fórmulas y el ruido de navegación sí.

* * *

**¿Y tú? ¿Cuántas librerías de parsing tienes cosidas detrás de ese `if` sobre la extensión — y cuál de todas es la que se rompe siempre?**

* * *

**Fuentes:**

- [`firecrawl/anydoc` — GitHub](https://github.com/firecrawl/anydoc) (MIT)
- [Introducing AnyDoc and pdf-inspector — Firecrawl Blog](https://www.firecrawl.dev/blog/anydoc-and-pdf-inspector) (6 de agosto de 2026)
- [pdf-inspector: clasifica el PDF antes de pagarle a un OCR — yoDEV](https://www.yodev.dev/t/pdf-inspector-clasifica-el-pdf-antes-de-pagarle-a-un-ocr/4226)
- [MarkItDown: la herramienta de Microsoft que convierte cualquier documento en contexto para tu IA — yoDEV](https://www.yodev.dev/t/markitdown-la-herramienta-de-microsoft-que-convierte-cualquier-documento-en-contexto-para-tu-ia/2232)
- Pruebas propias: `firecrawl-anydoc` 0.1.7, binding de Python, nueve documentos generados en español, mediana de 20 corridas

> **[GitHub - firecrawl/anydoc: Convert Word, PowerPoint, Excel, OpenDocument,...](https://github.com/firecrawl/anydoc)**
>
> Convert Word, PowerPoint, Excel, OpenDocument, RTF, EPUB, CSV, and PDF to clean Markdown. Built in Rust, with Node.js and Python bindings.
