ClaudeのCitationsでスキャンPDFを引用できない理由と回避策
テキスト抽出できないスキャンPDFはCitationsの引用対象外です。仕組み上の理由と、OCRやテキスト抽出による回避策、citations無効時の読み取りとの違いを扱います。
スキャンPDFを渡すとCitationsは何が起きるか
Citationsは、Claudeの回答に文書中の該当箇所を出典として添える機能です。しかし、紙をスキャンしただけのPDF、つまりテキストレイヤーを持たず画像だけで構成されたPDFは、この引用の対象になりません。
公式ドキュメントは明確にこう書いています。「PDF文書はテキストが抽出され、文単位でチャンク分割される。画像からの引用はまだサポートされていないため、抽出可能なテキストを含まないスキャンPDFは引用できない」。抽出できるテキストが1文字も無ければ、チャンク分割そのものが成立せず、cited_textを返す元データが存在しないことになります。
契約書・請求書・古い紙資料をまとめてナレッジベース化するようなワークフローでは、紙をスキャンしただけのPDFがそのまま混ざり込んでいることが珍しくありません。気づかないまま運用に乗せると、「一部の文書だけ引用が付かない」という原因が分かりにくい形で表面化します。
エラーで弾かれるわけではありません。リクエスト自体は通り、Claudeは画像として認識した内容から応答を生成しますが、その応答に位置情報付きの引用が付かない、という形で制約が表れます。テキストを含む通常のPDFであれば、応答の各文には次のようなpage_location型の引用が付きます。
{
"type": "page_location",
"cited_text": "Water is essential for life.",
"document_index": 1,
"document_title": "PDF Document",
"start_page_number": 5,
"end_page_number": 6
}スキャンPDFではこのcitations配列自体が空になるか付与されず、地の文だけが返ってきます。エラーメッセージで気づける不具合ではないため、「引用が付くはずなのに付かない」という形で発覚しやすい点に注意します。
公式ドキュメントの記述は文書単位で、複数ページの一部だけがスキャンで残りはテキスト付きという混在PDFの挙動までは明記されていません。混在するPDFを扱う場合は、想定どおりに引用が付くかを事前に検証してから運用に組み込むほうが安全です。
なぜ画像のみのPDFは引用できないのか
理由はCitations機能の設計そのものにあります。PDFの引用は「ページ内のどの文字範囲を参照したか」をページ番号込みで返す仕組みで、これは元のPDFから抽出したテキストに対してのみ機能します。画像から直接テキスト位置を特定して引用する機能(画像内引用)は、現時点でCitations側にまだ実装されていません。
つまりボトルネックは2つ重なっています。1つはスキャンPDFにテキストレイヤーが無いこと、もう1つはCitationsが画像そのものからの引用にまだ対応していないことです。どちらか一方が解消されても、もう一方が残っていれば引用は成立しません。
この2つ目の制約は、スキャンPDF以外にも及びます。テキストがきちんと抽出できる通常のPDFであっても、ページ内のグラフや図表そのものを引用元として指し示すことはできません。Claudeはグラフの内容を読み取って説明できますが、その説明に付くcitationsは、あくまで抽出済みテキストの範囲を指すものに限られます。
アップロード前にテキストレイヤーの有無を機械的に確認する
PDFビューアで目視確認する以外に、手元のスクリプトでテキストレイヤーの有無を先に判定しておく方法もあります。以下はpdfplumberを使い、各ページから抽出できる文字数を数える最小限のチェックです。
import pdfplumber
def has_extractable_text(pdf_path, min_chars_per_page=20):
with pdfplumber.open(pdf_path) as pdf:
for page in pdf.pages:
text = page.extract_text() or ""
if len(text.strip()) < min_chars_per_page:
return False
return True大量のPDFをまとめてCitations対応のパイプラインに流す場合、この種のチェックをアップロード前段に挟んでおくと、スキャンPDFだけを自動でOCR処理に振り分けられます。1ページでも抽出できる文字数が閾値を下回れば、そのファイル全体をスキャン扱いとして扱う、という単純な判定で十分実用になります。
回避策1: OCRでテキストレイヤーを加えてから渡す
もっとも直接的な対処は、アップロード前にOCR(光学文字認識)でスキャンPDFへテキストレイヤーを加えることです。テキストレイヤーが埋め込まれたPDFは「抽出可能なテキストを含む」PDFになるため、通常のPDF文書と同じ経路でCitationsの対象になります。
自分のPDFがすでにテキストレイヤーを持っているかどうかは、PDFビューアでテキストを選択・コピーできるかで簡単に確認できます。選択できなければ画像のみのスキャンで、選択できればすでに抽出可能な状態です。OCR後のPDFをそのままリクエストに埋め込むと容量が大きくなりがちなので、繰り返し使う文書はFiles APIにアップロードしてfile_idで参照する方法もあります。
スキャンPDFはページ数のわりにファイルサイズが大きくなりやすい点にも注意します。リクエスト全体のサイズには32MBという上限があり、これはPDF単体だけでなく、同じリクエストに含める他のテキストや画像もあわせた合計です。OCR後もサイズが大きいままなら、Files API経由での参照か、ページ単位への分割を検討します。
回避策2: 自前で抽出したテキストをプレーンテキスト・カスタムコンテンツ文書として渡す
Citationsが対応する文書形式はPDFだけではありません。プレーンテキスト文書とカスタムコンテンツ文書も選べます。
| 文書タイプ | 適した用途 | チャンク分割 | 引用の形式 |
|---|---|---|---|
| プレーンテキスト | 適した用途シンプルな文章 | チャンク分割文単位で自動 | 引用の形式文字インデックス(0始まり) |
| 適した用途テキストを含むPDFファイル | チャンク分割文単位で自動 | 引用の形式ページ番号(1始まり) | |
| カスタムコンテンツ | 適した用途箇条書き・書き起こしなど、より細かい引用単位が必要な場合 | チャンク分割追加分割なし(渡したブロックがそのまま単位) | 引用の形式ブロックインデックス(0始まり) |
自前のOCRパイプラインやサードパーティのOCRサービスでスキャンPDFからテキストを抽出できるなら、そのテキストをPDFとしてではなく、プレーンテキスト文書かカスタムコンテンツ文書として渡す方法があります。すでにテキストを持っているので、Claude側での再抽出は発生しません。
カスタムコンテンツ文書を使うと、抽出したテキストをどう区切って引用単位にするかを自分で制御できます。ページ単位・段落単位・見出し単位など、OCR結果の構造に合わせてブロックを分けられます。
OCRでテキストレイヤーを加えるひと手間は、引用の正確性だけでなくコスト面でも意味があります。Citationsは応答に含まれるcited_textを出力トークンとしてカウントしないため、抽出可能な状態にしてCitationsの対象にできれば、その分だけ長期的なコストも抑えられます。
2つの回避策のどちらを選ぶかは、既存のワークフローに何があるかで決まります。
| 判断基準 | OCRしてPDFのまま渡す | 抽出してカスタムコンテンツで渡す |
|---|---|---|
| すでにOCR済みのPDF資産がある | OCRしてPDFのまま渡す向く。追加実装がほぼ不要 | 抽出してカスタムコンテンツで渡す向かない。二重の変換になる |
| 引用の単位を段落・見出しなど細かく制御したい | OCRしてPDFのまま渡す向かない。文単位の自動分割になる | 抽出してカスタムコンテンツで渡す向く。ブロック単位を自分で決められる |
| ページ番号ベースの引用をそのまま使いたい | OCRしてPDFのまま渡す向く。page_location型がそのまま使える | 抽出してカスタムコンテンツで渡す向かない。ページ番号ではなくブロックインデックスになる |
| OCR結果をすでに構造化データとして保持している | OCRしてPDFのまま渡す向かない。PDFへ戻す変換が余計 | 抽出してカスタムコンテンツで渡す向く。構造化データをそのままブロックにできる |
curl https://api.anthropic.com/v1/messages \
-H "content-type: application/json" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-opus-5",
"max_tokens": 1024,
"messages": [{
"role": "user",
"content": [
{
"type": "document",
"source": {
"type": "content",
"content": [
{"type": "text", "text": "(OCR抽出: 1ページ目)"},
{"type": "text", "text": "(OCR抽出: 2ページ目)"}
]
},
"title": "スキャンPDFのOCR結果",
"citations": {"enabled": true}
},
{"type": "text", "text": "この文書の要点を教えて"}
]
}]
}'このカスタムコンテンツ文書には、元のPDFのページ番号ではなく、渡したブロックのインデックスが引用として返ります。ページ番号で参照したい場合は、ブロックごとに「◯ページ:」のような接頭辞をテキストへ自分で埋め込んでおくと、応答からどのページの内容かを読み取れます。
複数文書を同時に渡すときの落とし穴
Citationsは1リクエストに含まれる全ドキュメントに対して、有効・無効を揃える必要があります。テキスト付きのPDFとスキャンPDFを同じリクエストに混在させて、片方だけCitationsを有効にする、という指定はできません。
実務でよくあるのは、複数の資料をまとめて1回のリクエストに詰め込んだところ、その中に1つだけスキャンPDFが混じっていたケースです。この場合、選択肢は2つです。スキャンPDFだけを事前にOCRしてから他の文書と一緒に渡すか、スキャンPDFをリクエストから外して別リクエストに分けるかのどちらかになります。「1つのファイルだけが原因で全体の引用が使えなくなる」という状況を避けるには、リクエストを組み立てる前に全文書のテキスト抽出可否を確認しておくのが確実です。
Citations無効なら画像のみのPDFでも内容は読める
紛らわしい点として、Citationsを無効にした通常のPDF処理では、スキャンPDFでも内容を読ませること自体はできます。Claudeは各ページを画像として変換し、その画像とあわせてテキスト(抽出できた場合のみ)を渡す仕組みで動いています。テキストレイヤーが無くても、画像としての理解は機能するため、要約や質問応答のタスク自体は成立します。
制約が出るのはあくまで引用のグラウンディング、つまり「この主張は文書のどこにあるか」を位置情報付きで返す機能だけです。スキャンPDFの内容についてClaudeに質問すること自体はCitationsなしでも問題なくできるので、必要なのが要約や質問応答だけで、出典の厳密な位置情報までは要らない場合は、Citationsを無効にしたまま使う選択肢もあります。通常のPDF読み込みそのものの手順やアップロード上限はClaudeのPDF読み込み・画像解析の使い方にまとめています。
まとめ
スキャンPDFがCitationsで引用できないのは、テキストレイヤーが無いことと、Citationsが画像からの直接引用にまだ対応していないことの2つが重なっているためです。回避策は主に2つで、OCRでテキストレイヤーを加えてPDFのまま渡すか、自前で抽出したテキストをプレーンテキスト・カスタムコンテンツ文書として渡すかのどちらかです。テキスト付きPDFのグラフや図表も同じ制約の対象で、引用できるのはあくまで抽出済みテキストの範囲だけである点も忘れずに押さえておきます。
引用のグラウンディングまでは要らず、内容を読ませるだけでよいなら、Citationsを無効にした通常のPDF処理でも画像のみのスキャンPDFを扱えます。複数文書を1リクエストにまとめるときは、Citationsの有効・無効が全文書で揃っている必要がある点にも注意します。トークンコストの面でCitationsがどう効くかはCitationsのトークンコストの仕組みで扱っているので、コスト設計とあわせて確認すると導入判断がしやすくなります。