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でも同じ操作をエージェントツールとして使えます。
ジョブを作成
PDF URLまたはアップロードをPOST /api/v2/jobsへ送り、ジョブIDと状態を受け取ります。
readyまで確認
GET /api/v2/jobs/{id}を呼び、readyまたはerrorまで待ちます。失敗時はerror_codeとerror_messageを読みます。
Markdownを取得
GET /api/v2/jobs/{id}/downloadから結果を取得し、truncatedとpagesを確認します。
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を提供します。
Markdownを意味のある単位で分割します
見出しと節を自然な境界として使えます。
見出しで分割
見出し階層をchunk境界にし、各chunkを文脈の分かる自己完結した節にします。
表を途中で切らない
表の半分だけでは意味が失われます。表とその見出しを一つのchunkに保ちます。
少しoverlapさせる
隣接chunkに一、二文程度の重なりを持たせ、境界を越える文脈を保ちます。
見出しパスを付加
各chunkの先頭に節見出しまたは見出しのbreadcrumbを付け、文書内の位置をembeddingに含めます。
chunkサイズを調整
数百トークン程度から始めます。大きすぎると関連性が薄れ、小さすぎると文脈が失われます。
定型文を除去
各ページのヘッダーやフッターなどの繰り返しを除き、embeddingを支配しないようにします。
最小の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があるため、スクリプトとエージェントのどちらからも操作できます。
よくある質問
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と一括作成が追加されます。