RAG・LLMパイプライン向け

RAG用PDFをMarkdown(マークダウン)に変換

PDFを検索とLLM取り込みに適したMarkdownへ変換します。表と数式を保ち、スキャンはOCRで文字化し、生のPDFテキストよりトークンを抑えます。REST APIまたはホスト型MCPから操作できます。

要点

RAGには整ったMarkdownを入れます

生のPDFテキストをembeddingすると、見出し、リスト、表が崩れ、読み順のノイズがchunkに混ざります。先にMarkdownへ変換すると文書構造が残り、見出しや節で分割できます。表と数式は事実として保たれ、一つの節が使うトークンも減ります。

効果

RAGパイプラインが扱いやすい形にします

自然なchunk境界

見出しと節が残るため、文の途中ではなく意味のまとまりで分割できます。

少ないトークン

生のPDFダンプやHTMLより小さく、embeddingと検索コンテキストのコストを抑えられます。

表を事実として保持

数値とヘッダーが揃ったMarkdown表になり、表の事実を検索できます。

数式を保持

数学記法を乱れた文字列へ平坦化せず、embeddingのノイズを減らします。

スキャンを文字化

OCRで画像だけのPDFを検索可能なMarkdownへ変換します。日本語も指定できます。

リンクと脚注

ハイパーリンクと脚注をMarkdownリンクとして保ち、参照関係を残します。

取り込み手順

4ステップでPDFをRAGへ取り込みます

HTTPSとBearer APIキーを使う一定のライフサイクルです。ホスト型MCPでも同じ操作をエージェントツールとして使えます。

1

ジョブを作成

PDF URLまたはアップロードをPOST /api/v2/jobsへ送り、ジョブIDと状態を受け取ります。

2

readyまで確認

GET /api/v2/jobs/{id}を呼び、readyまたはerrorまで待ちます。失敗時はerror_codeerror_messageを読みます。

3

Markdownを取得

GET /api/v2/jobs/{id}/downloadから結果を取得し、truncatedpagesを確認します。

4

chunkingとembedding

見出しと節で分割し、embeddingを作成してvector storeへ登録します。

# 1. create a job from a PDF URL
curl -s -X POST https://pdf2md.dev/api/v2/jobs \
  -H "Authorization: Bearer p2m_your_key" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/paper.pdf"}'
# -> { "job_id": "...", "status": "queued" }

# 2. poll status until ready or error
curl -s https://pdf2md.dev/api/v2/jobs/JOB_ID \
  -H "Authorization: Bearer p2m_your_key"
# -> { "status": "ready", "pages": 24, "truncated": false }
#    on failure: { "status": "error", "error_code": "...", "error_message": "..." }

# 3. fetch the Markdown, then chunk + embed it
curl -s https://pdf2md.dev/api/v2/jobs/JOB_ID/download \
  -H "Authorization: Bearer p2m_your_key"

エージェントから使う場合: ホスト型MCPはpdf_to_markdown_create_job_from_url_get_job_get_markdownを提供します。

chunking

Markdownを意味のある単位で分割します

見出しと節を自然な境界として使えます。

見出しで分割

見出し階層をchunk境界にし、各chunkを文脈の分かる自己完結した節にします。

表を途中で切らない

表の半分だけでは意味が失われます。表とその見出しを一つのchunkに保ちます。

少しoverlapさせる

隣接chunkに一、二文程度の重なりを持たせ、境界を越える文脈を保ちます。

見出しパスを付加

各chunkの先頭に節見出しまたは見出しのbreadcrumbを付け、文書内の位置をembeddingに含めます。

chunkサイズを調整

数百トークン程度から始めます。大きすぎると関連性が薄れ、小さすぎると文脈が失われます。

定型文を除去

各ページのヘッダーやフッターなどの繰り返しを除き、embeddingを支配しないようにします。

Python

最小のRAG取り込み例

ジョブを作成し、状態を確認し、Markdownを取得して見出しで分割します。

# pip install requests
import requests, time, re

API = "https://pdf2md.dev/api/v2"
H = {"Authorization": "Bearer p2m_your_key"}

job = requests.post(f"{API}/jobs", headers=H,
    json={"url": "https://example.com/paper.pdf"}).json()
jid = job["job_id"]

while True:
    j = requests.get(f"{API}/jobs/{jid}", headers=H).json()
    if j["status"] in ("ready", "error"): break
    time.sleep(3)

md = requests.get(f"{API}/jobs/{jid}/download", headers=H).text
# naive split on top-level headings -> chunks ready to embed
chunks = re.split(r"\n(?=# )", md)

表が検索しやすくなる理由

行とヘッダーが揃うため、価格、指標、日付などの表データを検索し、回答に引用できます。

ポーリングとWebhook

数件なら数秒ごとにGET /api/v2/jobs/{id}を呼びます。有料プランの一括処理ではWebhookまたはcallback_urlを登録し、readyまたはerrorの通知を受けます。

パイプライン

同じ変換をREST APIとホスト型MCPから使えます

機械可読のOpenAPIとMCP discoveryがあるため、スクリプトとエージェントのどちらからも操作できます。

FAQ

よくある質問

RAGで生のPDFテキストではなくMarkdownを使う理由は?

生の抽出では見出し、リスト、表、読み順が崩れ、ノイズの多いchunkになります。Markdownは構造を保つため、見出しで分割した節が検索しやすく、生テキストやHTMLよりトークンも抑えられます。

表と数式は検索用に保たれますか?

はい。列は実際のMarkdown表になり、数式も記法として保持されるため、数値と表の事実を検索できます。

パイプラインで自動化できますか?

はい。Bearer APIキー付きのREST APIで作成、ポーリング、ダウンロードを行うか、エージェントフレームワークからホスト型MCPを使います。有料プランではWebhookも利用できます。

長い文書はどう処理しますか?

処理時間枠に達した文書は失敗せず、truncated=true付きの一部結果として返ります。truncatedを確認し、大きな文書を分割するか処理時間枠の長いプランを使います。

スキャンPDFもRAGに取り込めますか?

はい。OCRで画像だけのPDFを検索可能なMarkdownへ変換します。日本語OCRもリクエスト単位で指定できます。

RAG用Markdownはどのようにchunkingしますか?

見出し階層で分割し、表は途中で切らず、隣接chunkに一、二文程度のoverlapを持たせます。各chunkの先頭に見出しパスを付け、数百トークン程度から調整します。

Markdown表はなぜ生テキストより検索しやすいですか?

生の抽出では列が混ざり、クエリと値が対応しにくくなります。Markdown表では行とヘッダーが揃うため、表の事実を検索し、回答に引用できます。

無料でテストできますか?

はい。無料のGoogleアカウントでAPIキーとホスト型MCPを利用できます。上限は3スロット、最大10 MB、処理時間枠15分、保存期間1時間です。有料プランでは各上限が上がり、Webhookと一括作成が追加されます。