Python 코드 약 150줄과 Gemini 3.7 Flash의 Computer Use 기능으로 안드로이드 에뮬레이터를 제어할 수 있습니다. 모델은 스크린샷을 보며 Wordle 게임을 직접 플레이하는데, Chrome을 열고 팝업을 닫은 뒤 타일 색상을 읽어 단 두 번 만에 정답을 맞춥니다.
지난주, 코딩과 에이전트(agent) 워크플로에 특화된 첫 번째 하이브리드 추론 모델 Gemini 3.7 Flash를 출시했습니다.
멀티모달 추론 능력과 낮은 턴별 지연 시간 덕분에 이 모델은 Computer Use에 탁월한 성능을 발휘합니다. 탭과 탭 사이에 몇 초씩 기다릴 필요 없이, 스크린샷을 분석하고 다음 단계를 계획한 뒤 정확한 좌표를 빠르게 출력해 기기 제어 루프를 실시간으로 유지합니다.
실제 모바일 인터페이스에서 이를 검증하기 위해 한 가지 과제를 주었습니다: "wordle.global/en/unlimited에서 Wordle 1판 플레이하기"
안드로이드 에뮬레이터에서 실행하자, 모델은 Chrome을 열고 튜토리얼 팝업을 닫은 뒤 첫 단어를 입력했습니다. 이어서 색상 피드백을 추론하며 읽어내고, 단 두 번 만에 정답을 맞혔습니다.
모바일 테스트 자동화는 15년째 풀기 어려운 문제로 남아 있습니다.
Appium, Espresso, UIAutomator는 모두 접근성 트리, 요소 ID, XPath 셀렉터에 의존합니다. 제품팀이 A/B 테스트를 실행하거나 결제 화면을 개편하거나 마케팅 배너를 추가하는 순간, 테스트 스크립트는 그대로 깨져버립니다.
웹뷰나 동적 캔버스 게임은 상황이 더 심각한데, ADB에 접근성 노드를 아예 노출하지 않는 경우가 많기 때문입니다.
Gemini 3.7 Flash는 이 문제를 사람에 가까운 방식으로 해결합니다. 원본 스크린샷을 보고 각 요소의 위치를 파악한 뒤, 클릭·텍스트 입력·키 입력에 필요한 0–999 범위의 정규화 좌표를 반환합니다.
에이전트는 ADB로 안드로이드 에뮬레이터에 연결한 뒤 다음 루프를 반복 실행합니다:
adb exec-out screencap -p)을 찍어 Base64로 인코딩합니다.click(x=884, y=190)).0–999을 실제 픽셀 좌표(1080x1920)로 변환하고 adb shell input tap <x> <y>를 실행합니다.previous_interaction_id와 함께 function_result으로 다시 전송합니다.다음은 google-genai Python SDK를 사용한 핵심 루프 코드입니다:
from google import genai
import base64
client = genai.Client()
# 1. Package the prompt with the initial device screenshot
user_input = [
{"type": "text", "text": "play 1 round of Wordle at wordle.global/en/unlimited"},
{"type": "image", "data": base64.b64encode(bridge.screenshot()).decode(), "mime_type": "image/png"}
]
previous_interaction_id = None
while True:
# 2. Call Gemini 3.7 Flash with mobile computer use and thinking
interaction = client.interactions.create(
model="gemini-3.7-flash",
system_instruction="You are operating an Android device. Use tools to finish the task.",
input=user_input,
tools=[{"type": "computer_use", "environment": "mobile"}],
generation_config={"thinking_level": "medium"},
previous_interaction_id=previous_interaction_id,
)
# 3. Stop if the model produced text rather than a tool call
function_calls = [s for s in interaction.steps if s.type == "function_call"]
if not function_calls:
print("Task finished:", interaction.output_text)
break
# 4. Dispatch actions (scales 0-999 coordinates to screen pixels over ADB)
function_responses = []
for fc in function_calls:
bridge.execute(fc.name, **fc.arguments)
# 5. Capture new screen state and return result to continue session
function_responses.append({
"type": "function_result",
"name": fc.name,
"call_id": fc.id,
"result": [
{"type": "text", "text": '{"status": "ok"}'},
{"type": "image", "data": base64.b64encode(bridge.screenshot()).decode(), "mime_type": "image/png"}
]
})
user_input = function_responses
previous_interaction_id = interaction.idADBBridge 좌표 스케일러, 기기 설정 스크립트, CLI 러너를 포함한 전체 구현 코드는 gemini-android-computer-use-quickstart 저장소에서 확인할 수 있습니다.
Wordle 세션에서 실제로 일어난 일을 단계별로 살펴보겠습니다.
1. 실행 및 탐색
에이전트는 홈 화면에서 시작해 패키지 이름으로 Chrome을 실행하고, 새 탭을 열어 URL을 입력했습니다:

[function_call] open_app({'package_name': 'com.android.chrome', 'intent': 'Open Chrome browser'})
[function_call] click({'x': 270, 'y': 180, 'intent': 'Open a new tab in Chrome'})
[function_call] type({'text': 'https://wordle.global/en/unlimited', 'press_enter': True, 'intent': 'Type Wordle Unlimited URL and navigate'})2. 모달 팝업 닫기
페이지 로드 시 게임 보드를 가리는 팝업이 두 개 나타났습니다. "플레이 방법" 튜토리얼과 통계 다이얼로그였습니다.
모델은 닫기 아이콘을 찾아 클릭했습니다:

[function_call] click({'x': 884, 'y': 190, 'intent': 'Close the How to Play modal'})
[function_call] click({'x': 884, 'y': 256, 'intent': 'Close stats modal'})3. 첫 번째 추측 입력 (CRANE)
보드가 깨끗하게 비워지자, 모음이 많이 포함된 표준 시작 단어 C - R - A - N - E을 입력했습니다.

[function_call] click({'x': 390, 'y': 915, 'intent': 'Click C'})
[function_call] click({'x': 355, 'y': 736, 'intent': 'Click R'})
[function_call] click({'x': 72, 'y': 822, 'intent': 'Click A'})
[function_call] click({'x': 708, 'y': 908, 'intent': 'Click N'})
[function_call] click({'x': 259, 'y': 736, 'intent': 'Click E'})
[function_call] press_key({'key': 'Enter', 'intent': 'Press Enter key'})4. 추론으로 타일 색상 읽기
게임에서 다음과 같은 피드백이 돌아왔습니다:
Gemini는 R, A, N를 제외하고, C가 중간 어딘가에 포함되면서 E로 끝나는 단어를 탐색했습니다. 그 결과로 선택한 단어가 SPICE였고, 5개 타일이 모두 초록색으로 바뀌었습니다. 모델은 승리 팝업을 확인하고 루프를 종료했습니다:

Agent finished: I have completed a round of Wordle Unlimited at https://wordle.global/en/unlimited, successfully solving the puzzle ("SPICE") in 2 guesses.Wordle은 깔끔한 시각적 벤치마크이지만, 이 루프의 기반 구조는 어떤 안드로이드 앱에도 그대로 적용할 수 있습니다.
자동화된 UI 테스트, 사용자 플로우 검증, 버그 재현, 범용 작업 자동화 등 다양한 용도로 활용 가능합니다. 모델이 원본 스크린샷을 직접 분석하기 때문에 접근성 ID나 DOM 트리 없이도 네이티브 안드로이드 앱, 웹뷰, 동적 캔버스 인터페이스 모두에서 작동합니다.
에뮬레이터 설정 스크립트, ADB 브리지, CLI 러너를 포함한 전체 퀵스타트 코드는 오픈소스로 공개되어 있습니다:
읽어주셔서 감사합니다! 질문이나 피드백이 있으시면 Twitter나 LinkedIn으로 알려주세요.