マルチモーダル入力とは
Claude は テキストだけでなく、画像や PDF といった視覚的なコンテンツも理解できます。これが「マルチモーダル入力」です。写真の内容を説明させたり、グラフを分析させたり、PDF レポートから情報を抽出したりと、テキストだけでは不可能だったタスクを API 経由で実行できます。
ℹ️ マルチモーダル入力で可能になること:
- 画像の内容認識・分析・説明
- PDF 文書のテキスト&視覚要素の解析
- グラフ・チャート・表の読み取り
- 複数画像の比較・対照
- ドキュメントからの構造化データ抽出
画像入力の基本
Claude は JPEG、PNG、GIF、WebP の 4 つの画像フォーマットをサポートしています。画像を API に送信するには 3 つの方法があります。
方法 1: Base64 エンコード
画像をローカルファイルから読み込み、Base64 に変換して送信する最も基本的な方法です。
import anthropic
import base64
# ローカル画像を読み込んで Base64 エンコード
with open ( "photo.jpg" , "rb" ) as f:
image_data = base64.standard_b64encode(f.read()).decode( "utf-8" )
client = anthropic.Anthropic()
message = client.messages.create(
model = "claude-sonnet-4-6" ,
max_tokens = 1024 ,
messages = [
{
"role" : "user" ,
"content" : [
{
"type" : "image" ,
"source" : {
"type" : "base64" ,
"media_type" : "image/jpeg" ,
"data" : image_data,
},
},
{ "type" : "text" , "text" : "この画像に何が写っていますか?" },
],
}
],
)
print (message.content[ 0 ].text)
TypeScript での実装:
import Anthropic from "@anthropic-ai/sdk" ;
import fs from "fs" ;
const client = new Anthropic ();
const imageData = fs. readFileSync ( "photo.jpg" ). toString ( "base64" );
const message = await client.messages. create ({
model: "claude-sonnet-4-6" ,
max_tokens: 1024 ,
messages: [
{
role: "user" ,
content: [
{
type: "image" ,
source: {
type: "base64" ,
media_type: "image/jpeg" ,
data: imageData,
},
},
{ type: "text" , text: "この画像に何が写っていますか?" },
],
},
],
});
方法 2: URL 指定
オンラインでホストされている画像を URL で直接指定できます。Base64 変換が不要なため、最もシンプルです。
import anthropic
client = anthropic.Anthropic()
message = client.messages.create(
model = "claude-sonnet-4-6" ,
max_tokens = 1024 ,
messages = [
{
"role" : "user" ,
"content" : [
{
"type" : "image" ,
"source" : {
"type" : "url" ,
"url" : "https://example.com/chart.png" ,
},
},
{ "type" : "text" , "text" : "このグラフのトレンドを分析してください。" },
],
}
],
)
方法 3: Files API
何度も使う画像は Files API で一度アップロードし、file_id で参照する方法が効率的です。マルチターン会話では特に有効で、毎回 Base64 データを再送信する必要がなくなります。
import anthropic
client = anthropic.Anthropic()
# 画像をアップロード
with open ( "photo.jpg" , "rb" ) as f:
file = client.beta.files.upload(
file = ( "photo.jpg" , f, "image/jpeg" )
)
# file_id で参照
message = client.beta.messages.create(
model = "claude-sonnet-4-6" ,
max_tokens = 1024 ,
betas = [ "files-api-2025-04-14" ],
messages = [
{
"role" : "user" ,
"content" : [
{
"type" : "image" ,
"source" : { "type" : "file" , "file_id" : file .id},
},
{ "type" : "text" , "text" : "この画像を説明してください。" },
],
}
],
)
💡 Files API はベータ版です。リクエストヘッダーに `anthropic-beta: files-api-2025-04-14` を含める必要があります。
画像のサイズと制限
画像を送信する際のサイズ制限と最適化について理解しておきましょう。
項目 制限
最大ファイルサイズ (API) 5 MB
最大ファイルサイズ (claude.ai) 10 MB
最大画像数 (API) 100 枚/リクエスト
最大画像数 (claude.ai) 20 枚/ターン
最大ピクセル 8000 x 8000 px
サポート形式 JPEG, PNG, GIF, WebP
トークンコストの計算
画像のトークン数は以下の式で概算できます:
トークン数 ≈ (幅 px × 高さ px) / 750
たとえば 1000 x 1000 px の画像は約 1,334 トークンを消費します。Claude Opus 4.6 の入力トークン単価 ($3/100万トークン) で計算すると、1 枚あたり約 $0.004 です。
画像サイズの最適化
長辺が 1568 px を超える画像は自動的にリサイズされます。リサイズは time-to-first-token の遅延を増やすだけで、モデルの性能は向上しません。事前にリサイズしておくことを推奨します。
from PIL import Image
def optimize_for_claude (image_path, max_edge = 1568 ):
"""Claude API 向けに画像をリサイズ"""
img = Image.open(image_path)
width, height = img.size
if max (width, height) > max_edge:
ratio = max_edge / max (width, height)
new_size = ( int (width * ratio), int (height * ratio))
img = img.resize(new_size, Image. LANCZOS )
img.save(image_path, quality = 85 )
print ( f "リサイズ: { width } x { height } → { new_size[ 0 ] } x { new_size[ 1 ] } " )
return img
複数画像の送信
1 回のリクエストで複数の画像を送信し、比較分析を行うことができます。
import anthropic
client = anthropic.Anthropic()
message = client.messages.create(
model = "claude-sonnet-4-6" ,
max_tokens = 1024 ,
messages = [
{
"role" : "user" ,
"content" : [
{ "type" : "text" , "text" : "画像 1:" },
{
"type" : "image" ,
"source" : {
"type" : "url" ,
"url" : "https://example.com/before.jpg" ,
},
},
{ "type" : "text" , "text" : "画像 2:" },
{
"type" : "image" ,
"source" : {
"type" : "url" ,
"url" : "https://example.com/after.jpg" ,
},
},
{ "type" : "text" , "text" : "2 つの画像の違いを説明してください。" },
],
}
],
)
💡 画像はプロンプトのテキストよりも前に配置すると、最適な結果が得られます。Claude は画像→テキストの順序で処理するのが最も得意です。
PDF 入力
Claude は PDF ドキュメントのテキストと視覚要素(チャート、図表、レイアウト)の両方を理解できます。
PDF の制限
項目 制限
最大リクエストサイズ 32 MB
最大ページ数 100 ページ/リクエスト
対応形式 標準 PDF(パスワード保護なし)
PDF を URL で送信
import anthropic
client = anthropic.Anthropic()
message = client.messages.create(
model = "claude-sonnet-4-6" ,
max_tokens = 1024 ,
messages = [
{
"role" : "user" ,
"content" : [
{
"type" : "document" ,
"source" : {
"type" : "url" ,
"url" : "https://example.com/report.pdf" ,
},
},
{ "type" : "text" , "text" : "このレポートの主要な発見を要約してください。" },
],
}
],
)
PDF を Base64 で送信
ローカルの PDF ファイルを送信する場合:
import anthropic
import base64
# PDF を読み込んで Base64 エンコード
with open ( "report.pdf" , "rb" ) as f:
pdf_data = base64.standard_b64encode(f.read()).decode( "utf-8" )
client = anthropic.Anthropic()
message = client.messages.create(
model = "claude-sonnet-4-6" ,
max_tokens = 1024 ,
messages = [
{
"role" : "user" ,
"content" : [
{
"type" : "document" ,
"source" : {
"type" : "base64" ,
"media_type" : "application/pdf" ,
"data" : pdf_data,
},
},
{ "type" : "text" , "text" : "この PDF の内容を分析してください。" },
],
}
],
)
PDF を Files API で送信
import anthropic
client = anthropic.Anthropic()
# PDF をアップロード
with open ( "report.pdf" , "rb" ) as f:
file = client.beta.files.upload(
file = ( "report.pdf" , f, "application/pdf" )
)
# file_id で参照
message = client.beta.messages.create(
model = "claude-sonnet-4-6" ,
max_tokens = 1024 ,
betas = [ "files-api-2025-04-14" ],
messages = [
{
"role" : "user" ,
"content" : [
{
"type" : "document" ,
"source" : { "type" : "file" , "file_id" : file .id},
},
{ "type" : "text" , "text" : "主要なポイントを箇条書きで教えてください。" },
],
}
],
)
PDF の処理の仕組み
Claude が PDF を処理する際、内部では以下のステップが実行されます:
ページの画像変換 — 各ページが画像としてレンダリングされます
テキスト抽出 — 各ページからテキストが抽出され、画像と一緒に提供されます
マルチモーダル分析 — Claude がテキストと画像の両方を分析して回答を生成します
このため、PDF のトークンコストはテキスト分とページ画像分の両方を含みます。1 ページあたり約 1,500〜3,000 トークン(テキスト密度に依存)+画像トークンが必要です。
Files API の活用
Files API はマルチモーダル入力を効率化するための重要なツールです。
ファイルのライフサイクル
import anthropic
client = anthropic.Anthropic()
# 1. アップロード
with open ( "document.pdf" , "rb" ) as f:
file = client.beta.files.upload(
file = ( "document.pdf" , f, "application/pdf" )
)
print ( f "ファイル ID: { file .id } " )
# 2. メタデータ取得
metadata = client.beta.files.retrieve_metadata( file .id)
print ( f "ファイル名: { metadata.filename } " )
print ( f "サイズ: { metadata.size_bytes } bytes" )
# 3. 一覧表示
files = client.beta.files.list()
for f in files.data:
print ( f " { f.id } : { f.filename } " )
# 4. 削除
client.beta.files.delete( file .id)
Files API の利点
リクエストサイズの削減 : Base64 データの代わりに短い file_id を送信
マルチターン会話の最適化 : 会話が長くなっても、画像データが毎ターン再送信されない
再利用性 : 同じファイルを複数のリクエストで使い回せる
ストレージ制限
項目 制限
最大ファイルサイズ 500 MB
組織あたりの合計ストレージ 100 GB
実践的なユースケース
レシート・請求書の自動処理
import anthropic
import json
client = anthropic.Anthropic()
message = client.messages.create(
model = "claude-sonnet-4-6" ,
max_tokens = 1024 ,
messages = [
{
"role" : "user" ,
"content" : [
{
"type" : "image" ,
"source" : {
"type" : "base64" ,
"media_type" : "image/jpeg" ,
"data" : receipt_image_data, # Base64 エンコードされたレシート画像
},
},
{
"type" : "text" ,
"text" : """このレシートから以下の情報を JSON で抽出してください:
- store_name: 店名
- date: 日付
- items: 商品名と価格のリスト
- total: 合計金額
- tax: 消費税額""" ,
},
],
}
],
)
result = json.loads(message.content[ 0 ].text)
技術文書のレビュー
import anthropic
client = anthropic.Anthropic()
message = client.messages.create(
model = "claude-opus-4-6" ,
max_tokens = 4096 ,
messages = [
{
"role" : "user" ,
"content" : [
{
"type" : "document" ,
"source" : {
"type" : "url" ,
"url" : "https://example.com/api-spec.pdf" ,
},
},
{
"type" : "text" ,
"text" : """この API 仕様書をレビューしてください。以下の観点でフィードバックをお願いします:
1. エンドポイント設計の一貫性
2. エラーハンドリングの網羅性
3. セキュリティ上の懸念
4. ドキュメントの明確さ""" ,
},
],
}
],
)
複数 PDF のバッチ処理
大量の PDF を処理する場合、Message Batches API を活用できます:
import anthropic
import base64
client = anthropic.Anthropic()
# 複数の PDF からバッチリクエストを構築
requests = []
for i, pdf_path in enumerate ([ "doc1.pdf" , "doc2.pdf" , "doc3.pdf" ]):
with open (pdf_path, "rb" ) as f:
pdf_data = base64.standard_b64encode(f.read()).decode( "utf-8" )
requests.append({
"custom_id" : f "doc- { i } " ,
"params" : {
"model" : "claude-sonnet-4-6" ,
"max_tokens" : 2048 ,
"messages" : [
{
"role" : "user" ,
"content" : [
{
"type" : "document" ,
"source" : {
"type" : "base64" ,
"media_type" : "application/pdf" ,
"data" : pdf_data,
},
},
{ "type" : "text" , "text" : "この文書を 200 文字以内で要約してください。" },
],
}
],
},
})
# バッチ作成
batch = client.messages.batches.create( requests = requests)
print ( f "バッチ ID: { batch.id } " )
プロンプトキャッシングとの併用
PDF を繰り返し分析する場合、プロンプトキャッシングで大幅にコストを削減できます:
import anthropic
client = anthropic.Anthropic()
# キャッシュ付きで PDF を送信
message = client.messages.create(
model = "claude-sonnet-4-6" ,
max_tokens = 1024 ,
messages = [
{
"role" : "user" ,
"content" : [
{
"type" : "document" ,
"source" : {
"type" : "base64" ,
"media_type" : "application/pdf" ,
"data" : pdf_data,
},
"cache_control" : { "type" : "ephemeral" },
},
{ "type" : "text" , "text" : "売上の傾向を分析してください。" },
],
}
],
)
キャッシュされた PDF に対して追加の質問を送信する際、キャッシュヒットすればトークンコストが大幅に削減されます。
公式ドキュメントには書かれていない、運用で気づいたこと
ここまでは API の使い方を順に整理してきました。ここからは、私自身が個人開発の現場で画像・PDF 入力を回してみて、公式の説明だけでは見えてこなかった点をお伝えします。
私は壁紙アプリを運用していて、追加する画像を色調や被写体でカテゴリ分けする作業を、長らく手作業でこなしていました。数が増えるにつれて手が回らなくなり、サムネイルを Claude に渡して分類させる仕組みへ切り替えたのですが、そこで最初につまずいたのが「送る前のリサイズ」でした。
リサイズは精度ではなく、体感速度のために効く
長辺が 1568 px を超える画像は、API 側で自動的にリサイズされます。公式には「性能は上がらない」とだけ書かれていますが、実際に効いてくるのは初回応答までの時間(time-to-first-token)です。
手元で 4032 × 3024 px のスマホ写真をそのまま送ったときと、1568 px に縮小してから送ったときを比べると、初応答までがおよそ 2.3 秒から 0.9 秒へと縮みました。1 枚ずつ短時間で捌きたい分類のような用途では、この 1 秒あまりの差が数百枚分積み重なって効いてきます。
送信前に自前で縮小しておくと、アップロードのペイロードそのものも小さくなり、往復が軽くなります。前掲の optimize_for_claude を分類ジョブの前段に挟んでからは、1 バッチ(サムネイル 300 枚)の総処理時間が体感で 3 割ほど短くなりました。精度は変わりません。あくまで速度と費用の話です。
PDF は「文字が読める PDF」かどうかで費用が変わる
PDF のトークンは、テキスト分とページ画像分の両方を含みます。ここで見落としがちなのが、スキャンして画像化しただけの PDF です。文字情報を持たないため、テキスト抽出がほとんど効かず、ページ画像のトークンだけが嵩みます。
手元の実測では、文字ベースの 30 ページ資料が概ね 4.5 万トークン前後だったのに対し、同じページ数のスキャン PDF は 9 万トークン近くまで膨らみました。ほぼ倍です。請求書や古い仕様書のようにスキャン由来の PDF を扱うときは、この差を見込んで max_tokens と予算を組む必要があります。文字が選択できる PDF かどうか、送る前に一度確かめておくと安心です。
media_type の取り違えは、静かに 400 を返す
意外と多いのが media_type の指定ミスです。JPEG のデータを image/png と申告しても、多くの場合エラーメッセージは素っ気ない 400 で返ってきて、原因にたどり着くまで少し時間を取られます。拡張子と中身が食い違っているファイル(.jpg なのに実体は PNG、など)を機械的に処理していると、ここで詰まりがちです。私はこの取り違えを避けるため、送信前に Pillow で実フォーマットを判定し、そこから media_type を決める一手間を必ず挟むようにしています。
from PIL import Image
_MEDIA = { "JPEG" : "image/jpeg" , "PNG" : "image/png" , "GIF" : "image/gif" , "WEBP" : "image/webp" }
def detect_media_type (path: str ) -> str :
"""拡張子ではなく実体から media_type を決める"""
with Image.open(path) as img:
fmt = img.format # "JPEG" / "PNG" など
if fmt not in _MEDIA :
raise ValueError ( f "未対応の画像形式です: { fmt } " )
return _MEDIA [fmt]
Files API は、マルチターンで初めて元が取れる
Files API は万能ではありません。単発のリクエストなら、Base64 直送と体感差はほとんどありません。効いてくるのは、同じ画像を何度も参照するマルチターン会話です。
私の分類フローでは、当初 20 枚ほどのサムネイルを毎ターン Base64 で再送していました。会話が 5 往復も続くと、同じ画像データを 5 回送り直していることになります。これを一度アップロードして file_id 参照に切り替えたところ、2 ターン目以降のリクエストのペイロードが目に見えて小さくなり、往復のたびに感じていたもたつきが解消されました。逆に、一度きりの解析で使い捨てるなら、アップロードと削除の手間の分だけ Base64 のほうが素直です。使いどころを見極めるのが肝心だと感じています。
ベストプラクティス
画像入力のコツ
画像はテキストの前に配置する : Claude は画像→テキストの順序で最もよく機能します
事前にリサイズする : 1568 px 以下に最適化して遅延を減らす
高品質な画像を使う : ぼやけた画像や 200 px 未満の画像は精度が低下する
複数画像にはラベルを付ける : 「画像 1:」「画像 2:」のように明示する
PDF 入力のコツ
PDF はテキストの前に配置する : 画像と同様、先に読ませるのが効果的
標準フォントを使用する : 特殊フォントは認識精度が下がる可能性がある
ページの向きを正しくする : 回転した PDF は精度が低下する
大きな PDF は分割する : 100 ページを超える場合はチャンクに分割
コスト最適化
Files API を活用する : マルチターン会話では特に効果的
プロンプトキャッシングを使う : 同じドキュメントへの繰り返しクエリ
バッチ処理を活用する : 大量ドキュメントの処理に最適
不要な画像を送らない : リクエストに必要な画像だけを含める
制限事項と注意点
人物識別は不可 : Claude は画像内の人物を特定(名前を当てる)ことはできません
空間推論に制約 : 正確な位置関係やレイアウトの把握は苦手です
カウントは概算 : 大量の小さいオブジェクトの正確な数え上げは困難です
AI 生成画像の判別不可 : 画像が AI 生成かどうかの判断はできません
医療画像は非対応 : CT や MRI の診断利用は推奨されません
画像や PDF の入力は、一度仕組みに落とし込めば、これまで手作業でこなしていた地味な確認や仕分けを静かに肩代わりしてくれます。同じように個人開発で試している方の一助になれば幸いです。