TL;DR:agent-browser能在截圖上畫圖、寫字——screenshot --annotate在每個可互動元素上畫編號[1][2][3]並寫出對照清單、highlight在指定元素外畫高亮框、diff screenshot把畫面差異畫成像素級比對圖。重點不是給人塗鴉的小畫家,而是自動畫出 AI 看得懂的標記,把只能讀純文字 snapshot(一頁 200-400 tokens)的 agent 升級成「看著畫面操作」,補上 icon 按鈕、canvas、純視覺狀態這些純文字抓不到的盲區。版本 v0.27.2,全程 Mac 實測。
接續上一篇 agent-browser 是什麼。那篇把純文字流跑通了:snapshot 拿到 @eN refs、fill、click、截圖 round-trip。但寫完我自己卡在一個地方——有些頁面,純文字 snapshot 就是不夠用。
📌 目錄
- 純文字 snapshot 抓不到的那一塊
- annotate:在截圖上疊元素編號
- highlight:高亮單一元素
- diff screenshot:截圖像素級比對
- 三招比較:什麼時候用哪個
- 為什麼多模態 AI 需要看著有標號的畫面
- 踩坑紀錄
- 常見問題
- 延伸資源
🧩 純文字 snapshot 抓不到的那一塊
agent-browser 真的能在截圖上畫圖、寫字——它會把元素編號 [1][2][3]、對照清單、高亮框直接畫進截圖的像素裡。差別只在「畫什麼」:它不是給人塗鴉的小畫家,而是自動在截圖上畫出 AI 看得懂的標記與文字,把「只能讀文字的 agent」升級成「看著畫面操作」。這篇就把這三招畫法實測一遍。
為什麼需要在圖上畫東西?前一篇講的純文字 snapshot 很省 token,但它本質上是把頁面的可訪問性樹(accessibility tree)轉成文字。a11y tree 抓不到的東西,snapshot 就是空白:
- 沒有文字標籤的 icon 按鈕——一個只有齒輪圖示、沒有
aria-label的設定鈕,在 snapshot 裡可能根本看不出是什麼 - canvas 畫的內容——圖表、白板、遊戲畫面,canvas 對 a11y tree 來說就是一塊黑盒
- 純視覺狀態——某個元素變紅了、loading spinner 在轉、彈窗蓋住了底層,這些「看得到但讀不到」的狀態
🏷️ annotate:在截圖上疊元素編號
screenshot --annotate 是三招裡最核心的。它截圖的同時,在每個可互動元素上疊一個編號標籤 [N],而且每個 [N] 直接對應到純文字流的 @eN ref。
agent-browser screenshot --annotate
回傳長這樣(截圖檔 + 一份對照清單):
Screenshot saved to /tmp/screenshot-2026-02-17T12-00-00-abc123.png
[1] @e1 button "Submit"
[2] @e2 link "Home"
[3] @e3 textbox "Email"
關鍵在最後一段話:截完 annotate 後,refs 會進快取,你可以馬上拿編號去操作。
agent-browser screenshot --annotate ./page.png
agent-browser click @e2 # 直接點截圖上標 [2] 的 "Home" 連結
這就是它設計得巧妙的地方——同一套 @eN ref,文字流跟視覺流共用。多模態 AI 看著截圖上的 [2] 推理「我要點首頁」,產生的指令 click @e2 跟純文字流一模一樣,不用兩套座標系統。官方把它形容成「你的可訪問性樹的視覺除錯器」(a visual debugger for your accessibility tree),蠻貼切的。
它解決的具體場景
- 沒標籤的 icon:截圖一看就知道齒輪在右上角標
[7],click @e7收工,不用猜 selector - 重疊/被遮擋的元素:snapshot 看不出哪個蓋住哪個,標號截圖一目了然
- 給多模態模型當地圖:把 annotate 截圖丟進模型,它能「看圖點號」,比純文字描述精準得多
🔦 highlight:高亮單一元素
highlight 比 annotate 輕量,只做一件事:把指定的元素框起來高亮。
agent-browser highlight @e1 # 高亮 ref
agent-browser highlight "button.submit" # 也吃 CSS selector
用途跟 annotate 不一樣。annotate 是「全頁掃描」,一次標所有可互動元素;highlight 是「聚焦驗證」——我已經知道要操作哪個了,截圖前先 highlight 它,截出來確認「對,就是這顆」,避免點錯。
實際跑的時候,我常拿它做這種事:自動化流程跑到一半懷疑點錯按鈕,highlight @e5 + screenshot,肉眼確認一下再往下,比盲改 selector 快。
📊 diff screenshot:截圖像素級比對
第三招是視覺回歸測試的味道。diff screenshot 拿現在的畫面跟一張 baseline 截圖做像素級比對。
agent-browser diff screenshot --baseline before.png # 跟基準圖比
agent-browser diff screenshot --baseline b.png -o diff.png # 輸出差異圖到指定路徑
agent-browser diff screenshot --baseline b.png -t 0.2 # 調色彩 threshold(0-1)
這跟它的另一個指令 diff snapshot 要分清楚——一個比畫面、一個比文字:
agent-browser diff snapshot # 比 a11y tree(文字層)
agent-browser diff snapshot --baseline before.txt # 跟存檔的 snapshot 比
agent-browser diff screenshot --baseline before.png # 比像素(視覺層)
差別在於:文字 diff 抓「結構改了」,像素 diff 抓「長相改了」。 一個按鈕從藍變紅、間距跑掉、字型 render 不一樣——這些 a11y tree 文字一字不差,但 diff screenshot 一比就現形。-t 調 threshold 是為了過濾抗鋸齒造成的微小色差,免得每次都報「有變化」。
它甚至能直接比兩個 URL:
agent-browser diff url https://v1.com https://v2.com --screenshot
新舊版上線前比個版面,這招很省事。
⚖️ 三招比較:什麼時候用哪個
| 指令 | 做什麼 | 典型場景 | 比對對象 |
|---|---|---|---|
screenshot --annotate | 全頁疊元素編號 [N],對應 @eN | 給多模態 AI 當操作地圖、找沒標籤的 icon | ✗ |
highlight | 高亮單一元素 | 操作前聚焦驗證「是不是這顆」 | ✗ |
diff screenshot | 現況 vs baseline 像素比對 | 視覺回歸、版面跑版偵測 | ✓ 像素 |
diff snapshot | 現況 vs baseline 文字比對 | 結構/內容變動偵測 | ✓ 文字 |
- 不知道頁面長怎樣、要 AI 看圖操作 →
annotate - 已知目標、只想確認沒點錯 →
highlight - 要抓「長相變了」 →
diff screenshot - 要抓「結構/內容變了」 →
diff snapshot
🧠 為什麼多模態 AI 需要看著有標號的畫面
這是整篇的核心。官方 README 對 annotate 的用途寫得很明白:它是給「能推理視覺佈局、沒標籤的 icon 按鈕、canvas 元素,或文字可訪問性樹捕捉不到的視覺狀態」的多模態 AI 模型用的。
把這句話拆開來看,背後的設計取捨是:
[2] 對應 @e2,看圖推理完直接 click @e2換句話說,annotate 不是「截個圖」,是幫多模態 AI 把視覺感知跟動作指令對齊。模型負責「看懂這是首頁連結」,agent-browser 負責「首頁連結 = @e2 你點就對了」。這個分工是它比「直接餵截圖給模型」好用的原因。
⚠️ 踩坑紀錄
annotate 只支援 CDP 後端,Safari 不行
這是查 README 時最該記的一條限制:
Annotated screenshots are supported on the CDP-backed browser path (Chrome/Lightpanda). The Safari/WebDriver backend does not yet support --annotate.
annotate 只在 CDP 後端(Chrome / Lightpanda)能用,Safari/WebDriver 後端目前不支援。 如果你在 Mac 上習慣跑 Safari 後端,--annotate 會無效。要用視覺標註就乖乖切 Chrome。
ref 會過期,annotate 也救不了
承襲前一篇講過的坑:@eN ref 是「這一次 snapshot 的快照」,頁面一重整、一導航、DOM 一變動,ref 就失效。annotate 截圖快取的 ref 也一樣——截完 annotate 別拖太久才操作,中間如果頁面動了,先重截一次。我踩過一次:annotate 完去做別的事,回來 click @e3 點到不存在的元素。
diff threshold 不調,每次都報有變化
diff screenshot 不帶 -t 用預設值時,抗鋸齒、字型 sub-pixel render 的微小差異會被算成「有變化」。做視覺回歸時記得 -t 0.1 ~ -t 0.2 過濾雜訊,不然 CI 會一直假警報。
❓ 常見問題
Q1:agent-browser 可以在截圖上畫圖、寫字嗎?
可以,而且這正是它的賣點。--annotate 會在截圖上畫出元素編號 [N] 並寫出對照清單、highlight 會在指定元素外面畫高亮框、diff screenshot 會把差異畫在輸出圖上——這些都是直接畫進截圖像素裡的標記與文字。它不是讓你手動塗鴉的小畫家(要手畫框寫字用 macOS 預覽、Skitch 那類工具),而是自動畫出 AI 看得懂的標註,畫的目的是讓多模態模型看圖就能精準操作。
Q2:annotate 的編號 [N] 和純文字 snapshot 的 @eN 是同一套嗎?
是。這是它設計得最聰明的地方——[2] 對應 @e2,視覺流跟文字流共用同一套 ref,不用維護兩套座標。
Q3:diff screenshot 跟 diff snapshot 差在哪?diff screenshot 比像素(長相變了沒),diff snapshot 比可訪問性樹(結構/內容變了沒)。按鈕變色、跑版用前者;DOM 結構、文字內容變動用後者。
Q4:為什麼 Safari 後端不能用 annotate?
annotate 需要 CDP(Chrome DevTools Protocol)的能力來掃描並疊加元素標籤,Safari 走的是 WebDriver 協定,目前還沒實作這塊。要用 annotate 就切 Chrome 或 Lightpanda 後端。
Q5:這些指令適合接進 Claude Code 嗎?
適合。跟前一篇的純文字流一樣,這三招都是 CLI 指令,可以用「薄存根 + CLI 動態供給」的方式接進 Claude Code,讓對話裡直接調用。多模態場景(要 AI 看圖)特別適合用 annotate 當輸入。
🔗 延伸資源
- agent-browser 是什麼?AI agent 專用瀏覽器自動化 CLI 實戰(含 Claude Code 接法)——上一篇,純文字 snapshot + refs 流,先看這篇再回來
- vercel-labs/agent-browser GitHub——官方 repo,README 的 Annotated Screenshots 段
- agent-browser README——指令完整清單
- agent-browser npm——版本(撰文時 v0.27.2)