意外なほど多くの「ドキュメント AI」は、要するに画像をチャットモデルに 送って、返ってきた内容を読んでいるだけです。レシート、ダッシュボードの スクリーンショット、スキャンした PDF のページ、ホワイトボードの写真 — 最新の Claude や Gemini はそのすべてをネイティブに読み取り、別途 OCR エンジンを用意する必要はありません。厄介なのはたいてい配管部分です。 プロバイダーごとに画像の添付方法が違い、コードを一方から他方へ移植する のは面倒です。
Brievio を通せば、1 つのリクエストの形 — OpenAI の Chat Completions の content 配列に image_url パートを入れる形 — だけで、Claude Opus 4.7、Sonnet 4.6、Haiku 4.5、 そして Gemini 2.5 Pro / Flash に対して同じように動きます。これらは ネイティブビジョンをそのまま尊重した本物のファーストパーティのモデルなので、 Claude がうまく読める JPEG は、Claude が実際にちゃんと読みます。本記事で 扱うのは画像入力(理解)であって画像生成ではありません。URL、base64、 複数画像のプロンプト、そして実務で出てくる OCR / チャート / スキャン文書の パターンを取り上げます。
最もシンプルなケース: URL による画像
画像がすでに公開 HTTPS URL に置かれているなら、テキストの隣に image_url パートとして添付します。claude-sonnet-4-6 を gemini-2.5-pro に差し替えてもリクエストボディは変わりません — この移植性こそが肝心な点です。
# 画像を URL で送る。OpenAI と同じ chat の形のまま、本物のモデルに対して。
from openai import OpenAI
client = OpenAI(
api_key="sk-brievio-...",
base_url="https://api.brievio.com/v1",
)
resp = client.chat.completions.create(
model="claude-sonnet-4-6", # または gemini-2.5-pro — リクエストの形は同じ
max_tokens=500,
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "What does this chart show? Give the trend in one sentence."},
{
"type": "image_url",
"image_url": {"url": "https://example.com/q3-revenue.png"},
},
],
}
],
)
print(resp.choices[0].message.content)
# 画像は入力(INPUT)トークンとして課金される — resp.usage.prompt_tokens でコストを確認。早いうちに体に染み込ませておくべきこと: 画像は入力トークンを 消費します。モデルはピクセルをタダで見るわけではなく — 画像を タイルに分割し、各タイルがテキストと同じように課金されます。Brievio は 正直なトークン数を報告するので、画像のコストは上流プロバイダーが課金する とおりに resp.usage.prompt_tokens へそのまま現れます。 フルスクリーンのスクリーンショットは解像度しだいで数百から数千の入力 トークンに達することがあります。タダの特典ではなく、ひと段落ぶんの コンテキストと同じように見積もってください。
base64: 実際にあなたが使うことになるケース
本番では画像が公開 URL であることはまれです — ユーザーが今アップロード したばかりのファイル、スキャナーからのバッファ、非公開の S3 オブジェクト です。そういうときは、バイト列を base64 の data: URL として インライン埋め込みします。モデルには違いが分かりませんし、バイト列を公開 到達可能にする必要も一切ありません。
# 本番の画像の多くは公開 URL ではない。base64 のデータ URL としてインライン埋め込みする。
import base64
from openai import OpenAI
client = OpenAI(api_key="sk-brievio-...", base_url="https://api.brievio.com/v1")
def data_url(path: str, media_type: str = "image/png") -> str:
with open(path, "rb") as f:
b64 = base64.standard_b64encode(f.read()).decode("utf-8")
return f"data:{media_type};base64,{b64}"
resp = client.chat.completions.create(
model="gemini-2.5-flash", # OCR / レシートには安価で高速
max_tokens=800,
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "Extract every line item and total as JSON. Keys: items[], total."},
{"type": "image_url", "image_url": {"url": data_url("receipt.jpg", "image/jpeg")}},
],
}
],
)
print(resp.choices[0].message.content)
# ヒント: データ URL は生ファイルよりリクエストボディが約 33% 膨らむ。画像は
# 適度なサイズに抑える — テキストなら 2〜3MP のスクリーンショットで十分、12MP はまず不要。実践的な注意点が 2 つ。第一に、base64 はリクエストボディを約 33% 増やしますし、画像 1 枚あたりのサイズ上限もあります(Anthropic は API 上で単一画像を約 5 MB に制限、Gemini にも独自の上限があります)。 大きなスキャンが 413 を返すなら縮小してください — テキストは想像より ずっと低い解像度でも判読できます。第二に、正しい media_type (image/png、image/jpeg、image/webp) を送ってください。タイプの不一致は、無言のデコード失敗のよくある原因です。 Brievio ではリクエストが 4xx や 5xx で失敗しても課金されません — 失敗した呼び出しは無料なので、縮小した画像を二重払いせずに再試行できます。
複数画像のプロンプトとスキャン文書
content 配列には、テキストと交互に、好きなだけ image_url パートを入れられます。これによって本当に役立つ ワークフローが開けます。ビフォー / アフターのスクリーンショットを比較する、 複数ページのスキャン文書を読む、一連のチャートを与えて一貫した筋を尋ねる、 など。両方のモデル系列で効く小技は、各画像に小さなテキストアンカーを 付けて、モデルが引用できるようにすることです。
# 1 つのプロンプトに複数画像 — 2 枚のスクリーンショットを比較したり、4 ページのスキャンを読んだり。
content = [
{"type": "text", "text": "These are pages 1-3 of a scanned contract. Summarize the parties, term, and termination clause. Cite the page number for each."},
]
for i, path in enumerate(["page1.png", "page2.png", "page3.png"], start=1):
content.append({"type": "text", "text": f"--- Page {i} ---"})
content.append({"type": "image_url", "image_url": {"url": data_url(path)}})
resp = client.chat.completions.create(
model="claude-opus-4-7", # 密度の高い文書に対する最強の推論
max_tokens=1200,
messages=[{"role": "user", "content": content}],
)
print(resp.choices[0].message.content)
# 各画像の前に小さなテキストラベル("--- Page 2 ---")を挟むと、モデルが引用する
# アンカーになり、どちらのモデル系列でも複数画像のグラウンディングが目に見えて向上する。長い文書にはモデル選択のトレードオフがあります。Gemini 2.5 Flash は 安価で高速、大量の OCR、レシート、フォーム抽出には最適なデフォルトです。 Claude Opus 4.7 は密度が高く複数ページにまたがる素材 — 契約書、財務諸表、 複数ページを視野に保って相互参照させる必要があるもの — に対してより強く 推論します。Sonnet 4.6 と Gemini 2.5 Pro はその中間に位置します。model 文字列以外のコードを変えずにタスクごとにルーティング できます。最新の一覧は /models をご覧ください。
これらのモデルが得意なこと(そして不得意なこと)
ネイティブビジョンは幅広い実務タスクをうまくこなします。
- OCR と文字起こし — 印刷されたテキスト、そして驚くほど まともな手書き文字。維持すべき Tesseract のパイプラインはありません。
- チャートとダッシュボード — 棒グラフ / 折れ線グラフから 数値を読み取る、トレンドを要約する、スクリーンショット内の指標を ざっと検算する。
- 構造化抽出 — レシート、請求書、フォーム、身分証を JSON に。プロンプトに厳密なスキーマを添えれば、きれいな出力が得られます。
- UI と図の理解 — 画面を説明する、エラーダイアログを 読む、アーキテクチャ図を解説する。
そして正直な限界もあります。モデルは依然としてときどき1 桁の 数字や密な表のセルを読み違えます。なので、数字を間違えると 高くつくものについては、スキーマやチェックサムで検証してください(例: 明細の合計が記載の総額と一致するか)。低解像度の画像内の小さな文字が 最もよくある失敗です — より高解像度の切り抜きを与えてください。そして モデルごとの挙動は本当に異なります。あるモデルが完璧に決めるレイアウトを、 別のモデルがつまずくこともあり、だからこそ 1 つの API の裏でモデルを差し替え られて、自分自身の文書で A/B テストできることは、どんな単一のベンチマーク よりも価値があるのです。
さらに先へ: ビジョンとツール
ビジョンは API の他の機能と組み合わせられます。モデルに画像 とツール一式を渡せば、スクリーンショットを読んでから、抽出した 内容で関数を呼び出せます —「この請求書を読んで、それから create_expense(amount, vendor, date) を呼べ」のように。 このツール呼び出しの層もまた、Brievio を通せば Claude と Gemini で 統一されています。共通の形については ツール利用ガイド が解説しています。ビジョンと組み合わせれば、1 つのリクエストで ドキュメント処理パイプラインのほぼ全体になります。
まとめ
画像理解のために、別個の OCR サービスやプロバイダー固有の SDK は要りません。 通常のチャットリクエストに image_url パート — URL でも base64 データ URL でも — を添付し、複数画像にラベルを付けてモデルが 引用できるようにし、タスクに合うモデルへルーティングするだけです。 大量の安価な読み取りには Gemini Flash、難しい文書には Claude Opus。 画像が入力トークンとして課金されること(usage に正直に 表示されます)を忘れず、解像度を妥当に保ち、抽出した数字を検証し、 大きなスキャンが弾かれたら失敗呼び出し無料の再試行に頼ってください。 完全なリクエストリファレンスとモデルごとの上限は ドキュメントにあります — そこから始めれば、 Claude や Gemini に文書を流し込めるようになるのは午後のうちです。