Vision 與 PDF
把圖片跟整份 PDF 直接餵給 Claude——image block、document block 結構,跟「截圖 debug、發票抽欄位、合約摘要」三大應用場景。
TL;DR
- 圖:
imagecontent block,base64 或 URL,每張 ≤ 5MB;單張最大 8000×8000、多張最大 2000×2000;單個 request 最多約 100 張 - PDF:
documentcontent block,原生支援版面+內嵌圖+表格——不用先 OCR - 大原則:跟 text 一樣靠 prompt engineering 才會準——「這張圖有幾顆球」這種懶問法常常數錯
一個情境:客服信附了一張截圖
User 寄客服信:「我的帳單怎麼算的?」附了一張對帳單截圖——上面有金額、明細、日期。
不能 vision 的時候你只能:請 user 把表格 retype、或叫 OCR 服務先轉文字、再丟 LLM。每一步都會丟資訊(OCR 認錯數字、版面亂掉)。
Vision 直接讓你把截圖當成另一種 input block 塞進 user message:model 自己讀圖、自己解析欄位。發票、合約、儀表板截圖、設計稿都是同一條路。
Image content block 結構
User message 的 content 變成 list,每個 element 是一個 block:
import base64
with open("invoice.png", "rb") as f:
img_b64 = base64.standard_b64encode(f.read()).decode("utf-8")
messages = [{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": img_b64,
},
},
{"type": "text", "text": "把這張發票的金額、日期、品項抽成 JSON。"},
],
}]
兩種 source type:
# 1. base64(檔案在本地)
{"type": "base64", "media_type": "image/png", "data": "<b64>"}
# 2. URL(圖片在 public CDN)
{"type": "url", "url": "https://example.com/invoice.png"}
支援格式:PNG、JPEG、GIF、WEBP。
圖的規格限制
| 限制 | 數值 |
|---|---|
| 每張大小 | ≤ 5 MB |
| 單個 request 最多張數 | ~100 |
| 單張時最大解析度 | 8000 × 8000 px |
| 多張時最大解析度 | 2000 × 2000 px |
| Token 計算(粗估) | (width × height) / 750 |
最後那條公式可以拿來估帳單——一張 1000×1000 的圖約 1333 tokens。多張、解析度高的 request 很快就燒完 input budget。
拍圖的 prompt 也要好好寫
新手 vision 第一次的反射動作:
{"type": "text", "text": "圖裡有幾顆彈珠?"}
12 顆的圖常常回答「13」「14」⋯⋯。不是 vision 不行,是你 prompt 太懶。
跟文字 prompt 一樣的招式都管用——給步驟、給範例、拆任務:
請依下列步驟分析這張彈珠圖:
1. 先用「左到右、上到下」的方式逐顆編號數
2. 用另一種策略再數一次(例如分群、按顏色)
3. 兩次數字若不同,重新對照圖確認
4. 最終答案以 <answer>數字</answer> 包起來
實測 vision 任務裡,有沒有給「verify 步驟」差很多。model 第一次數錯不會自己回頭看,但你叫它再數一次它會改。
真實場景:發票抽欄位
{"type": "text", "text": """
從這張發票抽欄位,回 JSON:
{"vendor": str, "date": "YYYY-MM-DD", "total": float, "items": [{"name": str, "qty": int, "price": float}]}
如果欄位看不清楚,那欄位回 null,不要猜。
"""}
「不要猜」這句很重要——model 看不清會自己腦補一個合理數字,production 抽帳很危險。
PDF:跟圖幾乎一樣
換掉 type 跟 media_type,其他長得一模一樣:
with open("contract.pdf", "rb") as f:
pdf_b64 = base64.standard_b64encode(f.read()).decode("utf-8")
messages = [{
"role": "user",
"content": [
{
"type": "document", # ← image → document
"source": {
"type": "base64",
"media_type": "application/pdf", # ← 換 mime
"data": pdf_b64,
},
},
{"type": "text", "text": "用一句話總結這份合約。"},
],
}]
Claude 的 PDF 處理是原生的——它會讀:
- 全文文字(不用先 OCR)
- 內嵌圖、chart、scanned 頁面
- 表格與表格之間的關係
- 文件結構(標題、章節層級)
不是把 PDF 轉純文字再丟 model,而是把 PDF 當「圖+文字+結構」的混合輸入處理。掃描版 PDF(純圖片那種)也讀得懂,因為內部會走 vision pipeline。
PDF 限制
實際數值請查當前 docs,但常見限制:
- 檔案大小上限(base64 後)—— 約幾十 MB 等級
- 頁數上限——超大 PDF 建議 先切頁 或走 RAG 流程
- 加密 PDF 不能直接吃,要先解密
Vision/PDF 不適合的場景
| 情境 | 為什麼不行 / 該用什麼 |
|---|---|
| Pixel-perfect 比較(前後兩張圖差幾 px) | LLM 不適合,用 image diff library |
| 抓圖中文字精確座標(OCR bounding box) | 用專門 OCR 服務(Tesseract、Google Vision OCR) |
| 大量圖片建索引(搜圖) | 用 image embedding model,不是 chat |
| 影片 | 拆成 keyframes 再丟(chat API 不吃 video) |
Image + PDF + caching 一起用
image 跟 document block 可以掛 cache_control——同一份合約反覆問問題的場景,把 document block 標 cache 起來:
{
"type": "document",
"source": {...},
"cache_control": {"type": "ephemeral"}, # ← 整份 PDF 進 cache
}
第二題開始 PDF 部分都 cache 命中,省到爆。
接下來
下一篇 citations——讓 Claude 在回答時把每句話的「出處」框出來(cited_text + 頁碼),是 RAG 的天作之合。

