停止在安卓自動化上浪費代碼
大多數由大語言模型驅動的安卓自動化開始時都會向模型展示螢幕.
聽起來很合理。人類看著手機,決定要點擊什麼,然後點擊它。給模型同樣的視角.
問題在於「同樣的視角」很昂貴。
一張完整的螢幕截圖很花費。一個原始的 Android UI XML 輸出也很花費,只是方式比較安靜。模型在讀取數千個表示佈局機械的標記之後,才達到幾個重要的標籤:
Email
Password
Continue
對於單個步驟,那種浪費很容易被忽略。對於一個50步的移動代理軌跡,它變成了賬單。
環路
安卓代理通常這樣做:
- 讀取當前螢幕。
- 決定要做什么。
- 點擊、輸入或滑動。
- 等待下一個螢幕。
- 重複。
第一步是令牌洩露的開始。
如果你使用 uiautomator dump,模型會得到這樣的XML:
<node index="0" text="" resource-id=""
class="android.widget.FrameLayout"
package="com.google.android.apps.nexuslauncher"
content-desc=""
checkable="false" checked="false"
clickable="false" enabled="true"
focusable="false" focused="false"
scrollable="false" long-clickable="false"
password="false" selected="false"
bounds="[0,0][1440,3120]">
這是一個佈局節點。它幾乎沒有提到代理人可以執行的動作.
這不是 UIAutomator 的錯誤。XML 是對可訪問性樹的忠實序列化。忠實不等於有用.
數字
在幾個普通的 Android螢幕上,差異看起來像這樣:
| 螢幕 | UIAutomator XML | 手機hs ui -i
|
減少 |
|---|---|---|---|
| 啟動器首頁 | 3,153 個詞彙 | 246 個詞彙 | 12.8x |
| 設定首頁 | 5,762 個詞彙 | 729 個詞彙 | 7.9x |
| 設定 ->應用程式 | 4,050 個詞彙 | 320 個 token | 12.7x |
Token 數量來自 tiktoken,使用 GPT-4 編碼。更詳細的說明是 An Android UI Dump for LLMs.
簡短版本:一個典型的螢幕,以 XML 格式可能需要 4,000-6,000 個 token,但以動作表格式通常只需幾百個 token。
走過50步,那就是在傳送約250k個螢幕狀態的token和傳送約25k-40k個token之間的差異。
代理通常在兩種情況下做出相同的決定。
模型實際上需要什麼
對於UI自動化,模型不需要一個DOM形狀的樹。
它需要一個它可以操作的物品列表:
fill EditText "Email" #email 540,540
fill EditText "Password" #password 540,640 [password]
tap Button "Continue" #continue 540,860
這個表格給模型有用的資訊:
- 有哪些動作可用.
- 人類看到的是哪個標籤.
- 這是什麼類型的控制.
- 工具將會點擊或輸入的位置.
模型現在可以回答:
tap "Continue"
它不必解析佈局祖先、負數布林值、完整限定類名,或四數字邊界矩形。
規則
對於LLM工具輸出,優化規則很簡單:
不要序列化模型在其下一步行動中無法使用的事實。
Android XML經常違反這個規則:
-
clickable="false"在代理永遠不會點擊的節點上。 -
enabled="true"在幾乎每個節點上重複。 - 空的
FrameLayout和LinearLayout容器。 - 完整的類名,例如
android.widget.TextView。 - 當代理只需要一個點擊點時,才界定邊界矩形。
- 當讀取器是語言模型而非解析器時,出現 JSON 風格的鍵重複。
手機移除預設值,縮短名稱,計算中心點,並保留標籤.
結果不是一個更小的 XML 檔案。它是一個不同的介面:
hs ui
hs tap "Continue"
hs wait "Dashboard"
屏幕截圖仍然有用
這不是反對屏幕截圖的理由。
當佈局重要、視覺狀態重要,或應用程式渲染重要資訊但無法存取標籤時,螢幕截圖是有用的。
但螢幕截圖並非每個步驟的優選。它們體積龐大,移動緩慢,且常迫使模型對於Android已經暴露的文字執行類似OCR的工作。
更好的迴圈是:
hs ui > /tmp/screen.txt
hs see --size 768 /tmp/screen.jpg # only when visual context matters
先給模型文字UI。當文字不夠時再添加圖片.
這通常能節省代碼並讓操作更容易審計.
為何這對代理比測試更關鍵
傳統的手機測試不太關心代碼數量。測試執行者不需要支付讀取XML的費用。
LLM 代理不同。每個迴圈步驟都有一個上下文預算和一個成本。如果一半的提示是一個滿佈無效佈局節點的 UI 樹,模型就在關注垃圾資料。
這在三個地方顯現出來:
- 成本:重複的螢幕狀態佔據長序列的主導地位。
- 延遲:大提示傳送和處理的時間更長。
- 可靠度:行動導向的語境較短,讓模型捕捉到不相關結構的空間減少。
對代理來說,最好的工具輸出不是系統最完整的表現。它是保留下一個正確行動的最小表現。
實用模式
對 Android,模式看起來像這樣:
hs use
hs ui
hs tap "Sign in"
hs fill "Email" "you@example.com"
hs fill "Password" "$PASSWORD"
hs tap "Continue"
hs wait "Dashboard"
對於大型語言模型,重要的交接甚至更小:
Here is the current Android UI. Pick the next action by label.
fill EditText "Email" #email 540,540
fill EditText "Password" #password 540,640 [password]
tap Button "Continue" #continue 540,860
模型不需要知道這些節點位於三個嵌套的FrameLayout之內。它需要知道「繼續」是一個按鈕.
相關指南
https://handsets.dev/blog/stop-wasting-tokens-on-android-automation/











