ITや趣味など気軽に投稿しています。

【RAG精度向上】Doclingの使い方:複雑なPDFを構造化データへ

RAG

RAG(Retrieval-Augmented Generation)システムの構築において、PDFドキュメントの正確な解析は回答精度を左右する重要な要素です。 本記事では、IBMが開発したオープンソースのドキュメント処理ツール「Docling」を使用し、複雑なレイアウトのPDFを高精度に解析・構造化する方法を解説します。

Doclingとは:特徴とメリット

Doclingは、PDF、Word、PowerPoint、HTMLなどのドキュメントを、LLM(大規模言語モデル)が処理しやすいMarkdownJSON形式に変換するツールキットです。

主な特徴

  • 高度なレイアウト解析: 表(Table)、数式、コードブロック、ヘッダー・フッターを正確に認識します。特に表組みの構造化に優れています。
  • 文脈の保持: 見出しや段落の階層構造を維持したまま変換するため、RAGのチャンク分割(Chunking)や検索精度が向上します。
  • OCR機能: スキャンされた画像ベースのPDFからもテキスト抽出が可能です。

Doclingのインストール手順

Python 3.9以上の環境で動作します。

基本インストール

pip install docling

OCR機能などの拡張ライブラリを含める場合

easyocrなどの依存関係を含める場合は以下を実行します。

pip install "docling[easyocr]"

主要パラメータの設定

Doclingでは、用途に合わせて変換処理を細かくカスタマイズできます。特にPDF解析において重要なパラメータを以下にまとめます。

DocumentConverter(コンバーター全体)の引数

DocumentConverterの初期化時に指定可能な主要パラメータです。

パラメータ名説明
allowed_formats変換対象とするファイル形式を制限します(例: PDFのみ)。デフォルトではサポートされる全形式が許可されます。
format_optionsファイル形式ごとの詳細設定を辞書形式で指定します。PDFのOCRや表解析の設定はここで行います。

PdfPipelineOptions(PDF解析パイプライン)の属性

PDF変換の挙動を制御する PdfPipelineOptions クラスの主要な属性です。これは format_options を通じて設定します。

属性名説明推奨設定例
do_ocrTrueにすると、画像化されたテキストに対してOCRを実行します。スキャンPDFを扱う場合は必須です。スキャンPDFの場合: True
do_table_structure表組みの構造(行・列・ヘッダー)をAIモデルで解析します。複雑な表を正しく抽出するために重要です。通常: True
table_structure_options表解析のモードを指定します。TableFormerMode.ACCURATE(高精度)とFAST(高速)があります。精度優先: ACCURATE
generate_page_imagesPDFの各ページを画像として生成し、結果に含めます。マルチモーダルRAGなどで使用します。必要時のみ: True
images_scale画像抽出やページ画像生成時の解像度倍率です。デフォルト(2.0)

以下は、これらの設定を適用するコード例です。

from docling.document_converter import DocumentConverter, PdfFormatOption
from docling.datamodel.base_models import InputFormat
from docling.datamodel.pipeline_options import PdfPipelineOptions, TableFormerMode

# パイプラインオプションの設定
pipeline_options = PdfPipelineOptions()
pipeline_options.do_ocr = True  # OCRを有効化
pipeline_options.do_table_structure = True # 表解析を有効化
pipeline_options.table_structure_options.mode = TableFormerMode.ACCURATE # 高精度モード

# コンバーターの初期化(オプションを適用)
converter = DocumentConverter(
    format_options={
        InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_options)
    }
)

ドキュメント変換の実装例

PDFを読み込み、Markdown形式として出力する基本的なPythonスクリプトです。

convert_doc.py

from docling.document_converter import DocumentConverter

def main():
    # 変換対象のパス(URLまたはローカルファイルパス)
    source = "https://arxiv.org/pdsf/2408.09869" 
    
    # コンバーターの初期化と実行
    converter = DocumentConverter()
    result = converter.convert(source)
    
    # Markdown形式でエクスポート
    markdown_output = result.document.export_to_markdown()
    
    # 結果の確認
    print(markdown_output[:500])

    # ファイル保存
    with open("output.md", "w", encoding="utf-8") as f:
        f.write(markdown_output)
    print("変換が完了しました。")

if __name__ == "__main__":
    main()

実行コマンド:

python convert_doc.py

初回実行時はモデルのダウンロードが自動的に行われます。生成された output.md を確認し、見出しや表が正しく構造化されているか確認してください。

RAGフレームワークとの連携

Doclingで変換したデータは、主要なRAGフレームワーク(LlamaIndex, LangChain)にスムーズに統合できます。 単なるテキスト抽出ツールと異なり、Doclingは見出しや表構造を維持したMarkdown形式でデータを渡せるため、RAGの検索精度(Retrieval)の向上が期待できます。

以下に、それぞれのフレームワークでの具体的な利用手順を解説します。

LlamaIndexでの利用

LlamaIndexでは、公式の連携ライブラリllama-index-readers-doclingを使用します。これを使うと、PDFをLlamaIndexのDocumentオブジェクトとして直接ロードし、すぐにインデックス化できます。

1. インストール

pip install llama-index-readers-docling

2. 実装コード例

from llama_index.core import VectorStoreIndex
from llama_index.readers.docling import DoclingReader

def create_index_with_docling():
    # DoclingReaderの初期化
    reader = DoclingReader()
    
    # ドキュメントの読み込み
    # 自動的にMarkdownへ変換され、構造情報を持ったままロードされます
    documents = reader.load_data(file_path="sample.pdf")
    
    # インデックスの作成(ここから通常のLlamaIndexのフローです)
    index = VectorStoreIndex.from_documents(documents)
    
    # 検索エンジンの作成とクエリ実行
    query_engine = index.as_query_engine()
    response = query_engine.query("このドキュメントの要点は何ですか?")
    print(response)

# if __name__ == "__main__":
#     create_index_with_docling()

LangChainでの利用

LangChainでは、langchain-doclingライブラリを使用します。DoclingLoaderを使うことで、他のデータローダーと同じ感覚でDoclingの高精度な解析機能を利用できます。

1. インストール

pip install langchain-docling

2. 実装コード例

from langchain_docling import DoclingLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter

def run_langchain_pipeline():
    # DoclingLoaderでPDFを読み込む
    loader = DoclingLoader(file_path="sample.pdf")
    docs = loader.load()
    
    # 読み込んだデータの確認(メタデータなども含まれます)
    print(f"ドキュメント数: {len(docs)}")
    
    # テキストの分割
    # Markdown形式でロードされるため、構造を意識した分割とも相性が良いです
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=1000,
        chunk_overlap=200
    )
    splits = text_splitter.split_documents(docs)
    
    # 以降、FAISSやChromaなどのVectorStoreへ保存します
    # ...

# if __name__ == "__main__":
#     run_langchain_pipeline()

なぜ連携ライブラリを使うのか?

これらの統合ライブラリを使う最大のメリットは、「表(Table)」の意味を損なわずにLLMへ渡せる点です。 通常のPDF読み込みツールでは、表内の数値が単なる文字列の羅列になってしまい、「A社の売上はいくら?」といった質問に答えられないことがよくあります。Doclingを経由することで、表がMarkdownの表形式として保持されるため、LLMが構造を理解しやすくなります。

まとめ

Doclingを導入することで、従来難易度の高かった「複雑なレイアウトを持つPDF」の解析精度を飛躍的に向上させることができます。 RAGの回答品質に課題を感じている場合は、ドキュメントの前処理としてDoclingの採用を検討してみてください。