【RAG】Gemini 3 flashでPDFをマークダウン変換したら精度向上が...できなかった
忙しくて時間が無い方へ(検証内容を簡単に説明)
- pdfplumber、tesseract、Gemini 3 flash(Geminiのみマークダウン変換)でPDFをテキスト化
- それぞれの文書をRAGに登録し、3つのRAGシステムを作成
- その他は同じ条件でそれぞれのRAGを検証
- 結果はpdfplumberのRAGが一番精度が良かった
前回まで
前回:
前回はragasを使ってRAGの性能を評価しました。
リポジトリ:
検証した3つの変換手法
今回は、PDFからテキストデータを抽出するために以下の3つの手法を比較しました。
1. Simple Text Extraction (pdfplumber)
Pythonのライブラリpdfplumberを使用して、PDFからテキストと表データを単純に抽出する方法です。レイアウト情報はほとんど保持されませんが、文字情報は正確に取得できます。
今回は検証用スクリプトとして simpleext_pdfplumber.py を作成しました。
2. OCR (Tesseract)
画像ベースのアプローチです。pdfplumberでPDFの各ページを画像に変換し、GoogleのOCRエンジンTesseract(pytesseract経由)でテキストを読み取ります。
スキャンされたPDFなど、テキストデータが埋め込まれていないファイルにも対応できるのが強みですが、誤認識が発生する可能性があります。
検証用スクリプト: ocr_tesseract.py
3. LLMによるMarkdown変換 (Gemini 3 flash)
Gemini 3 flash にPDFを直接渡し、構造化されたMarkdownとして出力させる方法です。
プロンプトで「見出し、リスト、表などを適切なMarkdown記法に変換すること」を指示しています。
論理的な構造が保持されるためRAGのチャンク分割に有利ではないかと仮説を立てて検証しました。
検証用スクリプト: pdf2md_llm.py
検証用コードの実行方法
今回の検証で使用したコードは、以下のコマンドで実行できます(リポジトリルートで実行)。
docs/ ディレクトリに置かれたPDFファイルを対象に処理を行い、pdf2md/coverted_texts/ 配下に結果を保存します。
1. pdfplumber
python3 -m pdf2md.simpleext_pdfplumber
2. Tesseract
python3 -m pdf2md.ocr_tesseract
3. Gemini 3 flash
python3 -m pdf2md.pdf2md_llm
※ その後のRAG構築(OpenSearchへの登録)や評価(Ragasの実行)については、前回・前々回の記事を参照してください。
評価環境の構築
RAGの構築と評価は、以前の記事で紹介した構成をベースにしています。
- Vector Database: OpenSearch
- Embedding: gemini-embedding-001
- Evaluation Framework: Ragas
- Retrieval Method: RRF (Reciprocal Rank Fusion)
作成した3種類のテキストデータ(pdfplumber抽出テキスト、Tesseract OCRテキスト、Gemini Markdown)をそれぞれ別のインデックスとしてOpenSearchに登録し、同一のテストセット(評価用質問と回答のペア)を用いて評価を行いました。
前提: Gemini 3 flashモデルについて
今回、PDFのMarkdown変換には最新のGemini 3 flash を使用しました。
以前のモデルと比較して処理速度が向上しており、大量のドキュメント処理に適していると期待されました。
評価指標
今回は Ragas フレームワークを使用し、以下の3つの指標で評価を行いました。
-
Context Recall
- 検索されたコンテキストが、正解(Reference)に含まれる重要な情報をどれだけ網羅できているかを測定します。
- 「検索漏れ」が少ないほど高スコアになります。
-
Context Entity Recall
- 正解に含まれる**エンティティ(固有表現など)**が、検索されたコンテキストの中にどれだけ含まれているかを測定します。
- キーワードレベルでの網羅性を確認する指標です。
-
Context Relevance
- 検索されたコンテキストが、ユーザーの質問に対してどれだけ関連しているかを評価します。
- ノイズ(無関係な情報)が少ないほど高スコアになります。
結果
ragasによる評価結果(平均値)は以下の通りです。
| Metric | pdfplumber | Tesseract | Gemini 3 flash |
|---|---|---|---|
| Context Recall | 0.5675 | 0.4016 | 0.4091 |
| Context Entity Recall | 0.3484 | 0.2964 | 0.2858 |
| Context Relevance | 0.7625 | 0.8250 | 0.7250 |
考察
予想に反して、**pdfplumberによる単純なテキスト抽出が最も高いRecall(再現率)**を記録しました。
Gemini 3 flashによるMarkdown変換は、Tesseractと同程度のRecallにとどまりました。
この結果になった要因として、以下の点が考えられます。
1. チャンク分割手法の影響
今回、すべてのテキストデータに対して RecursiveCharacterTextSplitter を使用してチャンク分割を行いました。
Markdownの構造(見出しなど)を意味的な区切りとして活用する MarkdownHeaderTextSplitter などを利用していれば、Geminiが生成した構造化データの強みをもっと活かせた可能性があります。
つまり、「Markdownにしたけれど、それを活かす分割をしなかった」ことが敗因の一つと考えられます。
2. プロンプトとチューニングの不足
Markdown変換のプロンプトやパラメータ(Temperatureなど)の細かいチューニングを行っていません。
「表をどう表現するか」「改行をどう扱うか」など、RAGに適したMarkdownの形式を突き詰めれば、精度は向上する余地があります。
まとめ
「LLMでリッチなMarkdownを作ればRAGの精度が上がるはず」という仮説は、ツール(Splitter)ごとの最適化や、泥臭いチューニングを行わない限り、簡単には成立しないことがわかりました。
もちろん、時間をかけてMarkdown分割に特化したパイプラインを作り込めば、pdfplumberを超える可能性は十分にあります。
しかし、「そこまで労力をかけるコスパが見合うか?」 という点は疑問です。
今回の検証範囲では、pdfplumberのような確実なテキスト抽出ツールを使用した方が、手軽かつ安定して高い精度を出せるという結果になりました。
「まずはpdfplumberでベースラインを作り、どうしても精度が足りない場合にLLM変換などの高度な手法を検討する」というアプローチが現実的かもしれません。