RAG で表や画像入りの文書を扱いたい
RAG とか Agentic AI で、プレーンなテキストではなくて、表とか画像とか含んだPDFとかPPTXとかの非構造化データを使いたいケースはあると思います。非構造化データもがんばって実装すればいろいろ解析できるんでしょうけど、手っ取り早くやってみたいものです。
Langflow 1.5 から非構造化データを解析する Docling をサポートするようになったので、これを試してみたいと思います。この記事では Langflow 1.9.2 を使うので1.5よりも安定してきていると思います。
インストールと実行
公式 Doc (https://docs.langflow.org/bundles-docling) をみると、以下のコマンドで Langflow と Docling をまとめてインストールできます。
uv pip install langflow
私はコンテナイメージを使いたいので、以下のような Dockerfile を作ってイメージをビルドします。
- 最新版の 1.9.3 のイメージだとうまく Docling が入りませんでした (1.9.3のイメージがpython 3.14系でサポート外なので)
- Docling をビルドするためのツールや、実行時に必要な画像処理系のライブラリを apt-get でいれます。これらが欠けると、ビルドに失敗したりビルドに成功しても実行時にエラーが出ました。
FROM langflowai/langflow:1.9.2
USER root
# Build tool for compile and library for image processing in docling
RUN apt-get update && apt-get install -y \
build-essential \
python3-dev \
meson \
ninja-build \
libxcb1 \
libx11-6 \
libxext6 \
libxrender1 \
libgl1 \
libglib2.0-0 \
&& rm -rf /var/lib/apt/lists/*
RUN /app/.venv/bin/pip install --no-cache-dir "langflow[docling]"
RUN /app/.venv/bin/pip install --no-cache-dir "langchain-docling"
Dockerfile と同じディレクトリに移動して、以下のコマンドでイメージのビルドと実行を行います。
docker build -t langflow-docling:1.9.2 .
docker run --rm -p 7860:7860 langflow-docling:1.9.2
こんな感じの出力がでるので、http://localhost:7860 にアクセスします。
✓ Initializing Langflow...
✓ Checking Environment...
✓ Starting Core Services...
✓ Connecting Database...
✓ Loading Components...
✓ Adding Starter Projects...
✓ Launching Langflow...
╭─────────────────────────────────────────────────────────────────────────╮
│ │
│ Welcome to Langflow │
│ │
│ 🌟 GitHub: Star for updates → https://github.com/langflow-ai/langflow │
│ 💬 Discord: Join for support → https://discord.com/invite/EqksyE2EX9 │
│ │
│ We collect anonymous usage data to improve Langflow. │
│ To opt out, set: DO_NOT_TRACK=true in your environment. │
│ │
│ 🟢 Open Langflow → http://localhost:7860 │
│ │
╰─────────────────────────────────────────────────────────────────────────╯
Docling を試してみる
試してみるデータ
以前電子工作に使ったことのある、秋月電子さんのセンサーモジュールのマニュアルを使ってみたいと思います。回路図や表形式のピンの説明があるので、こういった情報がうまくとれることを期待したいです。
Docling 解析結果
まずはシンプルに Docling の PDF Parse の機能を使ってみます。テキスト、画像、表を分解して、内容を抽出してくれます。Langflow には Docling のコンポーネントを配置します。左のメニューから docling で検索すると出てくるので、ドラッグアンドドロップしましょう。
Select files で KXR94-2050 のマニュアルを選択して、コンポーネントの右上の再生ボタンから実行します。私の環境 (Macbook Pro) で40秒くらいすると処理が完了し、右下の Files から実行結果を確認することができます。
file_path は Langflow にアップロードされたドキュメントのパスで、doc は解析結果です。
途中、省略しながら解析結果の全体像を紹介していきます。
文書の属性
最初にファイル名などがあります。
"schema_name": "DoclingDocument",
"version": "1.10.0",
"name": "KXR94_2025_06_25",
"origin": {
"mimetype": "application/pdf",
"binary_hash": 9668758761038993000,
"filename": "KXR94_2025_06_25.pdf",
"uri": null
文書構造
body のなかには、ファイルの texts, tables, pictures またはそれらの組み合わせである groups がどういう順に表れているかが示されます。以下だと texts/0, groups/0, groups/1 ... と続きます。groups の中身についても別のところで記載されていますが、今回は説明を省略します。
"body": {
"self_ref": "#/body",
"parent": null,
"children": [
{
"cref": "#/texts/0"
},
{
"cref": "#/groups/0"
},
{
"cref": "#/groups/1"
}]
}
テキスト
テキスト内容(以下の場合、「3軸加速度センサー X、Y、Z アナログ電圧出力 KXR94-2050モジュール」)とバウンディングボックス、何ページ目に書かれているか、などがわかります。
"texts": [
{
"self_ref": "#/texts/0",
"parent": {
"cref": "#/body"
},
"children": [],
"content_layer": "body",
"meta": null,
"label": "section_header",
"prov": [
{
"page_no": 1,
"bbox": {
"l": 26.7,
"t": 695.8000000000001,
"r": 500.03000000000003,
"b": 626.232,
"coord_origin": "BOTTOMLEFT"
},
"charspan": [
0,
40
]
}
],
"orig": "3軸加速度センサー X、Y、Z アナログ電圧出力 KXR94-2050モジュール",
"text": "3軸加速度センサー X、Y、Z アナログ電圧出力 KXR94-2050モジュール",
"formatting": null,
"hyperlink": null,
"level": 1
}
表
table_cells のなかにセルの情報が表示されています。row_spans や col_spans は各セルがどれくらい行と列の幅を取っているかを示しています。start_row_offset_idxなどは、行列のどの位置から始まって、どこで終わっているかを示しています。text がセルの中に記載されているテキストを示しています。
"tables": [
{
"self_ref": "#/tables/0",
"parent": {
"cref": "#/body"
},
"children": [],
"content_layer": "body",
"meta": null,
"label": "table",
"prov": [
{
"page_no": 1,
"bbox": {
"l": 13.911752700805664,
"t": 286.4776306152344,
"r": 505.63787841796875,
"b": 48.79010009765625,
"coord_origin": "BOTTOMLEFT"
},
"charspan": [
0,
0
]
}
],
"captions": [],
"references": [],
"footnotes": [],
"image": null,
"data": {
"table_cells": [
{
"bbox": {
"l": 17,
"t": 449.4,
"r": 41,
"b": 461.388,
"coord_origin": "TOPLEFT"
},
"row_span": 1,
"col_span": 1,
"start_row_offset_idx": 0,
"end_row_offset_idx": 1,
"start_col_offset_idx": 0,
"end_col_offset_idx": 1,
"text": "番号",
"column_header": true,
"row_header": false,
"row_section": false,
"fillable": false
},
図
OCR Engine も Picture Description LLM も指定しない場合は、ただ pictures のバウンディングボックスなどが抽出され、図に関する情報は何も出力されません。
OCR Engine を指定する場合
OCR Engine を指定した場合は図中のテキストを抽出することができます。図には複数のテキストが含まれているので、まずは図とテキストの関係が以下のように出力されます。
"pictures": [
{
"self_ref": "#/pictures/0",
"parent": {
"cref": "#/body"
},
"children": [
{
"cref": "#/texts/8"
},
]
そのうえで各テキストが以下のように抽出されます。
{
"self_ref": "#/texts/8",
"parent": {
"cref": "#/pictures/0"
},
"children": [],
"content_layer": "body",
"meta": null,
"label": "text",
"prov": [
{
"page_no": 1,
"bbox": {
"l": 32,
"t": 479.66666666666663,
"r": 53.333333333333336,
"b": 469,
"coord_origin": "BOTTOMLEFT"
},
"charspan": [
0,
3
]
}
],
"orig": "Vdd",
"text": "Vdd",
"formatting": null,
"hyperlink": null
}
Picture Description LLM を指定する場合
以下のように画像に対応した Language Model を接続すると文書内の画像を解釈して図の説明(キャプション)をつけてくれます。以下の図では NVIDIA NIM の nemotron-nano-12b-v2-vl を vLLM コンポーネントから使用しています。これ以外にも OpenAI の gpt-4o や watsonx.ai の llama-3-2-11b-vision-instruct も使えます。
出力の picures のなかに、図の説明が含まれるようになります。
{
"self_ref": "#/pictures/3",
"parent": {
"cref": "#/body"
},
"children": [],
"content_layer": "body",
"meta": {
"summary": null,
"description": {
"confidence": null,
"created_by": "langchain",
"text": "This image is a diagram of a circuit board. The circuit board has many components including sensors, amplifiers, and logic gates. The circuit board also has many inputs and outputs.\n"
},
"classification": null,
"molecule": null,
"tabular_chart": null,
"code": null
},
PDF の RAG を構築する
Docling を VLM を使ったフローに、チャット用の LLM などを繋いで RAG のフローを構築してみます。
Docling の出力から Parser コンポーネントで {doc} だけ取り出します。この取り出した内容とChat Input を Prompt Template コンポーネントで結合します。結合したテキストを LLM (NVIDIA の NIM を使っています) に入力して、その出力を Chat Output に接続します。NVIDIA の NIM のモデルは、nvidia/nvidia-nemotron-nano-9b-v2 を使いますが、NVIDIA コンポーネントのメニューから選択できないので、Model Name のところに直打ちします。
チャットを実行してみる
Langflow の Playground から作成したフローを試してみます。最初に、PDFの中にある画像を説明してもらいます。そうすると Docling のパースした内容から pictures や tables の内容を拾って、どういう情報が含まれているかを回答してくれます。
もう少しマニュアルで調べてみたいような質問を投げかけてみます。
「KXR94-2050モジュールのピンについて教えて」
正しく教えてくれました。ただ、なぜか主なピンとその他のピンで分けて説明してくれます(Vdd がなぜその他なのか気になりますが、、、)。実際にモジュールをはんだ付けするときはPDFも見ておきましょう!
KXR94-2050モジュールを水平な場所に置いて静止しているのに、X軸の加速度が 0 ではありませんでした。なぜでしょうか。
初めて使うときの定番の質問ですが、マニュアルにもとづいて「主な原因はゼロg時のオフセット誤差と感度誤差です。」と回答してくれました。
まとめ
Docling と VLM を利用することで簡単に PDF を使った RAG ができました。手元の Laptop で実施したのもあって、1回のチャットに数十秒かかってしまうのが難点なので、事前にベクトルDBに入れておくと良いかもしれません。次は Docling を使って PDF や PPTX をベクトルDBに入れて RAG をやってみたいと思います。






