多格式文档统一解析Anydoc:简介、实战

概述

英文官网中文官网,把网页抓取做成开发者基础设施的Firecrawl团队,使用Rust+Python开发、于26年7月30号开源(GitHub,17.4K Star,996 Fork)Anydoc,面向AI时代的底层文档转换基础设施,解决多格式办公文档统一解析的痛点。也是Firecrawl Parse的底层实现。

区别于Pandoc、LibreOffice这类传统方案,以Rust实现做到毫秒级处理、轻量化部署、输出格式统一,非常适合私有化RAG知识库、AI Agent文档读取、企业文档批量归档等场景。

竞品分析:

  • Pandoc:转换表格会错乱
  • mammoth:只处理Word
  • markitdown:只能处理六种格式
  • LibreOffice:部署笨重还耗资源,命令行速度慢
  • 在线转换工具:隐私没法保证

核心特性

  • 统一输出标准:所有格式先解析进同一个文档模型,再由同一个Markdown序列化器渲染。标题(带锚点)、粗体/斜体/删除线、行内代码与代码块、链接与内部交叉引用、项目符号/编号/嵌套/任务列表(保留源编号样式)、带合并单元格的表格、块引用、脚注与尾注、演讲者备注,跨格式行为完全一致;
  • 嵌入式资源保留:图片和嵌入对象在Markdown中以alt文本呈现,原始字节保留在文档模型上并标注媒体类型;外部URL图片转为普通Markdown图片;
  • 基于内容的格式检测:从字节内容本身识别格式(PDF头、RTF起始组、OLE流名、ZIP包mimetype),即使文件扩展名错误也能正确转换;
  • 毫秒级性能:纯Rust实现,单文档中位转换耗时<5ms;
  • PDF本地直转:文本型PDF通过pdf-inspector本地转换,无需OCR服务;
  • 多端绑定:Node.jslibuv线程池,不阻塞事件循环)、Python(释放GIL)、WebAssembly(浏览器端本地转换,文件不出设备)、CLI、Agent Skill;
  • Agent就绪:一条npx skills add firecrawl/anydoc命令,即可让Codex等AI代理直接读取办公文档;
  • 安全性:内置解压、嵌套深度、节点数等固定安全限制,防范zip炸弹等恶意文件;
  • 测试完备:快照测试、变异测试(mutation testing)、每格式cargo-fuzz模糊测试目标。

优势特性:

  • 快:纯Rust、无外部服务调用、无网络调用、不依赖ML模型、不开子进程、纯内存、内置资源限制;
  • LLM友好:页眉页脚页码这类噪音默认剔除,脚注、演讲者备注、合并单元格、嵌套列表这些有信息量的结构会尽量保留,图片和嵌入对象以alt文本形式呈现,原始字节保留在文档模型上随时可取;
  • 统一:采用统一内部文档模型架构,一套内核处理全部文件格式。

核心能力

  1. 极致转换性能,无AI模型依赖(性能模块)
    • 纯Rust实现,不依赖GPU、不加载大模型,单文档转换中位数耗时5ms以内,对比LibreOffice方案速度提升百倍级别图片
    • 高吞吐,适合批量文档流水线处理,生产环境高并发场景压力小
    • 浏览器WASM编译版本,文件完全本地解析,数据不会上传服务器,保护敏感资料隐私
  2. 多格式强兼容,字节级文件识别(解析模块)
    • 不靠文件后缀判断格式,读取文件字节流识别真实文件类型,修改后缀名的损坏文件也可以正常解析
    • 完整保留标题层级、嵌套列表、合并单元格表格、脚注、PPT演讲备注等复杂排版信息
    • 统一内部文档模型,修复一处解析Bug,全部格式同步受益,不用每种文档单独维护解析器
  3. 多语言SDK+CLI命令行,适配各类开发场景(接口模块)
    • CLI工具:直接命令行完成单文件、批量文档转换,脚本流水线直接调用
    • Python、Node.js等SDK,快速集成进RAG服务、后端业务代码
    • WASM版本:前端页面直接上传文档浏览器本地转换,不需要后端中转
    • Agent Skill原生支持,Cursor等AI编程Agent可以直接调用读取本地各类文档
  4. LLM友好标准化输出(输出渲染模块)
    • 统一输出GitHub标准Markdown,格式干净规整,非常适合后续切片、向量化、检索入库
    • 图片资源保留文档模型资产列表,可自行导出处理
    • 输出风格统一,Word、PPT、PDF输出后结构表现一致,降低大模型理解文档的难度
  5. 轻量化部署,无重型依赖(部署模块)
    • 不需要安装LibreOffice、Office套件,二进制直接运行,容器镜像体积很小
    • 可嵌入程序,也可独立作为转换服务;支持本地开发、私有化部署,不用调用第三方API

格式支持列表

  • Word:.doc.docx.docm
  • PowerPoint:.ppt.pptx.pps.pot.pptm.ppsx.ppsm等7种变体
  • Excel:.xls.xlsx.xlsm.xlsb
  • OpenDocument:.odt.ods.odp
  • 其他:RTF、EPUB、CSV、PDF

性能测试:参考官方性能测试

适用场景:

  • AI Agent读取文档:一行命令让Cursor等AI工具读取任意办公文档:npx skills add firecrawl/anydoc
  • 文档批量入库:做知识库、RAG系统
  • 内容迁移:从老旧系统导出Word、RTF文件,转成Markdown放到GitHub或发布到博客

原理

四层解析架构

  • 内容探测优先于扩展名:格式从字节本身读出,PDF头、RTF开组、OLE流名、ZIP包mimetype。修改文件后缀名,依然能正确识别并完成转换
  • 每格式一个解析器,统一汇入共享Document模型:块、行内样式、表格、脚注、嵌入资产都进同一个中间表示
  • GFM(GitHub风格Markdown,GitHub Flavored Markdown)序列化器:转义、表格、标题锚点行为对所有格式一致,修一处表格转义Bug,.docx.rtf.odt同时受益
  • PDF:文本型PDF经内置pdf-inspector本地直转,扫描件PDF使用Firecrawl云端OCR API服务

关键依赖:

依赖 用途
Rust 核心语言,编译为原生库/WebAssembly
calamine Excel(xlsx、xls、xlsb等)解析
pdf-inspector PDF本地转换
flate2 压缩流处理
wasm-bindgen WebAssembly绑定
maturin Python打包

实战

官网

打开官网,在线体验:

实测截图:

  • 首先看看14KB小文档.docx

    确实非常快,比Office-CLI都快几倍。
  • 多Sheet旧版.xls文件貌似自动转为.xlsx文件,用##区分不同Sheet,3.16M文件耗时仅522ms:

    支持下载,得到表格形式markdown文件。
  • 再看看.pptx文件,没什么大问题。一页PPT就是一个##小标题

    幻灯片的备注会被翻译为引用(即>格式)

    PPT里的代码片段会有格式错乱问题,原始PPT是这样:

    识别后的.md格式:

CLI

npx命令无需安装环境?推荐体验

bash 复制代码
# 安装
npm install @firecrawl/anydoc
# 转换docx输出到标准输出,默认markdown
npx @firecrawl/anydoc contract.docx
# 等价命令
npx anydoc contract.docx -o contract.md
# 转换ppt并输出到指定markdown文件
npx @firecrawl/anydoc plan.pptx -o plan.md
# 从标准输入读取
npx @firecrawl/anydoc - --format csv < data.csv

Python

Python开发者,安装:pip install firecrawl-anydoc

入门示例:

py 复制代码
import anydoc

# docx 2 md
markdown = anydoc.to_markdown("1980年代的爱情.docx")
#print(markdown)
# xls 2 md
markdown = anydoc.to_markdown("示例 - 超市.xls")
#print(markdown)
# xls 2 md from file byte
with open("示例 - 超市.xls", "rb") as f:
	data = f.read()
markdown = anydoc.to_markdown_bytes(data)
#print(markdown)
# 获取文档模型
doc = anydoc.to_document(data)
# 查看所有属性名
print(dir(doc))

Python绑定转换时会释放GIL,不会阻塞其他线程。

Node.js

Node.js开发者安装:npm install @firecrawl/anydoc

WebAssembly版本可在浏览器直接运行:npm install @firecrawl/anydoc-wasm

示例:

js 复制代码
import { toDocument, toMarkdown, toMarkdownBytes } from '@firecrawl/anydoc';

// 从文件路径转换 
const markdown = await toMarkdown('report.docx');
// 从字节转换,自动检查格式 
const fromBytes = await toMarkdownBytes(bytes);
// CSV,无文件签名,显示指定 
const fromCsv = await toMarkdownBytes(bytes, 'csv');
// 获取文档模型(保留嵌入资源) 
const document = await toDocument(bytes);

Node版本,转换跑在libuv线程池,不阻塞事件循环。

Rust

Rust项目引入cargo add anydoc

入门示例:

bash 复制代码
// 从文件路径转换 
let markdown = anydoc::to_markdown("report.docx")?;
// 从字节转换,自动检查格式 
let markdown = anydoc::to_markdown_bytes(&bytes, None)?;
// CSV,无文件签名,显式指定
let markdown = anydoc::to_markdown_bytes(&bytes, anydoc::Format::Csv)?;
// 获取文档模型(保留嵌入资源) 
let document = anydoc::to_document(&bytes, None)?;

Agent Skills

基于npx安装:

bash 复制代码
npx skills add firecrawl/anydoc