인셔셔RSS 관심 있는 블로그, 뉴스, 기술 정보를 효율적으로 추적하고 읽으세요
원문 읽기 InertiaRSS에서 열기

추천 피드

Google DeepMind News
Google DeepMind News
人人都是产品经理
人人都是产品经理
M
MIT News - Artificial intelligence
博客园 - 叶小钗
MyScale Blog
MyScale Blog
V
Visual Studio Blog
月光博客
月光博客
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
量子位
I
InfoQ
有赞技术团队
有赞技术团队
阮一峰的网络日志
阮一峰的网络日志
Jina AI
Jina AI
V
V2EX
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Blog — PlanetScale
Blog — PlanetScale
Last Week in AI
Last Week in AI
雷峰网
雷峰网
Stack Overflow Blog
Stack Overflow Blog
博客园 - Franky

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python)
안드로이드 자동화에 토큰을 낭비하지 마세요
Elliot Gao · 2026-05-24 · via DEV Community

안드로이드 자동화에 토큰을 더 이상 낭비하지 마세요

대부분의 LLM 기반 안드로이드 자동화는 모델에게 화면을 보여주면서 시작됩니다.

그것은 합리적으로 들립니다. 사람이 폰을 보고, 클릭할 것을 결정하고 클릭합니다. 모델에게 동일한 시각을 제공하세요.

문제는 "동일한 시각"이 비용이 많이 드는 것입니다.

전체 화면 캡처는 비싸다. 원시 안드로이드 UI XML 덤프도 비싸지만 조용한 방식으로 비싸다. 모델은 레이아웃 기계의 수천 개의 토큰을 읽고 나서야 중요한 몇 개의 레이블에 도달한다:

Email
Password
Continue

전체 화면 모드를 입력하세요 전체 화면 모드를 종료하세요

한 단계에 대해 그 손실은 쉽게 무시할 수 있다. 50단계의 모바일 에이전트 경로에 대해 그것은 청구서가 된다.

루프

안드로이드 에이전트는 보통 이렇게 합니다:

  1. 현재 화면을 읽습니다.
  2. 무엇을 할지 결정합니다.
  3. 클릭하거나, 타이핑하거나, 스와이프합니다.
  4. 다음 화면을 기다립니다.
  5. 반복합니다.

첫 번째 단계에서 토큰 누수가 시작됩니다.

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은 접근성 트리의 충성스러운 직렬화입니다. 충성스러움은 유용하다는 것과 같지 않습니다.

숫자

일반적인 안드로이드 화면 몇 개에서는 차이가 이렇게 보입니다:

화면 UIAutomator XML 핸드셋 hs ui -i 감소
라ucher 홈 3,153 토큰 246 토큰 12.8x
설정 홈 5,762 토큰 729 토큰 7.9x
설정 -> 앱 4,050 토큰 320 토큰 12.7x

토큰 수는 tiktoken와 GPT-4 인코딩을 사용하여 얻었습니다. 더 자세한 내용은 An Android UI Dump for LLMs.

간단한 버전: 일반적으로 4,000-6,000 토큰이 드는 XML 스크린은 액션 테이블로 몇 백 토큰으로 표현할 수 있습니다.

50개의 단계를 거쳤습니다. 그것은 화면 상태의 대략 250k 토큰을 전송하는 것과 대략 25k-40k를 전송하는 것 사이의 차이입니다.

агент은 어느 쪽이든 동일한 결정을 내립니다.

모델이 실제로 필요한 것은

UI 자동화에 있어서, 모델은 DOM 모양의 트리가 필요하지 않습니다.

그것은 행동할 수 있는 것들의 목록이 필요합니다:

fill  EditText  "Email"     #email     540,540
fill  EditText  "Password"  #password  540,640  [password]
tap   Button    "Continue"  #continue  540,860

전체 화면 모드를 켜기 전체 화면 모드 종료

그 표는 모델에게 유용한 사실을 제공합니다:

  • 어떤 작동이 가능합니다.
  • 인간이 볼 수 있는 레이블입니다.
  • 어떤 종류의 제어인지입니다.
  • 도구가 클릭하거나 입력할 위치입니다.

이제 모델이 답변할 수 있습니다:

tap "Continue"

전체 화면 모드 입력 전체 화면 모드 종료

레이아웃 조상을 파싱하거나, 부정 논리값, 전체 클래스 이름, 또는 네 자리 숫자 경계 사각형을 파싱할 필요가 없습니다.

규칙

LLM 도구 출력에 대한 최적화 규칙은 간단합니다:

모델이 다음 작업에서 사용할 수 없는 사실을 직렬화하지 마세요.

안드로이드 XML은 이 규칙을 끊임없이 위반합니다:

  • clickable="false" 에이전트가 결코 클릭하지 않을 노드에서.
  • enabled="true"는 거의 모든 노드에서 반복됩니다.
  • FrameLayoutLinearLayout 컨테이너가 비어 있습니다.
  • android.widget.TextView과 같은 전체 클래스 이름.
  • 에이전트가 클릭 지점만 필요할 때 경계 사각형을 설정합니다.
  • 언어 모델이 파서가 아닌 경우 JSON 스타일 키 반복.

핸드셋은 기본값을 제거하고, 이름을 짧게 만들고, 중심점을 계산하고, 레이블을 유지합니다.

결과는 더 작은 XML 파일이 아닙니다. 그것은 다른 인터페이스입니다:

hs ui
hs tap "Continue"
hs wait "Dashboard"

전체 화면 모드로 전환 전체 화면 모드 종료

스크린샷은 여전히 유용합니다

이것은 스크린샷에 대한 반론이 아닙니다.

스크린샷은 레이아웃이 중요할 때, 시각적 상태가 중요할 때, 또는 앱이 접근성 레이블 없이 중요한 정보를 렌더링할 때 유용합니다.

하지만 스크린샷은 모든 단계의 기본값으로는 부족합니다. 그들은 크고, 움직이는 데 느리고, 종종 모델이 안드로이드가 이미 노출한 텍스트에 대해 OCR과 유사한 작업을 강요합니다.

더 나은 루프는 다음과 같습니다:

hs ui > /tmp/screen.txt
hs see --size 768 /tmp/screen.jpg   # only when visual context matters

전체 화면 모드 입력 전체 화면 모드 종료

먼저 모델에게 텍스트 UI를 제공하세요. 텍스트가 부족할 때 이미지를 추가하세요.

그렇게 하면 토큰을 절약하고 작업을 검토하기 쉽게 만듭니다.

에이전트보다 테스트에 더 중요한 이유

傳統의 모바일 테스트는 토큰 수를 많이 신경 쓰지 않습니다. 테스트 러너는 XML을 읽는 데 비용을 지불하지 않습니다.

LLM 에이전트는 다릅니다. 각 루프 단계에는 컨텍스트 예산과 비용이 있습니다. 프롬프트의 절반만 사망한 레이아웃 노드로 가득 찬 UI 트리라면 모델은 쓰레기에 주의를 기울입니다.

이는 세 곳에서 나타납니다.

  • 비용: 반복된 화면 상태는 긴 트레이지토리를 지배합니다.
  • 지연 시간: 큰 프롬프트는 전송하고 처리하는 데 더 오랜 시간이 걸립니다.
  • 신뢰성: 짧은 행동 중심적인 맥락은 모델이 관련 없는 구조에 달라붙을 여지를 줄여줍니다.

에이전트에 대한 최고의 도구 출력은 시스템의 가장 완전한 표현이 아닙니다. 다음에 올 올바른 행동을 보존하는 가장 작은 표현입니다.

실용적인 패턴

안드로이드의 경우, 패턴은 이렇게 보입니다:

hs use
hs ui
hs tap "Sign in"
hs fill "Email" "you@example.com"
hs fill "Password" "$PASSWORD"
hs tap "Continue"
hs wait "Dashboard"

전체 화면 모드로 전환 전체 화면 모드 종료

LLM의 경우 중요한 전달은 더욱 작습니다:

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 안에 있다는 것을 알 필요가 없습니다. "계속"이 버튼이라는 것을 알면 됩니다.

관련 가이드

JHSNS_URL_0__