PydanticAI ビジュアルガイド

Lesson CH06-L02

PDF解析

PDFドキュメントをそのまま入力し、構造化抽出を行う。

読了目安
10 min
Colab目安
16 min
合計
26 min
前提
画像入力

関連: 公式ドキュメント

一行サマリ

DocumentUrl(url='https://.../doc.pdf') または BinaryContent(data=pdf_bytes, media_type='application/pdf')agent.run_sync のリストに含めるだけで、Gemini に PDF を直接渡してテキスト + レイアウト + 表 + 図 を理解させられる。OCR / 前処理パイプラインを組まずに、構造化抽出までワンショット。

ヒーロー: PDF も「メディア要素」の 1 つ

画像 (Ch6-L01) と同じく、PDF も agent.run_sync([prompt, DocumentUrl(...)]) のリストに混ぜる だけで Gemini に渡せます。Gemini は内部で PDF をページ単位の画像 + テキストに分解し、レイアウトと表構造を保持したまま 解析します。

図を読み込み中…
図1. PDF 入力の流れ

概念: 画像入力との違いは media_type だけ

渡し方型 / media_type
URL 参照DocumentUrl(url='https://.../file.pdf')
バイナリ直接BinaryContent(data=bytes, media_type='application/pdf')

「PDF 用の特別な API」ではなく、Document または media_type='application/pdf' を選ぶだけ。複数 PDF も、PDF + 画像も、PDF + テキスト指示も、リストに積めば自由に組み合わせられます。

Gemini の PDF サイズ上限は概ね 50 MB / リクエスト、ページ数も 数百ページまで 受け付けます (モデルやコンテキスト長による)。本番では事前に分割するのが安全。

コード: 3 つのパターン

パターン 1: 公開 PDF を URL で渡して要約

from pydantic_ai import Agent, DocumentUrl
from pydantic_ai.models.google import GoogleModel
 
agent = Agent(
    GoogleModel('gemini-3-flash-preview'),
    instructions='PDF の内容を日本語で 5 行以内に要約してください。',
)
 
result = agent.run_sync([
    'この資料の要点を教えてください。',
    DocumentUrl(url='https://arxiv.org/pdf/2305.13245.pdf'),
])
print(result.output)

ポイント:

  • DocumentUrlpydantic_ai から直接 import
  • 公開 URL から Gemini 側がダウンロード
  • 中身が PDF か HTML かは 拡張子ではなく Content-Type で判定される (PDF を返さないとエラー)

パターン 2: ローカル PDF を BinaryContent で渡す

from pathlib import Path
from pydantic_ai import Agent, BinaryContent
from pydantic_ai.models.google import GoogleModel
 
agent = Agent(GoogleModel('gemini-3-flash-preview'))
 
pdf_bytes = Path('./report.pdf').read_bytes()
 
result = agent.run_sync([
    'この PDF の Executive Summary 部分を抜粋してください。',
    BinaryContent(data=pdf_bytes, media_type='application/pdf'),
])
print(result.output)

media_type'application/pdf' にするのが唯一のポイント。社内文書や認証付きストレージから取得した PDF はこのパターン。

パターン 3: PDF から構造化データを抽出 (Ch4 の合わせ技)

from pydantic import BaseModel, Field
from pydantic_ai import Agent, DocumentUrl
from pydantic_ai.models.google import GoogleModel
 
class PaperMeta(BaseModel):
    title: str = Field(description='論文タイトル')
    authors: list[str] = Field(description='著者名のリスト')
    abstract_ja: str = Field(description='アブストラクトの日本語要約 (200 字以内)')
    key_findings: list[str] = Field(description='主要な発見を 3 つ', max_length=3)
 
agent = Agent(
    GoogleModel('gemini-3-flash-preview'),
    output_type=PaperMeta,
    instructions='論文 PDF から構造化メタ情報を抽出してください。',
)
 
paper = agent.run_sync([
    'この論文のメタ情報を抽出してください。',
    DocumentUrl(url='https://arxiv.org/pdf/2305.13245.pdf'),
]).output
 
print(paper)
# PaperMeta(title='...', authors=['...'], abstract_ja='...', key_findings=['...', '...', '...'])

研究論文のサーベイ、見積書のフィールド抽出、契約書からの条項抽出、医療レポートの定型化 ── 「PDF → JSON」のユースケースは無限 にあります。

図を読み込み中…
図2. PDF ユースケース別の出力タイプ

観察: トークン消費は「ページ数 × 解像度」

PDF は内部で画像 + テキストに分解されるため、ページ数が増えるほど input_tokens が線形以上に伸びる ことがあります。

result = agent.run_sync([
    'この PDF を要約',
    DocumentUrl(url='https://arxiv.org/pdf/2305.13245.pdf'),
])
print(result.usage())
# RunUsage(requests=1, input_tokens=8500, output_tokens=300, ...)
#                              ^^^^^ ページ数次第で 1 万超もある

長大な PDF は 章ごとに分割して並列処理 したほうが速度・コスト両面で有利。

まとめ

  • DocumentUrl(url=...) で公開 PDF、BinaryContent(data=bytes, media_type='application/pdf') でローカル PDF
  • 画像入力と同じくリストに混ぜるだけ
  • output_type=BaseModel と組み合わせれば「PDF → JSON」を 1 ステップで実現
  • ページ数 × 解像度で input_tokens が伸びるため、大きい PDF は事前分割

次レッスンでは YouTube URL 直接入力 — Gemini 固有の VideoUrl で動画をそのまま理解させるパターンを扱います。

Colab で実際に動かす

本レッスンの内容を Google Colab 上で実行できるノートブックを用意しています。下のボタンから自分のColab環境に開けます (要 Google アカウント / GOOGLE_API_KEY)。

Open in Colab

notebooks/ch06/02-pdf-parsing.ipynb