PDF の表やグラフから意味を抽出する RAG パイプライン構築法
本文の状態
日本語全文を表示中
詳細モードで約19分の本文を読めます。
同じ出来事の情報源
この情報源を基点に整理
Weaviate Blog
Weaviate は、従来の OCR やテキスト抽出を不要とする「Late Interaction RAG」アプローチを発表し、PDF 内のチャートや表から直接意味情報を抽出・検索する新手法と実装例を示した。
AI深層分析を開く2026年9月1日 22:26
AI深層分析
キーポイント
従来型 RAG の限界
OCR やテキスト抽出に依存する従来の RAG パイプラインは、PDF 内のチャートや表といった視覚的情報を見落とし、検索結果の質を低下させる。
Late Interaction RAG の導入
ページ全体を埋め込むマルチベクトルモデルを用いることで、テキスト抽出プロセスをスキップし、視覚的要素を含む文脈を直接処理する手法を提案している。
Weaviate Cloud の実装
複数の PDF を数回のクリックで取り込み可能な Weaviate Cloud 機能や、Python で約 50 行のコードで実装可能なデプロイ済みパイプラインを紹介している。
エージェントによる推論
Weaviate Query Agent を活用し、チャートから情報を合成して回答を生成する際、出典ページ画像を明示的に引用する機能を実証している。
ページ単位での埋め込みとチャンキングの不要性
この手法では文書全体やテキストの一部ではなく、ページそのものを埋め込むため、チャンキングステップが不要となる。モデルはページ内の特定の領域をベクトルとして保持し、クエリとの関連性を細かく評価できる。
重要な引用
OCR (or text-extract) the file... Chunk the text. Embed the chunks with a text embedding model.
For a slide deck full of charts, a 10-K with comparison tables... it's simply not enough.
With a late-interaction multi-vector model, you don't need any of those: You embed the page, and not the text within it.
The model sees the chart the way you do.
編集コメントを表示
編集コメント
PDF 解析におけるテキスト依存からの脱却は、実務的な RAG システムのボトルネック解消に向けた重要な一歩である。Weaviate が示すアプローチは、複雑な前処理を排除しつつ視覚情報を活用する現実的な解決策として注目される。
Source Article
元記事を日本語で読む
本文に関係しない購読案内、埋め込み通知、サイト内プロモーションは除いています。

もし投資家向けの資料、学術論文、あるいは年次報告書を RAG(Retrieval-Augmented Generation)パイプラインに流し込んだ経験があれば、その手順はご存じでしょう。まず OCR やテキスト抽出のステップを設け、チャンキング戦略を選び、テキストを埋め込み、最後に情報を検索します。
しかし、こうした一連の手順を経て「2025 年第 2 四半期の収益はどうですか?」と質問されたとき、実際の答えがバーチャートに含まれているにもかかわらず、インデックス化されていないため、関連性の低い箇条書きが 3 ページ分も返されてしまうことがよくあります。
これまで、PDF の価値を高める要素であるトレンドを示す棒グラフや比較表、アーキテクチャ図といった「面白い部分」を RAG から除外して扱うしかなかったのです。
この記事では、チャートに埋め込まれた豊富な情報を取得できるだけでなく、複雑な処理工程も不要にする新しいアプローチをご紹介します。具体的には以下の 3 つのトピックを解説します。
- 従来の RAG: OCR とテキスト埋め込みが構造化・非構造化データの両方でなぜ有効なのか、そしてなぜ「リッチな PDF」では機能しないのか。
- Late Interaction RAG: Late-interaction マルチベクトルモデルとは何か、そしてなぜこれを使えばテキスト抽出を完全にスキップできるのか。
- ドラッグ&ドロップで完了: Weaviate Cloud 上で数回のクリックだけで複数の PDF を取り込む方法。
実例:NVIDIA の FY2026 四半期決算に対するクエリでは、各上位結果が質問に答える正確なチャートとして返されます。
複雑なエージェント推論:Weaviate Query Agent を使用して同じデータをラップし、ページ画像の引用付きで合成された回答を生成する方法です。
コード化済みかつ本番環境対応:本番環境へのデプロイが必要な場合のために、約 50 行の Python で記述された同一の取り込みパイプラインです。
まずはデモを見てから解説を読むという場合は、以下のクエリセクションへスキップしてください。
従来の RAG が抱える課題
まず、PDF 向けに RAG パイプラインを構築する際、多くの人々が現在どのようなアプローチを取っているか見てみましょう。
- OCR(またはテキスト抽出):Python ライブラリやサードパーティ製ツールを使用してファイルから抽出します。
- テキストのチャンク化:抽出したテキストを小さな断片に分割します。
- 埋め込み生成:テキスト埋め込みモデルを用いて各チャンクをベクトル化します。
- 検索・(場合により)再ランク付け・回答生成。
このワークフロー自体に本質的な欠陥があるわけではありません。しかし、そこには「ページの内容はテキストトークンの列として単純化でき、情報の豊かさを損なうことはない」という素朴な前提が隠されています。プレスリリースや Wikipedia の記事であればこのアプローチでも十分機能しますが、チャートで埋め尽くされたスライド資料、比較表を含む 10-K(年次報告書)、あるいは図解を多用する学術論文においては、この方法では不十分です。
チャートを抽出して個別にベクトル化する複雑な ETL パイプラインを構築することも可能ですが、それには追加のモデルが必要となり、システム全体の複雑さが増すだけでなく、クエリ実行時の統合問題も生じます。
後期相互作用型マルチベクトルモデルを使えば、そのような複雑な処理は不要です。ページ内のテキストを埋め込むのではなく、ページそのものを埋め込みます。このモデルがチャートを捉える様子は、人間が見るのと全く同じです。お聞き漏らしなくとも、チャンキング(分割)ステップさえ存在しません。ページ自体がチャンクとなるのです。
後期相互作用型マルチベクトル検索の仕組みを2 つのポイントで解説します
デモに入る前に、なぜこの手法が機能するのかを簡単に振り返っておきましょう。すでに ColPali や ColBERT の仕組みに精通している方は、飛ばしていただいても構いません。
従来の密埋め込みモデルは、ドキュメント全体(またはチャンク)を 1 つのベクトルに圧縮します。一方、後期相互作用型マルチベクトルモデルは異なるアプローチを採用しています。これはドキュメントを複数のベクトルの集合として符号化します。通常、トークンごとに 1 つずつベクトルを割り当てます(あるいはこれから紹介する視覚モデルのように、画像の各パッチごとに 1 つずつベクトルを生成します)。クエリを実行する際にも、クエリ自体がベクトルの集合として符号化され、関連性スコアはクエリのトークンとドキュメントのトークンの間の最良の一致をすべて合計した値(MaxSim と呼ばれます)によって算出されます。
「このページ全体が私の質問全体に該当するか?」と問うのではなく、「Q4 決算に関するページの部分が、私の質問における『時系列変化』という部分とよくマッチしているか?」といった問いかけが可能になります。チャートが多く掲載されたページにおいては、まさにこの粒度が必要となります。モデルはスライド全体を 1 つのベクトルに要約する必要はなく、ページの各領域ごとに 1 つずつベクトルを保持し、クエリが重要な領域だけを抽出できるのです。
つまり、ここには明確な 2 つの利点があります:
このモデルは視覚モデルであるため、レイアウトやチャート、表などの要素をそのまま保持します。
MaxSim をベクトルセット全体に適用することで、チャンク分割の必要性がなくなります。
Weaviate は「multi2multivec-weaviate」というベクトライザーモジュールを提供しています。これは Weaviate Cloud 上でホストされた後期相互作用型マルチベクトルモデルを実行するもので、PDF からマルチベクトルを生成するために自分でモデルをホストしたり管理したりする必要がありません。
ドラッグ&ドロップによる PDF の取り込み
この機能を試す最も簡単な方法は、Weaviate Cloud 内のドラッグ&ドロップインポーターを利用することです。
- コンソールでクラスターを開きます。
- 「Collections」に移動し、新しいコレクションを作成します。
- 「ファイルからアップロード」オプションを選択し、PDF をドラッグ&ドロップしてください。


これで取り込みプロセスは完了です。裏側では、Weaviate が以下の 3 つの処理を行っています。
- 各 PDF ページを高解像度の画像としてレンダリングする
- その画像を新しいコレクションの BLOB プロパティとして保存する
- multi2multivec-weaviate モジュールを使用してベクトル化し、ページごとに多数のベクトルを生成する
いくつか重要なポイントがあります。
1 つのオブジェクト=1 ページ: 検索の単位はページです。これは人間が文書内で移動する際の基本単位でもあります。
OCR は不要: モデルはテキストとして文字列を見るのではなく、ページ全体を画像として認識します。そのため、キャプションのないチャートも段落と同じように検索可能です。
ベクトルは圧縮されています。後方相互作用モデルでは、1 ページあたり数百のベクトルを生成する可能性があります。これを素朴な方法で保存するとコストがかさむため、Weaviate はインデックスをコンパクトに保つためのマルチベクトル符号化スキームを採用しています(詳細は後述のトレードオフセクションをご覧ください)。
今回のデモでは、NVIDIA の 2026 会計年度第 1 四半期から第 4 四半期までの 4 つの投資家向けプレゼンテーション資料をインポートしました。これらは 2026 年 1 月で終了する会計年度を対象としており、図表や表がページいっぱいに掲載されています。合計 92 ページにわたるデータを、インポートには約 1 分半かかりました。
NVIDIA の四半期決算データの照会
データに対するエージェント推論などの高度な処理を行う前に、まずはそのままだでも十分印象的な「生きた検索結果」をご紹介しましょう。
取り込みが完了したら、コンソール(または Weaviate クライアント)で直接データを照会できます。クエリは平易な英語で行い、結果としてページ画像を埋め込んだランク付けリストが表示されます。
ここでは 3 つのクエリ例を紹介し、それぞれどのような結果が返ってくるか見ていきましょう。
クエリ 1: "自動車部門の収益は時間とともにどのように変化したのか?"

最上位の結果は、FY26 第 2 四半期の資料「Automotive」から抽出された 1 ページです。左側には棒グラフがあり、5 クォーター分の収益推移(3.46 億ドル→4.49 億ドル→5.70 億ドル→5.67 億ドル→5.86 億ドル、前年比 +69%)が示されています。右側には「Thor SoC」や「DRIVE AV」に関する 3 つの箇条書き項目が含まれています。
このページに「時間の経過とともに」というフレーズは記載されていません。同様に、「変化」という単語もありません。モデルがテキストの意味内容と照合したのではなく、ページそのものの画像を認識しました。そこには高さが順次増える5本の棒グラフがあり、四半期ごとのラベルが付いています。これだけで、時系列のトレンドに関する質問に対する該当ページとして識別できました。
クエリ 2:「粗利益率の推移」

最上位の結果は、26 会計年度第 2 四半期の財務サマリーページです。左側には組み合わせチャートがあり、収益の棒グラフと非 GAAP 粗利益率の折れ線が 5 四半分にわたって描かれています。右側には、GAAP/非 GAAP の主要業績評価指標(KPI)表があり、前年比(Y/Y)および前期比(Q/Q)の変動幅も記載されています。
ここでも、「粗利益率の推移」という文言がそのまま掲載されているわけではありません。しかし、26 会計年度第 1 四半期に 75.7% から 61.0% に低下し、同年第 2 四半期には 72.7% に回復したことを視覚化した折れ線グラフが存在します。これがまさに「推移」の姿であり、モデルが取得した也正是な情報です。
補足:同じページには詳細な財務表も含まれています。そのため、「粗利益率はいくつベーシスポイント回復したのか?」といった続投質問に対して、非常に有用な検索対象となります。答えはすでにモデルが返却したページ上に存在します。これについては後ほど「クエリエージェント」を紹介する際に詳しく触れます。
クエリ 3:「データセンター収益は時間とともにどのように変化したか?」

最上位の結果は、第 4 四半期(FY26)の収益ページです。これは Y/Y の棒グラフで、データセンター部門の収益が ChatGPT の登場以来 13 倍に増加したことを示す注釈付きです。この例は、テキストの方がより適切な回答となる場合にモデルがそれを尊重することを示しています。この場合、チャート自体はそれほど重要ではありませんが、正確な答えを記述したボックスが、ページ上で最も高い類似度(MaxSim)を示しました。つまり、両方のモダリティの利点を同時に得られるのです。
2 番目にランクされたのは、別の四半期からの専用データセンターページで、セグメントをコンピューティングとネットワークに分割しています。

2 番目のベストマッチが単なる「別のデータセンターに関するページ」ではないことに注目してください。それは同じ収益を異なる方法で分解した、全く異なる種類の回答です。これは、同一の基礎数値に対する複数の視点から三角測量を行いたいエージェントにとって有用な特性と言えます。
検索から回答へ:Weaviate Query Agent
ベクトル検索は結果を返しますが、時には明確な答えが必要な場合があります。
Weaviate Query Agent は、多段階推論、ソースの引用、およびインラインページ画像を備えたベクトル検索をラップする管理型エージェントです。これは Weaviate Cloud クラスターであればすぐに利用可能です。コレクションを指定して質問するだけで動作します。

「自動車部門の収益は FY26 四半期を通じてどのように変化したのか?その要因は何なのか?」と、同じデータセットに対して問いかけると、エージェントは棒グラフの数値や Thor SoC や DRIVE AV の採用状況に関する箇条書きなどを統合した回答を返します。同時に、根拠となったページ画像も引用元として提示されます。エージェントはどのページを取得すべきかを判断し、視覚的に確認しながらスライドから直接引用しています。
「ソース」パネルを開くと、回答の裏付けとなったページが具体的に示されます。その中に含まれるのは、Q1 FY26 の資料にある自動車部門のページです。先ほどベクトル検索で取り上げた棒グラフと同じ種類のもので、対象となる四半期が違うだけです。
回答に含まれるすべての数値主張は、特定の PDF 内の特定のページに紐付けられており、検証用にそのページの画像も併記されています。エージェントを盲目的に信頼する必要はなく、自分でスライドの内容を確認することも可能です。

Python で実用可能なパイプラインを構築する
ドラッグ&ドロップの UI は、概念実証(POC)を素早く作成するための最速の手段ですが、本番環境のパイプラインではコードが必要になります。ここでは、おおよそ 50 行で同等の機能を実現するコード例を示します。
まず、依存関係をインストールしてください。
pip install "weaviate-client>=4.21" PyMuPDF
次に、各 PDF ページを 2000 ピクセル幅の PNG にレンダリングし、multi2multivec-weaviate でベクトル化されたコレクションに BLOB として保存します。
import os
from base64 import b64encode
from pathlib import Path
import fitz # PyMuPDF
from weaviate import connect_to_weaviate_cloud
from weaviate.classes.config import Configure, DataType, Property
def page_to_b64(page, long_edge: int = 2000) -> str:
scale = long_edge / max(page.rect.width, page.rect.height)
pix = page.get_pixmap(matrix=fitz.Matrix(scale, scale))
return b64encode(pix.tobytes(output="png")).decode()
client = connect_to_weaviate_cloud(
os.environ["WEAVIATE_URL"],
auth_credentials=os.environ["WEAVIATE_API_KEY"],
)
if not client.collections.exists("PDF"):
client.collections.create(
name="PDF",
properties=[
Property(name="pdf_name", data_type=DataType.TEXT),
Property(name="page_number", data_type=DataType.INT),
Property(name="page_image", data_type=DataType.BLOB),
],
vector_config=Configure.MultiVectors.multi2vec_weaviate(
image_field="page_image",
),
)
col = client.collections.get("PDF")
for pdf_path in Path("pdfs").glob("*.pdf"):
with col.batch.fixed_size(batch_size=2) as batch, fitz.open(pdf_path) as doc:
for i, page in enumerate(doc, start=1):
batch.add_object(properties={
"pdf_name": pdf_path.name,
"page_number": i,
"page_image": page_to_b64(page),
})
client.close()
上記のコードに関するいくつかのポイント
Python の MultiVectors.multi2vec_weaviate(image_field="page_image") コールは、multi2multivec-weaviate モジュールを設定します。これは Console のインポート UI でも使用されている同じベクトライザーです。
ラスタライズ処理は PyMuPDF が担当します。長辺 2000 ピクセルをターゲットとするデフォルト値は妥当な選択です。より小さいサイズにすると処理時間が短縮され、大きいサイズにするとモデルがより詳細な情報を取得できます。1500 よりも小さくしたり、2500 よりも大きくしたりする明確な必要性は見つかっていません。
batch_size=2 は意図的な設定です。各オブジェクトには数メガバイトの画像が含まれるため、バッチサイズを小さくすることで gRPC のペイロードが適切に保たれます。
作成したコレクションに対してクエリを実行し、ランク付けされたページを返します:
from weaviate.classes.query import MetadataQueryres = col.query.near_text(
query="how did automotive revenue change over time",
limit=5,
return_properties=["pdf_name", "page_number"],
return_metadata=MetadataQuery(distance=True),
)
for o in res.objects:
print(o.metadata.distance, o.properties)
NVIDIA のコーパスでは、このコードを実行すると「Q2 FY26 Automotive」のページが結果の 1 番目に返されます。これは先ほどご覧いただいた 5 クォーター分の棒グラフですが、OCR を一度も使わずに取得されたものです。
コンソールで確認したクエリエージェントは、Python でも利用可能です。処理対象とするコレクションを指定し、ask() メソッドを実行します:
from weaviate.agents.query import QueryAgent
from weaviate_agents.classes import QueryAgentCollectionConfig
agent = QueryAgent(
client=client,
collections=[
QueryAgentCollectionConfig(name="PDF"),
],
)
agent.ask("How did automotive revenue change across FY26 quarters? What's driving it?")
response.display()
このように、Console で見たのと同じ合成回答とページ画像への参照が表示されます。
では、これが PDF 処理における万能薬なのでしょうか?
もちろん、そんなことはありません。エンジニアリングの世界では常にトレードオフが伴います。
まず、オブジェクトやページあたりのベクトル数が増える点です。後方相互作用型マルチベクトルモデルは、1 ページあたり多くのベクトルを生成します。Weaviate では Muvera などの圧縮技術がネイティブにサポートされているため、これである程度はカバーできますが、圧縮と精度のトレードオフが生じる点には注意が必要です。もし対象となるコーパスが法律契約書や議事録、ログファイルのように大量のプレーンテキストで構成されているなら、従来のテキスト埋め込みモデルの方がコストを抑えつつ、同等以上の精度を達成できるケースが多いでしょう。
ページ単位の検索は粗い粒度です。回答が密集した契約書の特定の段落に隠れている場合、1 ページ丸ごと返却すると、必要な情報以上にコンテキストが含まれてしまう可能性があります。実際には、Weaviate の Query agent などのエージェント層でこの問題を緩和するのが一般的です。ここでは、大量のトークンを消費することなく、関連する段落を特定することが可能です。
さらに、モデルがチャートを理解できるかという点も重要です。学習済みの公開コーパスから汎化能力は高いですが、非常にドメイン固有の視覚的慣習(例えば、独自にデザインされた社内テンプレートなど)が存在する場合は、検索品質を検証してから導入することをお勧めします。
このアプローチが特に効果を発揮するのは、四半期ごとのスライド資料、デューデリジェンス用パケット、科学的な図表、技術図面などを含む PDF 中心のドメインです。テキスト主体のコーパスであれば、テキスト専用のパイプラインの方がコストを抑えつつ十分な性能を発揮できるケースがほとんどでしょう。
さらなる最適化のためには、ハイブリッドアプローチも検討できます。具体的には、チャートや表が含まれるページをマルチベクトルとして処理し、それ以外の部分は通常のテキストとして扱い、クエリ実行時に RRF 方式で結果を統合する方法です。
結論として、以下のポイントをまとめます。
チャートや表は、より優れた OCR で解決すべき課題ではありません。これらは抽出プロセスで失われてしまう重要な情報そのものです。もしパイプラインがテキストのみをインデックスする仕組みであれば、埋め込み処理を開始する段階ですでに、チャートから得られる貴重な情報が失われています。
後期相互作用型マルチベクトルモデルを使えば、抽出工程を完全に省略できます。ページをレンダリングして画像として埋め込み、「この画像が何を意味しているか」を質問すればよいのです。モデルは外観に基づいてページを検索します。チャートや表のレイアウト、視覚的な特徴などすべてが手がかりになります。
Weaviate Cloud では、データ取り込みもドラッグ&ドロップで完了します。クエリエージェントを生成されたコレクションに指向させ、質問を入力するだけで、適切な画像を引用元として提示した回答が得られます。
同じ基本機能をデプロイ可能なコードに変換することも可能です。MultiVectors.multi2vec_weaviate(image_field="page_image") がベクトライザー設定のすべてです。残りの工程は、PyMuPDF を用いたページのラスタライズと、小さなバッチ処理ループ batch.add_object の実行だけです。
インデックス処理のせいでチャートが多い PDF への対応に頭を抱えていた方へ、ぜひ試してほしいアプローチがあります。これまで「チャートばかりで面倒だから」と避けてきたファイルこそが、この手法が得意とするところです。
Weaviate Cloud クラスターを起動し、PDF をアップロードして、今日から質問を投げかけてみましょう。
構築を始めたい方は、クイックスタートチュートリアルをチェックするか、無料で Weaviate Cloud アカウントを登録してください。
GitHub
フォーラム
X (Twitter)
ブログ記事を逃したくないですか?
隔週ニュースレターに登録して、最新情報をキャッチアップしましょう!
送信することで、利用規約およびプライバシーポリシーに同意したことになります。
関連記事
今日のまとめ
AIデイリーブリーフで今日の重要ニュースをまとめ読み