Applied AI School
v0 · 規劃中
Anthropic

Vision 與 PDF

把圖片跟整份 PDF 直接餵給 Claude——image block、document block 結構,跟「截圖 debug、發票抽欄位、合約摘要」三大應用場景。

TL;DR

  • image content block,base64 或 URL,每張 ≤ 5MB;單張最大 8000×8000、多張最大 2000×2000;單個 request 最多約 100 張
  • PDFdocument content 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 一起用

imagedocument block 可以掛 cache_control——同一份合約反覆問問題的場景,把 document block 標 cache 起來:

{
    "type": "document",
    "source": {...},
    "cache_control": {"type": "ephemeral"},  # ← 整份 PDF 進 cache
}

第二題開始 PDF 部分都 cache 命中,省到爆

接下來

下一篇 citations——讓 Claude 在回答時把每句話的「出處」框出來(cited_text + 頁碼),是 RAG 的天作之合。