anydoc
一个快速的Rust库,可将多种文档(Word、PowerPoint、Excel、OpenDocument、RTF、EPUB、CSV和PDF)转换为干净的GitHub风格Markdown。包含Node.js和Python绑定。
由Firecrawl构建,旨在将任意办公文档在单位数毫秒内转换为可供LLM直接使用的Markdown,无论输入什么格式,输出都保持一致。它驱动着Firecrawl Parse,如果你不想自己运行,托管API也能提供相同的转换,外加针对anydoc无法识别的扫描页面所训练的OCR模型。
快速开始
智能体技能(Agent Skill)
anydoc 以 Agent Skill 形式提供,因此你的智能体可以读取它遇到的任何文档:
npx skills add firecrawl/anydoc
该技能教会智能体使用anydoc CLI转换文档。兼容Claude Code、Codex、Cursor、OpenCode以及任何其他兼容智能体。
CLI
npx @firecrawl/anydoc report.docx # Markdown输出到stdout
npx @firecrawl/anydoc slides.pptx -o slides.md # 或输出到文件
npx @firecrawl/anydoc - --format csv < data.csv # 从stdin读取
npx 会在首次运行时为你的平台下载预构建二进制文件。如需永久安装anydoc命令,可全局安装:npm install -g @firecrawl/anydoc。运行 anydoc --help 查看所有选项。
Node.js
npm install @firecrawl/anydoc
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);
完整API参考:node/README.md
Python
pip install firecrawl-anydoc
import anydoc
# 从文件路径:
markdown = anydoc.to_markdown("report.docx")
# 从字节,格式从内容中检测:
markdown = anydoc.to_markdown_bytes(data)
# 或指定格式,无签名格式(如CSV)需要:
markdown = anydoc.to_markdown_bytes(data, "csv")
# 或停在文档模型,其中也包含嵌入资源:
document = anydoc.to_document(data)
完整API参考:python/README.md
Rust
cargo add anydoc
// 从文件路径:
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)?;
特性
- 每种格式统一输出。 每种格式都解析为共享的文档模型,并通过单一的Markdown序列化器渲染,因此无论是2003年的
.doc还是昨天的.pptx,转义、表格、标题锚点和脚注的行为都完全一致。 - 完整文档结构。 带锚点的标题、粗体/斜体/删除线、行内代码和代码块、链接和内部交叉引用、项目符号/编号/嵌套/任务列表(保留原始编号)、带合并单元格和表头的表格、块引用、脚注和尾注,以及演讲者备注。
- 嵌入资源。 图片和嵌入对象在Markdown中渲染为替代文本,原始字节保留在文档模型上,并标记媒体类型。具有外部URL的图片则成为普通Markdown图片。
- 基于内容的格式检测。 格式从字节本身读取(PDF头、RTF开组、OLE流名称、ZIP包 mimetype),因此打错标签的文件也能正确转换。
- 速度快。 纯Rust实现,无机器学习模型,无外部服务。每个文档的中位转换时间低于5毫秒。
- 不碍事的绑定。 Node.js转换在libuv线程池上运行,永不阻塞事件循环;Python释放GIL,其他线程可继续运行。TypeScript类型和Python存根随包发布。
- 内置PDF支持。 基于文本的PDF通过pdf-inspector本地转换,无需OCR服务。
- 适配智能体。 以Agent Skill形式提供:一条
npx skills add firecrawl/anydoc命令即可让任何智能体读取办公文档。
支持的格式
| 格式 | 扩展名 |
|---|---|
| Word | .doc, .docx, .docm |
| PowerPoint | .ppt, .pps, .pot, .pptx, .pptm, .ppsx, .ppsm |
| Excel | .xls, .xlsx, .xlsm, .xlsb |
| OpenDocument | .odt, .ods, .odp |
| Rich Text Format | .rtf |
| EPUB | .epub |
| CSV | .csv |
.pdf |
基准测试
anydoc 与其他六个转换器在100个跨十四种格式的真实文档上进行了对比。分数范围0到100,越高越好;速度是转换一个文档的中位时间。
| 工具 | 格式数 | 中位毫秒 | 文档数 | 分数 | 完整性 | 结构 | 格式 | 整洁度 |
|---|---|---|---|---|---|---|---|---|
| anydoc | 14/14 | 4.7 | 94 | 80 | 88 | 78 | 77 | 79 |
| libreoffice | 12/14 | 1129.5 | 87 | 40 | 59 | 43 | 43 | 24 |
| unstructured | 8/14 | 572.9 | 58 | 65 | 76 | 62 | 52 | 67 |
| markitdown | 6/14 | 134.8 | 33 | 65 | 80 | 67 | 61 | 53 |
| pandoc | 5/14 | 102.1 | 34 | 57 | 75 | 57 | 58 | 39 |
| docling | 4/14 | 513.6 | 21 | 57 | 63 | 59 | 57 | 52 |
| mammoth | 1/14 | 52.5 | 8 | 70 | 85 | 68 | 74 | 55 |
按格式逐一对比:
| 格式 | anydoc | libreoffice | unstructured | markitdown | pandoc | docling | mammoth |
|---|---|---|---|---|---|---|---|
| doc | 88 | 58 | 68 | - | - | - | - |
| docm | 82 | 49 | - | - | - | - | - |
| docx | 86 | 53 | 56 | 72 | 68 | 68 | 70 |
| epub | 74 | - | 74 | 77 | 53 | - | - |
| odp | 87 | 22 | - | - | - | - | - |
| ods | 82 | 42 | - | - | - | - | - |
| odt | 80 | 52 | 70 | - | 61 | - | - |
| ppt | 80 | 25 | - | - | - | - | - |
| pptx | 76 | 22 | - | 59 | - | 50 | - |
| rtf | 89 | 58 | 48 | - | 46 | - | - |
| xls | 77 | 40 | 68 | 64 | - | - | - |
| xlsm | 70 | 30 | - | - | - | - | - |
| xlsx | 70 | 31 | 69 | 55 | - | 51 | - |
质量评分方式: 一个LLM评判器(Claude Sonnet 5)对两个工具的输出进行盲测,与基准真相对比:文档前六页由LibreOffice渲染为图像。每个输出按完整性、结构、格式和整洁度评分。每对输出在交换顺序后评判两次,以消除位置偏差,共479个评判。每个工具的score是其支持格式的格式分数平均值,因此某个格式占比很高的语料库不会造成偏差。这也意味着每行平均了不同的格式集(mammoth的70仅来自docx,而anydoc的80横跨全部十四种),因此按格式对比的表才是公平的比较。
速度测试为在Ryzen 9 9950X3D(Windows 11, 64 GB DDR5-6400)上每个文档一次热转换。anydoc和Python库的计时不包括进程生成;CLI工具则包括,因为这是它们的使用方式。测试框架位于bench/;语料库不可再分发且不在仓库中。
最佳使用场景: 需要接收混合办公文档并输出一致、结构化Markdown的流水线。在此对比中,anydoc是唯一覆盖全部十四种格式的工具,在除EPUB外的每个被评判格式上得分最高,且转换速度比第二快的工具快一个数量级。
格式检测
格式从文件内容中读取,使用其规范指定的标记:PDF头、RTF开组、OLE流名称、ZIP包mimetype和内容类型。CSV没有此类标记,因此使用扩展名或显式格式名来指定。
Format::from_bytes(&bytes); // Some(Format::Docx),无匹配时为None
Format::from_extension("pptm"); // Some(Format::Pptx)
Format::from_path(Path::new("report.odt")); // Some(Format::Odt)
同样的三个函数在Node(formatFromBytes,…)和Python(anydoc.format_from_bytes,…)中也存在。
工作原理
文档字节
│
├─► 格式检测 → 内容标记,而非扩展名
│
├─► 格式解析器 → 每种格式一个(doc, docx, ppt, pptx, xls,
│ xlsx, odt/ods/odp, rtf, epub, csv)
│ │
│ └─► Document → 共享模型:块、行内元素、表格、
│ 脚注、资源
│ │
│ └─► GFM序列化器 → Markdown
│
└─► PDF → pdf-inspector → 直接输出Markdown
由于每种格式都汇入相同的文档模型和序列化器,输出问题只需修复一次。针对docx的表格转义修复会自动应用到rtf、odt及其他所有格式。
开发
cargo test
cd node && npm install && npm run build && npm test
cd python && pip install maturin && maturin develop && python -m unittest discover -s tests
tests/fixtures/下有一套已提交的固定语料进行快照测试,tests/robustness.rs对每个固定样本进行变异测试,fuzz/为每种格式提供cargo-fuzz目标。速度和质量基准位于bench/。
发布时打标签v<version>,从.github/workflows/release.yml发布crate、npm包和PyPI wheels。版本号存在于三处,发布时同步更新:
Cargo.toml:cratenode/package.json:npm包python/Cargo.toml:wheel(python/pyproject.toml读取它)