
anydoc:把任何文档变成 Markdown 的极速转换器
前言:文档格式的大统一
2026-08-12 16:23 GMT+8
处理 Office 文档的痛点:
- 格式多样(Word, PowerPoint, Excel, PDF, ...)
- 解析复杂(需要理解每种格式的内部结构)
- 转换缓慢(传统工具动辄数秒)
- 输出不一致(不同格式转换结果差异大)
理想方案:
一个工具,一个输出,毫秒级速度
今天介绍 anydoc:
Fast Rust library that converts documents into clean GitHub-Flavored Markdown
Built by Firecrawl
一、项目概览
anydoc 是一个极速文档转换工具,将各种 Office 文档转换为干净的 Markdown。
一句话说清楚:
14 种格式,统一输出,毫秒级速度,把任何文档变成 LLM-ready Markdown
项目地址:https://github.com/firecrawl/anydoc 开发团队:Firecrawl 开源协议:MIT 核心语言:Rust 绑定语言:Node.js, Python, Browser (WebAssembly)
支持的格式
14 种格式全覆盖:
| 格式 | 扩展名 |
|---|---|
| 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 |
二、核心特性
1. 统一输出
一个文档模型,一个序列化器:
- 每种格式解析到共享文档模型
- 通过单个 Markdown 序列化器渲染
- 转义、表格、标题锚点、脚注行为一致
价值:
- 无论输入是 2003 的
.doc还是昨天的.pptx - 输出格式完全一致
- 修复一次,所有格式受益
2. 完整文档结构
保留完整结构:
- ✅ 标题(带锚点)
- ✅ 粗体/斜体/删除线
- ✅ 行内代码和代码块
- ✅ 链接和内部交叉引用
- ✅ 有序/无序/嵌套/任务列表(保留源编号)
- ✅ 表格(合并单元格、标题行)
- ✅ 引用块
- ✅ 脚注和尾注
- ✅ 演讲者备注
3. 嵌入资源
图片和嵌入对象:
- 在 Markdown 中渲染为 alt text
- 原始字节在文档模型中可用
- 标记媒体类型
- 外部 URL 图片变为普通 Markdown 图片
4. 基于内容的格式检测
从字节本身读取格式:
- PDF 头
- RTF open group
- OLE 流名称
- ZIP 包 mimetype
- CSV 需要扩展名或显式格式
价值:
- 错误标记的文件仍能正确转换
- 不依赖文件扩展名
5. 极速转换
性能数据:
- 纯 Rust 实现
- 无 ML 模型
- 无外部服务
- 中位数转换时间 < 5ms
6. 多语言绑定
三种绑定:
- Node.js:在 libuv 线程池运行,不阻塞事件循环
- Python:释放 GIL,其他线程继续运行
- 浏览器:WebAssembly,本地转换
类型支持:
- TypeScript 类型随包发布
- Python stubs 随包发布
7. Agent 就绪
Agent Skill 集成:
npx skills add firecrawl/anydoc支持的 Agent:
- Claude Code
- Codex
- Cursor
- OpenCode
- 任何兼容的 agent
8. 内置 PDF 支持
PDF 转换:
- 通过 pdf-inspector 本地转换
- 无需 OCR 服务
- 支持基于文本的 PDF
三、快速开始
Agent Skill
npx skills add firecrawl/anydocAgent 可以读取任何文档。
CLI
npx @firecrawl/anydoc report.docx # Markdown 到 stdout
npx @firecrawl/anydoc slides.pptx -o slides.md # 或到文件
npx @firecrawl/anydoc - --format csv < data.csv # 从 stdin永久安装:
npm install -g @firecrawl/anydoc
anydoc --helpNode.js
npm install @firecrawl/anydocimport { 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);Python
pip install firecrawl-anydocimport 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)浏览器(WebAssembly)
npm install @firecrawl/anydoc-wasmimport init, { toMarkdownBytes, toDocument } from '@firecrawl/anydoc-wasm';
await init();
// 从字节,自动检测格式:
const markdown = toMarkdownBytes(bytes);
// 指定格式(CSV 需要):
const fromCsv = toMarkdownBytes(bytes, 'csv');
// 停留在文档模型(包含嵌入资源):
const document = toDocument(bytes);在线 Demo: https://firecrawl.github.io/anydoc/
- WebAssembly 运行
- 本地转换
- 文件不离开机器
四、性能对比
Benchmark 结果
anydoc vs 其他工具:
| 工具 | 格式支持 | 中位数耗时(ms) | 评分 | 完整性 | 结构 | 格式 | 清洁度 |
|---|---|---|---|---|---|---|---|
| anydoc | 14/14 | 4.4 | 81 | 87 | 79 | 78 | 81 |
| libreoffice | 12/14 | 1129.5 | 40 | 59 | 42 | 40 | 24 |
| unstructured | 8/14 | 572.9 | 63 | 76 | 59 | 51 | 63 |
| markitdown | 6/14 | 134.8 | 65 | 78 | 66 | 60 | 52 |
| pandoc | 5/14 | 102.1 | 56 | 74 | 57 | 56 | 38 |
| docling | 4/14 | 513.6 | 57 | 60 | 60 | 57 | 51 |
| mammoth | 1/14 | 52.5 | 70 | 84 | 71 | 75 | 51 |
关键指标:
- ✅ anydoc 是唯一支持所有 14 种格式的工具
- ✅ anydoc 是最快的工具(4.4ms,比第二快 10 倍以上)
- ✅ anydoc 评分最高(81 分)
- ✅ anydoc 在每个格式上都是最高分
按格式对比
每种格式的评分对比:
| 格式 | anydoc | libreoffice | unstructured | markitdown | pandoc | docling | mammoth |
|---|---|---|---|---|---|---|---|
| doc | 87 | 57 | 67 | - | - | - | - |
| docm | 84 | 48 | - | - | - | - | - |
| docx | 88 | 56 | 53 | 71 | 68 | 71 | 70 |
| epub | 77 | - | 72 | 72 | 52 | - | - |
| odp | 86 | 23 | - | - | - | - | - |
| ods | 82 | 38 | - | - | - | - | - |
| odt | 80 | 51 | 68 | - | 60 | - | - |
| ppt | 80 | 26 | - | - | - | - | - |
| pptx | 74 | 24 | - | 66 | - | 52 | - |
| rtf | 88 | 53 | 46 | - | 45 | - | - |
| xls | 80 | 38 | 66 | 62 | - | - | - |
| xlsm | 76 | 32 | - | - | - | - | - |
| xlsx | 72 | 30 | 66 | 55 | - | 47 | - |
评分方法
LLM 评判:
- Claude Sonnet 5 盲评判
- 对比工具输出与真实值(文档前 6 页)
- 评分维度:完整性、结构、格式、清洁度
- 每对评判两次(交换位置以消除偏差)
- 总共 482 个评判
速度测试:
- Ryzen 9 9950X3D(Windows 11, 64 GB DDR5-6400)
- 每个文档一次预热转换
- anydoc 和 Python 库排除进程启动时间
- CLI 工具包括进程启动时间
五、架构设计
工作流程
文档字节
│
├─► 格式检测 → 内容标记,不是扩展名
│
├─► 格式解析 → 每种格式一个解析器(doc, docx, ppt, pptx, xls,
│ xlsx, odt/ods/odp, rtf, epub, csv)
│ │
│ └─► Document → 共享模型:blocks, inlines, tables,
│ footnotes, assets
│ │
│ └─► GFM 序列化器 → Markdown
│
└─► PDF → pdf-inspector → Markdown 直接统一架构
核心思想:
- 每种格式解析到共享文档模型
- 通过同一个序列化器渲染
- 修复一次,所有格式受益
优势:
- 表格转义修复对 docx 的修复自动成为 rtf、odt 和所有其他格式的修复
- 输出一致性
- 维护简单
格式检测
基于内容标记:
Format::from_bytes(&bytes); // 从字节检测格式
Format::from_extension("pptm"); // 从扩展名检测(CSV 需要)
Format::from_path(Path::new("report.odt")); // 从路径检测支持的标记:
- PDF 头
- RTF open group
- OLE 流名称
- ZIP 包 mimetype 和内容类型
六、错误处理
ConvertError
错误类型:
| 错误类型 | 含义 |
|---|---|
Unsupported | 未知格式,或无法转换的格式(如纯图片 PDF) |
Malformed | 结构不可用:无法提取有意义的内容 |
Encrypted | 加密或密码保护 |
ResourceLimit | 超过安全限制(解压缩、嵌套、节点数) |
MissingPart | 缺少任何有意义输出所需的部分 |
Io | 文件无法读取(仅 to_markdown) |
错误处理示例
match anydoc::to_markdown(path) {
Ok(markdown) => Some(markdown),
// 无法从这些文档中提取内容,记录文件并继续下一个
Err(error @ (ConvertError::Encrypted | ConvertError::Unsupported(_))) => {
unconverted.push((path, error));
None
}
Err(error) => return Err(error),
}七、实际应用
场景 1:文档处理流水线
场景:接收各种格式的文档,转换为 Markdown 存储到数据库
使用 anydoc:
import anydoc
from pathlib import Path
def process_document(file_path: str) -> str:
"""将任何文档转换为 Markdown"""
try:
markdown = anydoc.to_markdown(file_path)
return markdown
except anydoc.Unsupported:
# 记录不支持的格式,跳过
log_unsupported(file_path)
return None
except anydoc.Encrypted:
# 记录加密文件,跳过
log_encrypted(file_path)
return None
# 批量处理
for file in Path("./documents").glob("**/*"):
markdown = process_document(str(file))
if markdown:
save_to_database(file.name, markdown)价值:
- ✅ 统一处理 14 种格式
- ✅ 毫秒级速度
- ✅ 一致的输出格式
场景 2:RAG 系统
场景:将 Office 文档转换为 Markdown 用于 RAG
使用 anydoc:
import anydoc
from langchain.text_splitter import MarkdownHeaderTextSplitter
def office_to_chunks(file_path: str):
# 转换为 Markdown
markdown = anydoc.to_markdown(file_path)
# 分块
splitter = MarkdownHeaderTextSplitter(
headers_to_split_on=[("#", "Header 1"), ("##", "Header 2")]
)
chunks = splitter.split_text(markdown)
return chunks
# 上传到向量数据库
chunks = office_to_chunks("report.docx")
vector_store.add_texts(chunks)价值:
- ✅ 完整的文档结构
- ✅ 适合分块
- ✅ 保留标题层级
场景 3:Agent 文档读取
场景:Agent 需要读取各种格式的文档
使用 anydoc + Agent Skill:
# 安装 Agent Skill
npx skills add firecrawl/anydocAgent 可以直接读取:
- Word 文档
- PowerPoint 幻灯片
- Excel 表格
- PDF 文档
- 任何支持的格式
价值:
- ✅ Agent 可以读取任何文档
- ✅ 无需预转换
- ✅ 毫秒级响应
场景 4:浏览器本地转换
场景:用户上传文档,在浏览器中本地转换为 Markdown
使用 anydoc WebAssembly:
import init, { toMarkdownBytes } from '@firecrawl/anydoc-wasm';
await init();
async function convertFile(file: File): Promise<string> {
const bytes = await file.arrayBuffer();
const markdown = toMarkdownBytes(new Uint8Array(bytes));
return markdown;
}
// 使用
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', async (e) => {
const file = e.target.files[0];
const markdown = await convertFile(file);
console.log(markdown);
});价值:
- ✅ 文件不离开机器
- ✅ 毫秒级速度
- ✅ 支持 14 种格式
八、与其他工具的对比
vs LibreOffice
| 维度 | LibreOffice | anydoc |
|---|---|---|
| 速度 | 1129.5ms | 4.4ms |
| 格式支持 | 12/14 | 14/14 |
| 评分 | 40 | 81 |
| 部署 | 需要 Office 套件 | 单一二进制 |
| 输出一致性 | 格式间差异大 | 统一输出 |
vs Unstructured
| 维度 | Unstructured | anydoc |
|---|---|---|
| 速度 | 572.9ms | 4.4ms |
| 格式支持 | 8/14 | 14/14 |
| 评分 | 63 | 81 |
| 输出 | 元数据 + 文本 | 纯 Markdown |
vs Pandoc
| 维度 | Pandoc | anydoc |
|---|---|---|
| 速度 | 102.1ms | 4.4ms |
| 格式支持 | 5/14 | 14/14 |
| 评分 | 56 | 81 |
| 定位 | 通用文档转换器 | 专注 Office → Markdown |
九、核心价值
1. 统一输出
一个文档模型,一个序列化器:
- 所有格式解析到共享模型
- 通过同一个序列化器渲染
- 修复一次,所有格式受益
2. 极速转换
纯 Rust 实现:
- 无 ML 模型
- 无外部服务
- 中位数 < 5ms
3. 完整结构
保留完整文档结构:
- 标题、列表、表格、引用
- 脚注、尾注、演讲者备注
- 合并单元格、标题行
4. 多语言绑定
Node.js、Python、浏览器:
- TypeScript 类型
- Python stubs
- WebAssembly 支持
5. Agent 就绪
Agent Skill 集成:
- 一个命令安装
- Agent 可以读取任何文档
- 支持 Claude Code、Codex、Cursor、OpenCode
十、总结
核心问题
处理 Office 文档的痛点:
- ❌ 格式多样,解析复杂
- ❌ 转换缓慢,动辄数秒
- ❌ 输出不一致,格式间差异大
- ❌ 工具分散,需要多个工具
anydoc 的解决方案
统一转换器:
- ✅ 14 种格式,一个工具
- ✅ 毫秒级速度(< 5ms)
- ✅ 统一输出(GitHub-Flavored Markdown)
- ✅ 完整结构(标题、列表、表格、脚注...)
为什么选择 anydoc?
1. 性能
- 最快(4.4ms)
- 比第二快 10 倍以上
2. 覆盖
- 支持 14/14 格式
- 唯一全覆盖所有格式
3. 质量
- 评分最高(81 分)
- 每个格式都是最高分
4. 一致性
- 统一输出格式
- 修复一次,所有格式受益
5. 易用性
- 多语言绑定
- Agent Skill 集成
- WebAssembly 支持
记住
anydoc 是文档格式的大统一。
14 种格式,一个工具,毫秒级速度,统一输出。
把任何文档变成 LLM-ready Markdown。
附:资源链接
项目资源:
- GitHub:https://github.com/firecrawl/anydoc
- 在线 Demo:https://firecrawl.github.io/anydoc/
- Crates.io:https://crates.io/crates/anydoc
- npm:https://www.npmjs.com/package/@firecrawl/anydoc
- PyPI:https://pypi.org/project/firecrawl-anydoc/
Firecrawl:
- 官网:https://firecrawl.dev
- Firecrawl Parse:https://firecrawl.dev/parse
文档资源:
- Node.js API:node/README.md
- Python API:python/README.md
- WebAssembly API:wasm/README.md
安装速查:
# Agent Skill
npx skills add firecrawl/anydoc
# CLI(临时)
npx @firecrawl/anydoc report.docx
# CLI(永久)
npm install -g @firecrawl/anydoc
# Node.js
npm install @firecrawl/anydoc
# Python
pip install firecrawl-anydoc
# 浏览器
npm install @firecrawl/anydoc-wasm