多模態輸入:圖片、PDF 與文件處理
本篇是「Claude API & Agent SDK 完全指南」系列的第 6 / 15 篇。你可以從系列總覽開始閱讀,也可以直接接著看本文。
前幾章我們把 Claude 當純文字模型來用:送進去的是文字,出來的也是文字。但 Claude 的能力遠不止於此。
從 Claude 3 Sonnet 開始,Claude 就是一個真正的多模態模型(multimodal model)。你可以送圖片進去,Claude 看得懂。你可以丟 PDF,Claude 讀得了。你可以同時傳五張截圖,Claude 可以跨圖分析。
這一章我要帶你搞清楚多模態輸入的完整用法,包括技術細節、成本考量,以及我在生產環境中真正使用的做法。
什麼是多模態(Multimodal)?
所謂「多模態」,就是模型能處理不同種類的輸入,而不僅限於文字。
對 Claude 來說,目前支援的輸入模態是:
- 文字(一直支援)
- 圖片(JPEG、PNG、GIF、WebP)
- PDF 文件
值得注意的是,截至 2026 年,Claude 不支援影片輸入。你沒辦法把 mp4 傳給 Claude 分析。如果你的使用場景需要影片分析,目前的做法是把影片截成一系列關鍵幀圖片,再批次傳入——這個方法雖然繁瑣,但可行。
圖片輸入的兩種方式
Claude API 接受圖片的方式有兩種:base64 編碼和URL 直接引用。兩種方式各有適用場景。
方式一:Base64 編碼
把圖片轉成 base64 字串,直接嵌入 API 請求裡。
適合:
- 圖片存在本地(不需要先上傳到某個地方)
- 圖片是動態生成的(例如截圖)
- 你希望請求完全自包含,不依賴外部 URL
缺點:
- base64 會讓 payload 體積增大約 33%
- 長圖片會讓請求 JSON 變得很龐大
import anthropic
import base64
from pathlib import Path
client = anthropic.Anthropic()
# 讀取圖片並轉換為 base64
image_path = Path("screenshot.png")
image_data = base64.standard_b64encode(image_path.read_bytes()).decode("utf-8")
message = client.messages.create(
model="claude-opus-4-5",
max_tokens=1024,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png", # 必須正確指定
"data": image_data,
},
},
{
"type": "text",
"text": "這張截圖裡有什麼錯誤訊息?請詳細說明問題所在。"
}
],
}
],
)
print(message.content[0].text)
media_type 的值必須與實際圖片格式對應:
image/jpegimage/pngimage/gifimage/webp
方式二:URL 直接引用
如果圖片已經有一個公開可訪問的 URL,可以直接傳 URL,讓 Claude 自己去抓。
message = client.messages.create(
model="claude-opus-4-5",
max_tokens=1024,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "url",
"url": "https://example.com/chart.png",
},
},
{
"type": "text",
"text": "這張圖表顯示了什麼趨勢?"
}
],
}
],
)
URL 方式的限制:
- URL 必須是公開可訪問的(Claude 伺服器要能下載到)
- 不支援需要認證的 URL(例如需要登入的 S3 bucket)
- 不支援本地網路 URL
我在生產環境的習慣是:如果圖片已經在公開 CDN 上,用 URL;如果是用戶上傳的動態圖片或本地生成的,用 base64。
圖片大小與 Token 計算
這裡有個很多人忽略的重點:圖片會消耗 token,而且消耗量與圖片大小成正比。
Claude 在處理圖片時,內部會把圖片切分成 tiles(磁磚),每個 tile 大約消耗 1500-1600 個 token。
計算規則:
- 圖片先會縮放到最長邊不超過 1568px
- 縮放後,每個 512x512 的 tile 消耗約 1600 tokens
- 還有一個固定的基礎成本(base cost)約 2500 tokens
舉個例子:一張 1000x1000 的圖片,大約消耗 4000-5000 tokens。
實際影響:如果你的應用需要同時傳多張圖片,token 成本會快速累積。以 Claude Opus 4.5 為例,1000 tokens 輸入大約 $0.015。一張中等大小的圖片就可能消耗 $0.05-0.10。
我的建議:在傳圖片前先對圖片做壓縮。對截圖類的分析任務,把圖片壓到 800x600 以下通常不影響分析品質,但可以省下 50% 以上的 token。
from PIL import Image
import io
def compress_image_for_api(image_path: str, max_size: int = 1000) -> tuple[bytes, str]:
"""壓縮圖片以降低 token 消耗,同時保留分析品質"""
img = Image.open(image_path)
# 計算縮放比例,長邊不超過 max_size
ratio = min(max_size / img.width, max_size / img.height, 1.0)
if ratio < 1.0:
new_size = (int(img.width * ratio), int(img.height * ratio))
img = img.resize(new_size, Image.LANCZOS)
# 轉換為 JPEG(通常比 PNG 小很多)
output = io.BytesIO()
img.convert("RGB").save(output, format="JPEG", quality=85)
return output.getvalue(), "image/jpeg"
PDF 文件上傳與分析
PDF 支援是 Claude 相當強大的功能之一。你可以直接把 PDF 丟給 Claude,它能讀懂裡面的文字、表格,甚至是掃描版 PDF(帶有圖片的頁面)。
PDF 的傳入方式和圖片一樣,支援 base64 和 URL 兩種:
import anthropic
import base64
from pathlib import Path
client = anthropic.Anthropic()
# 讀取 PDF 並轉換為 base64
pdf_path = Path("contract.pdf")
pdf_data = base64.standard_b64encode(pdf_path.read_bytes()).decode("utf-8")
message = client.messages.create(
model="claude-opus-4-5",
max_tokens=2048,
messages=[
{
"role": "user",
"content": [
{
"type": "document",
"source": {
"type": "base64",
"media_type": "application/pdf",
"data": pdf_data,
},
},
{
"type": "text",
"text": "請摘要這份合約的主要條款,特別是付款條件和違約責任。"
}
],
}
],
)
print(message.content[0].text)
注意幾個細節:
- PDF 用的是
type: "document"而不是type: "image" media_type是application/pdf- PDF 的 token 消耗基本上跟文字提取後的文字量成正比,掃描版 PDF(全圖片)會比文字版 PDF 貴很多
PDF 分析的限制
Claude 在處理 PDF 時有幾個需要知道的限制:
- 頁數限制:目前 Claude 能處理的 PDF 上限大約是 100 頁,超過的頁面會被截斷
- 檔案大小:單個 PDF 不超過 32MB(base64 之前的原始大小)
- 掃描版 PDF:能讀,但品質取決於掃描品質;低解析度的掃描文件可能識別率不佳
- 加密 PDF:無法處理密碼保護的 PDF
TypeScript 範例
前面的例子都是 Python,但我知道很多人用 TypeScript 開發應用。這裡給一個完整的 TypeScript 範例:
import Anthropic from '@anthropic-ai/sdk';
import * as fs from 'fs';
import * as path from 'path';
const client = new Anthropic();
async function analyzeImageWithClaude(imagePath: string): Promise<string> {
const imageBuffer = fs.readFileSync(imagePath);
const base64Image = imageBuffer.toString('base64');
// 根據副檔名決定 media_type
const ext = path.extname(imagePath).toLowerCase();
const mediaTypeMap: Record<string, string> = {
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.png': 'image/png',
'.gif': 'image/gif',
'.webp': 'image/webp',
};
const mediaType = mediaTypeMap[ext] ?? 'image/jpeg';
const message = await client.messages.create({
model: 'claude-opus-4-5',
max_tokens: 1024,
messages: [
{
role: 'user',
content: [
{
type: 'image',
source: {
type: 'base64',
media_type: mediaType as 'image/jpeg' | 'image/png' | 'image/gif' | 'image/webp',
data: base64Image,
},
},
{
type: 'text',
text: '請描述這張圖片的內容,並指出任何值得注意的細節。',
},
],
},
],
});
return (message.content[0] as { type: 'text'; text: string }).text;
}
async function analyzePdfWithClaude(pdfPath: string): Promise<string> {
const pdfBuffer = fs.readFileSync(pdfPath);
const base64Pdf = pdfBuffer.toString('base64');
const message = await client.messages.create({
model: 'claude-opus-4-5',
max_tokens: 2048,
messages: [
{
role: 'user',
content: [
{
type: 'document',
source: {
type: 'base64',
media_type: 'application/pdf',
data: base64Pdf,
},
},
{
type: 'text',
text: '請摘要這份文件的主要內容。',
},
],
},
],
});
return (message.content[0] as { type: 'text'; text: string }).text;
}
// 使用範例
(async () => {
const imageAnalysis = await analyzeImageWithClaude('screenshot.png');
console.log('圖片分析結果:', imageAnalysis);
const pdfAnalysis = await analyzePdfWithClaude('report.pdf');
console.log('PDF 分析結果:', pdfAnalysis);
})();
多張圖片同時分析
Claude 支援在單次請求裡傳入多張圖片。這個功能在某些場景非常有用,例如:
- 比較兩個設計稿的差異
- 分析一系列截圖找出 bug
- 從多張商品圖片生成描述
import anthropic
import base64
from pathlib import Path
client = anthropic.Anthropic()
def load_image_as_base64(path: str) -> dict:
"""輔助函式:載入圖片並轉換為 API 格式"""
img_path = Path(path)
img_data = base64.standard_b64encode(img_path.read_bytes()).decode("utf-8")
ext_to_media_type = {
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".png": "image/png",
".gif": "image/gif",
".webp": "image/webp",
}
media_type = ext_to_media_type.get(img_path.suffix.lower(), "image/jpeg")
return {
"type": "image",
"source": {
"type": "base64",
"media_type": media_type,
"data": img_data,
}
}
# 同時分析三張截圖
screenshots = ["before.png", "after.png", "error.png"]
content = []
for i, screenshot in enumerate(screenshots):
content.append(load_image_as_base64(screenshot))
content.append({
"type": "text",
"text": f"[圖片 {i+1}: {screenshot}]"
})
content.append({
"type": "text",
"text": "以上三張截圖分別是:before(操作前)、after(操作後)、error(出現的錯誤)。請分析這個問題,找出 before 和 after 的差異,解釋錯誤可能的原因。"
})
message = client.messages.create(
model="claude-opus-4-5",
max_tokens=2048,
messages=[
{"role": "user", "content": content}
],
)
print(message.content[0].text)
實際應用場景
讓我分享幾個我在實際專案中用過的多模態應用場景:
截圖分析(Error Analysis)
這是我用得最多的場景。當使用者遇到錯誤時,讓他們截圖上傳,比手打錯誤訊息準確得多:
def analyze_error_screenshot(screenshot_base64: str) -> dict:
"""分析錯誤截圖,返回診斷結果和解決建議"""
message = client.messages.create(
model="claude-opus-4-5",
max_tokens=1024,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": screenshot_base64,
},
},
{
"type": "text",
"text": """你是一位技術支援工程師。請分析這張錯誤截圖:
1. 描述錯誤訊息的確切內容
2. 判斷錯誤的可能原因(列出 2-3 個)
3. 提供解決步驟(按優先順序排列)
請用繁體中文回答,格式清晰。"""
}
],
}
],
)
return {"analysis": message.content[0].text}
文件 OCR 與結構提取
掃描版合約或表單的結構化資料提取:
def extract_invoice_data(invoice_image_base64: str) -> dict:
"""從發票圖片提取結構化資料"""
message = client.messages.create(
model="claude-opus-4-5",
max_tokens=1024,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/jpeg",
"data": invoice_image_base64,
},
},
{
"type": "text",
"text": """請從這張發票圖片中提取以下資訊,以 JSON 格式回答:
{
"invoice_number": "發票號碼",
"date": "日期(YYYY-MM-DD)",
"vendor": "廠商名稱",
"total_amount": "總金額(數字)",
"currency": "幣別",
"items": [
{"description": "品項說明", "quantity": 數量, "unit_price": 單價, "amount": 金額}
]
}
只回答 JSON,不要其他文字。"""
}
],
}
],
)
import json
return json.loads(message.content[0].text)
設計評審
我在開發流程裡加入 Claude 做自動化設計審查:
def review_design_mockup(design_image_base64: str, design_brief: str) -> str:
"""根據設計簡報評審 UI mockup"""
message = client.messages.create(
model="claude-opus-4-5",
max_tokens=2048,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": design_image_base64,
},
},
{
"type": "text",
"text": f"""你是一位資深 UX 設計師。
設計簡報:
{design_brief}
請針對這個 UI mockup 提供專業意見:
1. 是否符合設計簡報的需求?
2. 可用性問題(如果有)
3. 視覺層次是否清晰?
4. 改進建議(最多三點,按重要性排序)"""
}
],
}
],
)
return message.content[0].text
Prompt 技巧:讓圖片分析更準確
幾個我實測有效的技巧:
1. 明確說明圖片的上下文
不要只說「分析這張圖片」,要告訴 Claude 這是什麼類型的圖片、你想知道什麼:
❌ 差:「請分析這張圖片。」
✅ 好:「這是一個 React 應用程式的截圖,頁面上出現了一個錯誤訊息。請識別錯誤訊息的完整內容,並推測可能的原因。」
2. 對多圖片請求,為每張圖片加標籤
在圖片之後加一個文字說明,讓 Claude 知道每張圖的角色:
content = [
image_1_block,
{"type": "text", "text": "[圖1: 設計稿 - 手機版]"},
image_2_block,
{"type": "text", "text": "[圖2: 設計稿 - 桌機版]"},
{"type": "text", "text": "請比較這兩個版本的設計一致性..."}
]
3. 要求結構化輸出
對需要從圖片提取資訊的任務,要求 JSON 格式輸出,方便後續處理:
"請從這張報表截圖中提取所有數據,以 JSON 格式回答,不要其他說明文字。"
4. 分步驟引導複雜分析
對複雜的圖片分析任務,分步驟引導比一次性提問效果更好:
# Step 1: 描述
message1 = "首先,請描述你在這張架構圖中看到的所有元件和連接關係。"
# Step 2: 分析(帶入 step 1 的結果)
message2 = f"根據你的描述:{description}\n現在請分析這個架構有哪些潛在的單點故障(SPOF)。"
影像品質 vs Token 成本的 Tradeoff
我來給你一個實際的對比數據,讓你在專案中做出有依據的決策:
| 圖片尺寸 | 大約 Token 消耗 | Claude Opus 4.5 成本 |
|---|---|---|
| 300x300 | ~1,000 tokens | ~$0.015 |
| 800x600 | ~3,000 tokens | ~$0.045 |
| 1200x900 | ~5,500 tokens | ~$0.083 |
| 1920x1080 | ~8,000 tokens | ~$0.120 |
對大多數截圖分析任務,800x600 的解析度已經足夠。把圖片壓縮到這個尺寸,可以在不影響分析品質的前提下,省下 60% 以上的圖片相關 token 費用。
我的實踐原則:
- 文字識別(OCR 類任務):至少 150 DPI,文字要清晰可辨
- 圖表分析:800px 寬度通常足夠
- UI 截圖分析:直接原始尺寸,UI 細節很重要
- 設計評審:直接原始尺寸,保留細節
多模態輸入讓 Claude 從「聊天機器人」變成真正能處理真實世界資料的助手。圖片和 PDF 的支援打開了大量原本無法自動化的使用場景。
不過,多模態請求的 token 消耗也比純文字請求高出不少。在下一章,我們來聊一個能大幅降低 API 成本的技術:Prompt Caching。如果你的應用有固定的 system prompt 或長文件,一個好的快取策略可以讓成本直接砍半。