Computer Use 도구를 사용하면 브라우저, 모바일, 데스크톱 제어 에이전트를 빌드하여 태스크와 상호작용하고 태스크를 자동화할 수 있습니다. 스크린샷을 사용하면 모델이 컴퓨터 화면을 '보고' 마우스 클릭 및 키보드 입력과 같은 특정 UI 작업을 생성하여 '작업'할 수 있습니다. 함수 호출과 마찬가지로 Computer Use 작업을 수신하고 실행하는 클라이언트 측 실행 환경을 구현해야 합니다.
지원되는 모델 목록은 모델 버전을 참고하세요. Gemini 3.x 모델은 다음과 같은 여러 고급 기능을 지원합니다.
- 멀티 환경 지원: 브라우저, 모바일, 데스크톱 환경용 빌드 에이전트
- 의도를 사용한 간소화된 작업: 작업에는 각 단계의 모델 추론을 설명하는
intent필드가 포함됩니다. - 구성 가능한 안전 정책: 내장 정책 카테고리 및 재정의를 사용하여 안전 동작을 미세 조정합니다.
- 프롬프트 인젝션 감지: 숨겨진 적대적 명령어를 감지하려면 스크린샷 스캔을 선택하세요.
Computer Use를 사용하면 다음 작업을 할 수 있는 에이전트를 빌드할 수 있습니다.
- 웹사이트에서 반복적인 데이터 입력과 양식 작성을 자동화합니다.
- 웹 애플리케이션 및 사용자 흐름의 자동 테스트 실행
- 다양한 웹사이트에서 조사 수행 (예: 전자상거래 사이트에서 제품 정보, 가격, 리뷰를 수집하여 구매에 대한 정보 제공)
다음은 브라우저 환경에서 computer_use 도구를 사용 설정하여 클라이언트를 초기화하고 모델에 프롬프트를 전송하는 간단한 예시입니다.
Python
from google import genai
client = genai.Client()
interaction = client.interactions.create(
model="gemini-3.7-flash",
input="Search for 'Gemini API' on Google.",
tools=[{"type": "computer_use", "environment": "browser"}]
)
print(interaction)
자바스크립트
import { GoogleGenAI } from '@google/genai';
const ai = new GoogleGenAI();
const interaction = await ai.interactions.create({
model: 'gemini-3.7-flash',
input: "Search for 'Gemini API' on Google.",
tools: [{ type: "computer_use", environment: "browser" }]
});
console.log(interaction);
Computer Use 작동 방식
컴퓨터 사용 모델로 에이전트를 빌드하려면 애플리케이션과 API 간에 연속 루프를 설정해야 합니다. 각 단계에서 코드가 실행하는 작업은 다음과 같습니다.
- 모델에 요청 보내기
- 애플리케이션은 Computer Use 도구, 구성 설정 (예: 타겟 환경), 사용자 프롬프트, 현재 화면의 스크린샷이 포함된 API 요청을 전송합니다.
- 모델 대답 수신
- 모델은 화면과 프롬프트를 분석하여 UI 작업을 나타내는 추천
function_call(예: 클릭, 스크롤, 키 입력)이 포함된 대답을 반환합니다. - Gemini 3.x 모델의 경우 모델이 해당 작업을 선택한 이유를 설명하는 추론
intent도 응답에 포함됩니다. - 대답에는 작업을 일반/허용,
require_confirmation(사용자 승인 필요) 또는 차단으로 분류하는 내부 안전 시스템의safety_decision도 포함될 수 있습니다.
- 모델은 화면과 프롬프트를 분석하여 UI 작업을 나타내는 추천
- 수신된 작업 실행
- 동작이 허용되거나 사용자가 확인하면 클라이언트 측 코드는
function_call를 파싱하고, 정규화된 좌표를 뷰포트에 맞게 조정하고, 자동화 도구(예: Playwright)를 사용하여 대상 환경에서 동작을 실행합니다. 작업이 차단되면 클라이언트는 실행을 중지하거나 중단을 처리해야 합니다.
- 동작이 허용되거나 사용자가 확인하면 클라이언트 측 코드는
- 새 환경 상태 캡처
- 작업이 실행되면 애플리케이션이 새 스크린샷을 캡처하고 다음 단계를 요청하기 위해
function_result에서 모델에 다시 전송합니다.
- 작업이 실행되면 애플리케이션이 새 스크린샷을 캡처하고 다음 단계를 요청하기 위해
그런 다음 이 프로세스는 2단계부터 반복되어 작업이 완료되거나 종료될 때까지 모델에서 다음 작업을 계속 요청합니다.

컴퓨터 사용 구현 방법
컴퓨터 사용 도구로 빌드하기 전에 다음을 설정해야 합니다.
- 안전한 실행 환경: 샌드박스 VM 또는 컨테이너에서 에이전트를 실행하여 호스트 시스템에서 격리하고 잠재적 영향을 제한합니다. 참조 구현에는 시작점으로 사용할 수 있는 즉시 사용 가능한 Docker 기반 샌드박스가 포함되어 있습니다.
- 클라이언트 측 작업 핸들러: 좌표를 실행하고, 텍스트를 입력하고, 스크린샷을 찍는 클라이언트 측 로직을 구현합니다.
아래 예에서는 웹브라우저를 실행 환경으로 사용하고 Playwright를 클라이언트 측 핸들러로 사용합니다.
0. Playwright 설정
먼저 필요한 패키지를 설치합니다.
pip install google-genai playwright
playwright install chromium
그런 다음 실행에 사용할 Playwright 브라우저 인스턴스를 초기화합니다.
from playwright.sync_api import sync_playwright
# 1. Configure screen dimensions for the target environment
SCREEN_WIDTH = 1440
SCREEN_HEIGHT = 900
# 2. Start the Playwright browser
# In production, utilize a sandboxed environment.
playwright = sync_playwright().start()
# Set headless=False to see the actions performed on your screen
browser = playwright.chromium.launch(headless=False)
# 3. Create a context and page with the specified dimensions
context = browser.new_context(
viewport={"width": SCREEN_WIDTH, "height": SCREEN_HEIGHT}
)
page = context.new_page()
# 4. Navigate to an initial page to start the task
page.goto("https://www.google.com")
# The 'page', 'SCREEN_WIDTH', and 'SCREEN_HEIGHT' variables
# will be used in the steps below.
1. 모델에 요청 보내기
클라이언트 라이브러리를 초기화하고 Computer Use 도구를 구성합니다. 요청을 발행할 때 디스플레이 크기를 지정할 필요는 없습니다. 모델은 화면의 높이와 너비에 맞게 조정된 픽셀 좌표를 예측합니다.
Gemini 3.x
Python
google-genai Python SDK (버전 2.7.0 이상)를 사용하여 브라우저 환경을 타겟팅하는 요청을 구성합니다.
from google import genai
client = genai.Client()
interaction = client.interactions.create(
model='gemini-3.7-flash',
input="Find a flight from SF to Hawaii on Jun 30th, coming back on Jul 6th",
tools=[
{
"type": "computer_use",
"environment": "browser",
"enable_prompt_injection_detection": True
}
]
)
print(interaction)
자바스크립트
@google/genai Node.js SDK를 사용하여 브라우저 환경을 타겟팅하는 요청을 구성합니다.
import { GoogleGenAI } from '@google/genai';
const ai = new GoogleGenAI();
const interaction = await ai.interactions.create({
model: 'gemini-3.7-flash',
input: "Find a flight from SF to Hawaii on Jun 30th, coming back on Jul 6th",
tools: [
{
type: "computer_use",
environment: "browser",
enable_prompt_injection_detection: true
}
]
});
console.log(interaction);
REST
curl을 사용하여 요청을 보냅니다.
curl -X POST \
"https://generativelanguage.googleapis.com/v1beta/interactions" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3.7-flash",
"input": "Find me a flight from SF to Hawaii on Jun 30th, coming back on Jul 6th. Start by navigating directly to flights.google.com",
"tools": [
{
"type": "computer_use",
"environment": "browser",
"enable_prompt_injection_detection": true
}
]
}'
Gemini 2.5 (기존)
Python
from google import genai
client = genai.Client()
# Specify predefined functions to exclude (optional)
excluded_functions = ["drag_and_drop"]
interaction = client.interactions.create(
model='gemini-2.5-computer-use-preview-10-2025',
input="Search for highly rated smart fridges on Google Shopping.",
tools=[
{
"type": "computer_use",
"environment": "browser",
"excluded_predefined_functions": excluded_functions
}
]
)
print(interaction)
자바스크립트
import { GoogleGenAI } from '@google/genai';
const ai = new GoogleGenAI();
// Specify predefined functions to exclude (optional)
const excludedFunctions = ["drag_and_drop"];
const interaction = await ai.interactions.create({
model: 'gemini-2.5-computer-use-preview-10-2025',
input: "Search for highly rated smart fridges on Google Shopping.",
tools: [
{
type: "computer_use",
environment: "browser",
excluded_predefined_functions: excludedFunctions
}
]
});
console.log(interaction);
2. 모델 응답 수신
대답 모델이 함수 호출을 제안합니다. Gemini 3.x 모델의 경우 대답에 좌표와 함께 맞춤형 추론 의도가 포함됩니다. 다음은 두 응답의 예시를 보여줍니다.
Gemini 3.x
{
"steps": [
{
"type": "function_call",
"name": "click",
"arguments": {
"x": 450,
"y": 120,
"intent": "Click the search box to type the destination."
}
}
]
}
Gemini 2.5 (기존)
{
"steps": [
{
"type": "model_output",
"content": [
{
"type": "text",
"text": "I will type the search query into the search bar."
}
]
},
{
"type": "function_call",
"name": "type_text_at",
"arguments": {
"x": 371,
"y": 470,
"text": "highly rated smart fridges",
"press_enter": true
}
}
]
}
3. 수신된 작업 실행
애플리케이션은 응답 좌표를 파싱하고 작업을 실행하고 정규화된 1000x1000 좌표에서 확장해야 합니다.
아래 코드는 기존 도구 명령어 (click_at, type_text_at)와 최신 간소화된 명령어 (click, type)를 모두 처리합니다.
Python
from typing import Any, List, Tuple
import time
def denormalize_x(x: int, screen_width: int) -> int:
"""Convert normalized x coordinate (0-1000) to actual pixel coordinate."""
return int(x / 1000 * screen_width)
def denormalize_y(y: int, screen_height: int) -> int:
"""Convert normalized y coordinate (0-1000) to actual pixel coordinate."""
return int(y / 1000 * screen_height)
def execute_function_calls(interaction, page, screen_width, screen_height):
results = []
function_calls = [
step for step in interaction.steps if step.type == "function_call"
]
for function_call in function_calls:
action_result = {}
fname = function_call.name
args = function_call.arguments
print(f" -> Executing: {fname} (Intent: {args.get('intent', 'N/A')})")
try:
if fname in ("open_web_browser", "open_app"):
pass # Handled / already open
elif fname in ("click", "click_at", "double_click", "triple_click", "middle_click", "right_click", "move", "long_press"):
actual_x = denormalize_x(args["x"], screen_width)
actual_y = denormalize_y(args["y"], screen_height)
if fname in ("click", "click_at"):
page.mouse.click(actual_x, actual_y)
elif fname == "double_click":
page.mouse.dblclick(actual_x, actual_y)
elif fname == "right_click":
page.mouse.click(actual_x, actual_y, button="right")
elif fname == "middle_click":
page.mouse.click(actual_x, actual_y, button="middle")
elif fname == "move":
page.mouse.move(actual_x, actual_y)
elif fname in ("type", "type_text_at"):
actual_x = denormalize_x(args["x"], screen_width) if "x" in args else None
actual_y = denormalize_y(args["y"], screen_height) if "y" in args else None
text = args["text"]
press_enter = args.get("press_enter", False)
if actual_x is not None and actual_y is not None:
page.mouse.click(actual_x, actual_y)
# Clear field first
page.keyboard.press("Meta+A")
page.keyboard.press("Backspace")
page.keyboard.type(text)
if press_enter:
page.keyboard.press("Enter")
elif fname == "navigate":
page.goto(args["url"])
elif fname == "go_back":
page.go_back()
elif fname == "go_forward":
page.go_forward()
elif fname == "wait":
time.sleep(args.get("seconds", 1))
else:
print(f"Warning: Custom or unhandled function {fname}")
page.wait_for_load_state(timeout=5000)
time.sleep(1)
except Exception as e:
print(f"Error executing {fname}: {e}")
action_result = {"error": str(e)}
results.append((fname, function_call.id, action_result))
return results
자바스크립트
function denormalizeX(x, screenWidth) {
// Convert normalized x coordinate (0-1000) to actual pixel coordinate.
return Math.floor((x / 1000) * screenWidth);
}
function denormalizeY(y, screenHeight) {
// Convert normalized y coordinate (0-1000) to actual pixel coordinate.
return Math.floor((y / 1000) * screenHeight);
}
async function executeFunctionCalls(interaction, page, screenWidth, screenHeight) {
const results = [];
const functionCalls = interaction.steps.filter(step => step.type === "function_call");
for (const functionCall of functionCalls) {
const actionResult = {};
const fname = functionCall.name;
const args = functionCall.arguments;
console.log(` -> Executing: ${fname} (Intent: ${args.intent || 'N/A'})`);
try {
if (fname === "open_web_browser" || fname === "open_app") {
// Handled / already open
} else if (["click", "click_at", "double_click", "triple_click", "middle_click", "right_click", "move", "long_press"].includes(fname)) {
const actualX = denormalizeX(args.x, screenWidth);
const actualY = denormalizeY(args.y, screenHeight);
if (fname === "click" || fname === "click_at") {
await page.mouse.click(actualX, actualY);
} else if (fname === "double_click") {
await page.mouse.dblclick(actualX, actualY);
} else if (fname === "right_click") {
await page.mouse.click(actualX, actualY, { button: "right" });
} else if (fname === "middle_click") {
await page.mouse.click(actualX, actualY, { button: "middle" });
} else if (fname === "move") {
await page.mouse.move(actualX, actualY);
}
} else if (fname === "type" || fname