Firecrawl fecha o círculo: AnyDoc soma os outros 14 formatos ao pipeline que pdf-inspector começou
Por Devy
Há algumas semanas cobrimos pdf-inspector, a biblioteca em Rust do Firecrawl que decide em milissegundos se um PDF precisa de OCR antes de você pagar a alguém para lê-lo. A nota terminava em um lugar confortável: resolvia PDFs e apenas PDFs.
Em 6 de agosto, Firecrawl publicou a outra metade. AnyDoc é uma biblioteca — também em Rust, também MIT, também sem chave de API — que converte 14 formatos de documento para Markdown limpo com uma única chamada:
let markdown = anydoc::to_markdown("informe.docx")?;
E embute pdf-inspector por baixo, então a mesma chamada também resolve PDFs de texto. A frase do anúncio é a tese inteira: “AnyDoc handles all 14 in one dependency-free library.”
Se você mantém um serviço onde os usuários fazem upload de “o que tiverem” — um contrato em .docx, uma planilha .xls exportada em 2009, um pitch deck, um .epub —, hoje você provavelmente tem quatro bibliotecas costuradas com um if sobre a extensão. Esta nota é sobre quanto dessa árvore você pode deletar, e sobre as três coisas que descobri testando-a com documentos em espanhol que a comparação oficial não cobre.
O que cobre, exatamente
Os 14: docx, doc, docm, xlsx, xls, xlsm, pptx, ppt, rtf, odt, ods, odp, epub e csv. Mais PDFs de texto através do pdf-inspector.
Uma precisão sobre a contagem, porque o README e o blog não dizem a mesma coisa: o README enumera muito mais extensões que essas catorze — xlsb, pptm, ppsx, ppsm, pps, pot — e coloca o PDF dentro da lista. Ou seja, “14” é uma contagem por família de formato, não por extensão reconhecida. Na prática cobre mais de 14 sufixos; na prática também, nenhuma das duas listas inclui Google Docs nativos nem HTML, que é onde MarkItDown ainda tem seu território.
O importante para um pipeline real: a detecção é por conteúdo, não por extensão. Copiei um .docx para um arquivo sem extensão e to_markdown() o converteu mesmo assim. Vale marcar a nuance — o helper format_from_path() sim depende do sufixo e me devolveu None nesse mesmo arquivo. A conversão olha os magic bytes; o helper olha o nome. Se seu armazenamento guarda blobs com nomes opacos, use a conversão direta e não o helper.
Instalação
Três registries, um único core em Rust:
cargo add anydoc
npm install @firecrawl/anydoc
pip install firecrawl-anydoc
A instalação de Python baixa uma wheel abi3 pré-compilada de 3,4 MB. Sem toolchain de Rust, sem compilar nada, sem dependências de sistema — que é o ponto onde a maioria dos stacks de parsing pede LibreOffice ou antiword no Dockerfile.
E a mesma cilada que pdf-inspector já tinha: os números de versão não estão alinhados entre registries. PyPI vai em 0.1.7 enquanto o crate e o pacote npm levam seu próprio stream. Fixe por registry e não tente raciocinar entre eles.
A API é curta de propósito:
import anydoc
markdown = anydoc.to_markdown("informe.docx") # string de Markdown
doc = anydoc.to_document(open("informe.docx","rb").read()) # AST estruturado
to_document() é o que importa se você vai fazer chunking: devolve blocos, tabelas, notas e assets como estrutura em vez de texto plano, então você pode segmentar por heading real em lugar de por regex sobre #. Há também build WASM para browser e exemplos de CLI para as três linguagens.
O benchmark do vendor, e por que não é suficiente
Firecrawl publicou uma comparação contra seis conversores sobre 100 documentos reais: AnyDoc tira 81 de qualidade global contra 70 do próximo melhor, com 4,4 ms de mediana por documento, e é a única biblioteca do conjunto que parseia os 14 formatos (LibreOffice cobre 12, e sua mediana fica na faixa de 52 a 1.130 ms).
Leia como afirmação do vendor, não como veredicto, por três razões que o próprio post admite ou que saltam ao comparar fontes:
- O juri é um LLM. A qualidade é pontuada por Claude Sonnet 5 sobre completude, estrutura, formato e limpeza. É uma metodologia razoável e é reproduzível; não é uma métrica objetiva.
- Cada ferramenta faz média apenas dos formatos que suporta. O post diz com todas as letras. O 81 de AnyDoc abrange os 14; o 70 do competidor abrange o subconjunto que esse competidor declara. Você está comparando médias de populações distintas.
- O README e o blog não coincidem. O blog diz 81 e 4,4 ms; o README diz 80 e 4,7 ms. A diferença é irrelevante para sua decisão, mas te diz que há pelo menos duas corridas distintas circulando com o mesmo título.
O corpus, além do mais, é do Firecrawl. Então rodei o meu.
O teste em espanhol
Gerei nove documentos com o que quebra parsers em nossa região e quase nunca aparece em um corpus de teste em inglês: acentos, ñ, aspas latinas «», sinais de abertura ¿ ¡, travessão, ±, €, separador decimal com vírgula, e um CSV exportado como Excel exporta em espanhol — UTF-8 com BOM e delimitador ;. Tudo sobre o binding de Python, mediana de 20 corridas, em um contêiner de nuvem compartilhada (ou seja: os tempos são da minha máquina, não um benchmark limpo).
| Formato | Mediana | O que saiu |
|---|---|---|
rtf |
0,04 ms | Texto e negrito corretos |
odp |
0,09 ms | Apenas o título |
ods |
0,18 ms | Tabela completa |
odt |
0,20 ms | Heading, parágrafo e tabela |
csv |
0,22 ms | Tabela Markdown, BOM e ; resolvidos |
epub |
0,22 ms | Heading, parágrafo, lista + TOC duplicada |
xlsx |
0,26 ms | Tabela, fórmula vazia |
pdf |
1,39 ms | Texto correto, um espaço comido |
pptx |
1,64 ms | Slides + notas do apresentador |
docx |
14,32 ms | Tudo: headings, negrito, itálico, listas, tabela |
O encoding passa limpo nos dez. Zero mojibake, zero ? no lugar de ñ, zero aspas latinas convertidas em lixo. O RTF — que guarda os não-ASCII como escapes \u241? — saiu perfeito. O CSV com BOM e ponto e vírgula também, sem configuração. Esse era o risco real e não se materializou.
O que encontrei sim, três coisas:
As fórmulas do Excel não são avaliadas. Coloquei =SUM(B2:B4) na célula de total e o Markdown traz a linha com a célula vazia:
| Total | | |
É coerente com o design — não há motor de cálculo aqui, e o .xlsx guarda o valor cacheado em um lugar que a biblioteca não lê —, mas se suas planilhas têm totais calculados, o resumo que você passa pro LLM vai ter buracos justo nos números que importam. Verifique antes de colocar em um pipeline financeiro.
O EPUB duplica o título e arrasta a TOC. A saída traz o título como #, outra vez como ##, depois a tabela de conteúdos como lista de links, e só aí o capítulo. Nada quebrado, mas se você faz embeddings sobre isso está indexando ruído de navegação como se fosse conteúdo. Um filtro de duas linhas resolve; você precisa saber que faz falta.
O PDF comeu um espaço. "Informe de facturación — año fiscal 2025" saiu como "Informe de facturacion-ano fiscal 2025" (os acentos os perdeu meu PDF de teste, não a biblioteca; o detalhe é o travessão). É a heurística de re-junção de palavras cortadas de pdf-inspector agindo sobre um travessão rodeado de espaços. Um artefato menor, na borda exata onde a pontuação espanhola e uma heurística pensada em inglês se cruzam.
E uma nota sobre velocidade: o .docx levou 14,3 ms de mediana, umas 65 vezes mais que o .odt equivalente com o mesmo conteúdo. A mediana publicada de 4,4 ms é uma média nos 14 formatos, e os formatos leves — rtf, csv, odf — a empurram para baixo. Se sua carga é 90% Word, dimensione com o número do docx, não com o título. Ainda é duas ordens de magnitude melhor que levantar LibreOffice, mas não é 4 ms.
Uma observação justa sobre o odp: minha apresentação OpenDocument tinha apenas uma caixa de texto, então esse “apenas o título” é o limite do meu arquivo de teste e não necessariamente o da biblioteca.
O que não faz
Não faz OCR. Um PDF escaneado, ou qualquer documento cujo conteúdo sejam imagens de texto, não se resolve aqui: a documentação te manda rotear esses para o endpoint hospedado /parse do Firecrawl. É a mesma divisão de trabalho que já propunha pdf-inspector — classificar local e barato, pagar apenas pelo que de verdade precisa de um modelo.
E convém ter claro o reparto entre os dois repos, porque são deliberadamente produtos separados: pdf-inspector é o especialista em PDF com roteamento para OCR por página; AnyDoc é o generalista dos outros 14 formatos que embutiu o primeiro para não reimplementá-lo. Se seu corpus é puro PDF, ainda quer pdf-inspector direto, com seu ScanStrategy e seu pagesNeedingOcr. Se seu corpus é “o que o usuário enviar”, AnyDoc é a porta única.
Vale uma tarde
A prova honesta aqui não é ler o benchmark, é rodar to_markdown() em cinquenta documentos reais do seu próprio storage — os feios, os de 2009, os que alguém exportou de uma versão do Office que já não existe — e ver a saída. São cinco minutos de setup porque não há que compilar nada, e o resultado é uma resposta concreta: quantas de suas bibliotecas de parsing ficam fazendo um trabalho que agora faz uma única chamada.
Minha aposta, depois do que está acima: a codificação não vai ser seu problema. As fórmulas e o ruído de navegação sim.
E você? Quantas bibliotecas de parsing tem cosidas atrás daquele if sobre a extensão — e qual de todas é a que sempre quebra?
Fontes:
firecrawl/anydoc— GitHub (MIT)- Introducing AnyDoc and pdf-inspector — Firecrawl Blog (6 de agosto de 2026)
- pdf-inspector: classifica o PDF antes de pagar a um OCR — yoDEV
- MarkItDown: a ferramenta da Microsoft que converte qualquer documento em contexto para sua IA — yoDEV
- Testes próprios:
firecrawl-anydoc0.1.7, binding do Python, nove documentos gerados em espanhol, mediana de 20 rodadas