anydoc に注目すべき理由

大規模言語モデルにドキュメントを与える際、フォーマット変換の品質は RAG の結果に直接影響します。Word のテーブルの位置ずれ、PPT の階層構造の消失、PDF の段落の分断——これらのフォーマット問題は、ベクトル検索の精度を大幅に低下させます。これまで、主要な Office フォーマットを何とかカバーするために、pandoc、python-docx、LibreOffice などの複数のツールを組み合わせなければならず、メンテナンスコストが高く、出力も一貫性がありませんでした。

anydoc は、Firecrawl チームが Rust でゼロから開発したドキュメント変換ライブラリです。1 回の API 呼び出しで 14 種類のフォーマットを変換でき、中央変換時間はわずか 4.4 ミリ秒です。すでに GitHub で 12,000 以上のスターを獲得し、RAG/LLM ツールチェーンにおけるドキュメント前処理の新しい標準となりつつあります。

サポートされる 14 種類のフォーマット

anydoc は、すべてのオープンソース変換ツールの中で最も広いフォーマットカバレッジを提供します:

フォーマットカテゴリ サポートされる拡張子
Word ドキュメント .doc, .docx, .docm
PowerPoint プレゼンテーション .ppt, .pps, .pot, .pptx, .pptm, .ppsx, .ppsm
Excel スプレッドシート .xls, .xlsx, .xlsm, .xlsb
OpenDocument .odt, .ods, .odp
リッチテキスト .rtf
電子書籍 .epub
データファイル .csv
PDF .pdf

.doc(古いバイナリ形式)と .docx(新しい XML 形式)の両方がサポートされている点に注意してください。これは同種のツールでは非常に稀です。ほとんどのツールは .docx のみサポートし、古い .doc ファイルには対応できません。

パフォーマンステスト:4.4ms の秘密

anydoc の公式ベンチマークは、100 の実際のドキュメントを使用して 7 つのツール(自身を含む)を 14 種類すべてのフォーマットで比較しました:

ツール サポート形式 中央値時間 品質スコア 完全性 構造 フォーマット 清潔度
anydoc 14/14 4.4ms 81 87 79 78 81
libreoffice 12/14 1129.5ms 40 59 42 40 24
unstructured 8/14 572.9ms 63 76 59 51 63
markitdown 6/14 134.8ms 65 78 66 60 52
pandoc 5/14 102.1ms 56 74 57 56 38
docling 4/14 513.6ms 57 60 60 57 51
mammoth 1/14 52.5ms 70 84 71 75 51

重要な発見:

  1. 圧倒的な速度:anydoc の 4.4ms は、pandoc(102.1ms)の 1/23、LibreOffice(1129.5ms)の 1/257 の時間です
  2. 最高品質:評価されたすべてのフォーマットで、anydoc が最高スコアを獲得
  3. 最も完全なカバレッジ:14 種類すべてのフォーマットをサポートする唯一のツール
  4. Rust の利点:純粋な Rust 実装、ML モデルへの依存なし、外部サービス呼び出しなし

品質スコアは、Claude Sonnet 5 が LLM 判定者として、2 つの出力をブラインド比較(LibreOffice でレンダリングされた最初の 6 ページの画像を基準)して決定しました。各ツールは各比較ペアに対して 2 回評価され、位置バイアスを排除しました——合計 482 回の評価。

フォーマットごとの比較:anydoc が全面的にリード

以下のデータは、同じフォーマットでのツールの直接比較を示しています(最大スコア 100):

フォーマット anydoc libreoffice unstructured markitdown pandoc docling mammoth
.doc 87 57 67 - - - -
.docx 88 56 53 71 68 71 70
.pptx 74 24 - 66 - 52 -
.xlsx 72 30 66 55 - 47 -
.rtf 88 53 46 - 45 - -
.odt 80 51 68 - 60 - -
.epub 77 - 72 72 52 - -

mammoth は .docx で 70 のスコアを獲得しており、一見良いように見えます——しかし、これは 1 つのフォーマットのみの結果です。anydoc の 81 ポイントは 14 種類すべてのフォーマットの平均であり、全く異なる意味を持ちます。

インストールとクイックスタート

anydoc は、Rust コアと Node.js/Python/WebAssembly バインディング、およびすぐに使える CLI を提供します。

CLI(インストール不要)

BASH
# npx で直接実行、初回はプリコンパイルされたバイナリが自動ダウンロードされます
npx @firecrawl/anydoc report.docx               # stdout に出力
npx @firecrawl/anydoc slides.pptx -o slides.md  # ファイルに出力
npx @firecrawl/anydoc - --format csv < data.csv # stdin から読み取り

Python 統合

BASH
pip install firecrawl-anydoc
PYTHON
import anydoc

# ファイルパスから変換
markdown = anydoc.to_markdown("report.docx")
print(markdown)

# バイトから変換(フォーマット自動検出)
with open("report.docx", "rb") as f:
    data = f.read()
markdown = anydoc.to_markdown_bytes(data)

# フォーマットを指定(CSV などの magic bytes がない形式に必要)
markdown = anydoc.to_markdown_bytes(csv_data, "csv")

# ドキュメントモデルを取得(埋め込み画像などのリソースを含む)
document = anydoc.to_document(data)

Node.js 統合

BASH
npm install @firecrawl/anydoc
JAVASCRIPT
import { toMarkdown, toMarkdownBytes, toDocument } from '@firecrawl/anydoc';

// ファイルパスから
const md = await toMarkdown('report.docx');

// バイトから
const mdFromBytes = await toMarkdownBytes(bytes);

// ドキュメントモデルを取得(埋め込みリソースを含む)
const doc = await toDocument(bytes);

Rust ネイティブ使用

BASH
cargo add anydoc
RUST
// ファイルパスから
let markdown = anydoc::to_markdown("report.docx")?;

// バイトから(フォーマット自動検出)
let markdown = anydoc::to_markdown_bytes(&bytes, None)?;

// フォーマットを指定
let markdown = anydoc::to_markdown_bytes(&bytes, anydoc::Format::Csv)?;

LangChain / LlamaIndex との実践的な組み合わせ

RAG パイプラインでは、anydoc は通常、ドキュメントロードの前処理ステップとして使用され、様々なフォーマットを均一に Markdown に変換してから、チャンク分割とベクトル化を行います。

LangChain との組み合わせ

PYTHON
import anydoc
from langchain.text_splitter import MarkdownTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS

# 1. anydoc で統一 Markdown 変換
def load_documents(file_paths):
    docs = []
    for path in file_paths:
        md = anydoc.to_markdown(path)
        docs.append({"content": md, "source": path})
    return docs

# 2. Markdown チャンク分割
splitter = MarkdownTextSplitter(chunk_size=1000, chunk_overlap=100)
raw_docs = load_documents(["report.docx", "slides.pptx", "data.xlsx"])

chunks = []
for doc in raw_docs:
    chunks.extend(splitter.split_text(doc["content"]))

# 3. ベクトル化と保存
embeddings = OpenAIEmbeddings()
db = FAISS.from_texts(chunks, embeddings)
db.save_local("./faiss_index")

LlamaIndex との組み合わせ

PYTHON
import anydoc
from llama_index.core import Document, VectorStoreIndex

# anydoc 変換
file_paths = ["contract.docx", "presentation.pptx", "budget.xlsx"]
documents = []
for path in file_paths:
    md = anydoc.to_markdown(path)
    documents.append(Document(text=md, metadata={"source": path}))

# LlamaIndex インデックス作成
index = VectorStoreIndex.from_documents(documents)
query_engine = index.as_query_engine()
response = query_engine.query("契約の違約条項は何ですか?")
print(response)

RAG シナリオのベストプラクティス

1. 埋め込みリソースには to_document() を使用

ドキュメントに画像が含まれている場合、to_document() が返すドキュメントモデルは画像のバイトデータとメディアタイプを保持します。以下の選択肢があります: - 画像の alt テキストをテキストコンテンツとして抽出 - 画像を個別にマルチモーダルモデル(GPT-4V など)に送信して OCR 処理 - 画像の URL 参照を保持(画像に外部リンクがある場合)

2. フォーマット自動検出を活用

anydoc はファイル拡張子ではなく、ファイル内容の magic bytes を介してフォーマットを検出します。つまり、ファイルが誤って名前付けされていても(例:.pdf が実際には .docx)、anydoc は正しく識別して変換します。

PYTHON
# フォーマット検出
fmt = anydoc.format_from_bytes(data)  # Format 列挙型を返す
print(fmt)  # Format.DOCX

3. バッチ処理時の GIL に注意

Python バインディングは GIL を解放するため、複数スレッドでのバッチ変換は相互にブロックしません:

PYTHON
import concurrent.futures
import anydoc

def convert(path):
    return anydoc.to_markdown(path)

with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
    results = list(executor.map(convert, file_paths))

4. スキャン PDF の処理

anydoc には pdf-inspector が統合されており、PDF がテキストベースかスキャンかを自動検出します。テキストベースの PDF は直接抽出されます。スキャン PDF には、Firecrawl の Parse API(OCR 機能付き)との組み合わせを推奨します。

制限事項と注意事項

  1. スキャン PDF の能力は限定的:anydoc 自体は OCR を行いません。スキャン PDF には外部 OCR サービスが必要です。Firecrawl の Parse API でこれを補完できます。
  2. 複雑なレイアウトは正確でない場合がある:多段レイアウトや画像とテキストが複雑に混在するドキュメントでは、変換結果が専門的なレイアウトツールほど正確でない場合があります。anydoc の目標は LLM が読み取れる構造化テキストであり、ピクセル単位の再現ではありません。
  3. 古い .doc フォーマット:サポートされていますが、.doc(OLE2 バイナリ形式)の解析複雑性は .docx よりも高く、変換品質が若干低くなる可能性があります。
  4. ML 強化なし:anydoc は意図的に ML モデルに依存しません。これは、docling や marker のようにディープラーニングを使用してレイアウト分析を行うことはないことを意味します。利点は速度が速く、GPU 依存がないこと。欠点は複雑なレイアウトの理解力が限られていることです。
  5. ブラウザ WASM バージョン:WebAssembly バージョンはブラウザ内でローカルに実行され、ファイルはユーザーのデバイスから離れません。プライバシーに敏感なシナリオに適していますが、大きなファイルの変換はブラウザのメモリ制限を受ける可能性があります。

総評

anydoc は非常に実用的な問題を解決します:RAG/LLM パイプラインにおいて、軽量で高速、かつすべてのフォーマットをカバーするツールで、以前は 4、5 のライブラリを組み合わせなければならなかったドキュメント変換作業を置き換えます。

利点: - 14 種類のフォーマットを完全にカバー、オープンソースツールで唯一 - 4.4ms の中央変換速度、2 位の 23 倍高速 - 品質スコアで全面的にリード、出力の一貫性が高い - 純粋な Rust 実装、外部依存なし、GPU 不要 - Python/Node.js/Rust/WASM の 4 つのバインディングを提供

適切なユーザー: - RAG パイプラインを構築し、アップロードされた様々なフォーマットのドキュメントを処理する必要がある開発者 - 統一されたドキュメント出力フォーマットが必要なチーム - 変換速度が求められるリアルタイムシナリオ - 複数の変換ツール依存を維持したくない開発者

GitHub: firecrawl/anydoc(12,000+ スター)

よくある質問(FAQ)

Q1: anydoc と pandoc の違いは何ですか? pandoc は汎用ドキュメントフォーマット変換ツールで、非常に多くの入出力フォーマットをサポートしていますが、各フォーマットの変換深度は限られています。anydoc は Office ドキュメントを LLM に適した Markdown に変換することに特化しており、カバーする 14 種類のフォーマットでより高い変換品質、23 倍の速度を提供し、RAG シナリオ向けに最適化されています。

Q2: anydoc には GPU や外部サービスが必要ですか? いいえ。anydoc は純粋な Rust 実装で、ML モデルへの依存もなく、外部 API 呼び出しもありません。ローカルで実行され、1 ファイルの中央変換時間は 4.4ms です。

Q3: anydoc はスキャン PDF を処理できますか? anydoc には pdf-inspector が統合されており、テキストベースの PDF を処理できます。スキャン PDF(画像ベース)には、Firecrawl Parse API(OCR 機能付き)との組み合わせを推奨します。

Q4: anydoc の出力フォーマットはどのようなものですか? GitHub Flavored Markdown(GFM)に統一して出力され、見出し階層、テーブル、リスト、コードブロック、リンクなどの構造が含まれます。14 種類すべてのフォーマットで出力スタイルが一貫しています。

Q5: anydoc はブラウザで実行できますか? はい。anydoc は WebAssembly バージョン(@firecrawl/anydoc-wasm)を提供しています。ファイルはブラウザ内でローカルに変換され、サーバーにアップロードされないため、プライバシーに敏感なシナリオに適しています。