Sử dụng máy tính

Công cụ Sử dụng máy tính cho phép bạn tạo các tác nhân kiểm soát trình duyệt, thiết bị di động và máy tính để bàn tương tác và tự động hoá các tác vụ. Bằng cách sử dụng ảnh chụp màn hình, mô hình này có thể "nhìn thấy" màn hình máy tính và "hành động" bằng cách tạo các thao tác cụ thể trên giao diện người dùng, chẳng hạn như nhấp chuột và nhập dữ liệu bằng bàn phím. Tương tự như việc gọi hàm, bạn sẽ cần triển khai môi trường thực thi phía máy khách để nhận và thực thi các thao tác Sử dụng máy tính.

Để biết danh sách các mô hình được hỗ trợ, hãy xem phần Các phiên bản mô hình. Các mô hình Gemini 3.x hỗ trợ một số chức năng nâng cao:

  • Hỗ trợ nhiều môi trường: tạo các tác nhân cho môi trường trình duyệt, thiết bị di động và máy tính.
  • Các thao tác tinh giản bằng ý định: các thao tác bao gồm một trường intent giải thích lý do của mô hình đằng sau mỗi bước.
  • Chính sách an toàn có thể định cấu hình: tinh chỉnh hành vi an toàn bằng các danh mục chính sách và chế độ ghi đè được tích hợp sẵn.
  • Phát hiện tiêm câu lệnh (prompt injection): chọn sử dụng tính năng quét ảnh chụp màn hình để phát hiện các chỉ dẫn đối nghịch bị ẩn.

Với tính năng Sử dụng máy tính, bạn có thể tạo các tác nhân có khả năng:

  • Tự động hoá việc nhập dữ liệu hoặc điền biểu mẫu lặp đi lặp lại trên các trang web.
  • Thực hiện kiểm thử tự động các ứng dụng web và quy trình của người dùng
  • Nghiên cứu trên nhiều trang web (ví dụ: thu thập thông tin sản phẩm, giá cả và bài đánh giá từ các trang web thương mại điện tử để đưa ra quyết định mua hàng)

Dưới đây là một ví dụ tối giản về việc khởi chạy ứng dụng và gửi một câu lệnh cho mô hình khi công cụ computer_use được bật cho môi trường trình duyệt:

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)

JavaScript

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);


Cách hoạt động của tính năng Sử dụng máy tính

Để tạo một tác nhân bằng mô hình Sử dụng máy tính, bạn cần thiết lập một vòng lặp liên tục giữa ứng dụng và API. Sau đây là những việc mà mã của bạn sẽ làm ở mỗi bước:

  1. Gửi yêu cầu đến mô hình
    • Ứng dụng của bạn gửi một yêu cầu API có chứa công cụ Sử dụng máy tính, chế độ cài đặt cấu hình (chẳng hạn như môi trường mục tiêu), câu lệnh của người dùng và ảnh chụp màn hình hiện tại.
  2. Nhận câu trả lời của mô hình
    • Mô hình này phân tích màn hình và câu lệnh, trả về một phản hồi bao gồm function_call được đề xuất, đại diện cho một thao tác trên giao diện người dùng (chẳng hạn như lượt nhấp, lượt cuộn hoặc lượt nhấn phím).
    • Đối với các mô hình Gemini 3.x, câu trả lời cũng bao gồm một suy luận intent giải thích tại sao mô hình chọn hành động đó.
    • Phản hồi cũng có thể bao gồm một safety_decision từ hệ thống an toàn nội bộ phân loại hành động là thông thường/được phép, require_confirmation (yêu cầu người dùng phê duyệt) hoặc bị chặn.
  3. Thực hiện hành động đã nhận
    • Nếu hành động được phép (hoặc người dùng xác nhận hành động đó), mã phía máy khách của bạn sẽ phân tích cú pháp function_call, điều chỉnh tỷ lệ các toạ độ được chuẩn hoá cho phù hợp với khung hiển thị và thực thi hành động trong môi trường mục tiêu bằng các công cụ tự động hoá (chẳng hạn như Playwright). Nếu thao tác bị chặn, ứng dụng của bạn sẽ phải dừng thực thi hoặc xử lý gián đoạn.
  4. Chụp trạng thái môi trường mới
    • Sau khi thao tác hoàn tất, ứng dụng của bạn sẽ chụp một ảnh chụp màn hình mới và gửi lại cho mô hình trong function_result để yêu cầu bước tiếp theo.

Sau đó, quy trình này lặp lại từ bước 2, liên tục yêu cầu mô hình thực hiện hành động tiếp theo cho đến khi hoàn thành hoặc kết thúc nhiệm vụ.

Tổng quan về việc sử dụng máy tính

Cách triển khai tính năng Sử dụng máy tính

Trước khi tạo bằng công cụ Sử dụng máy tính, bạn cần thiết lập:

  • Môi trường thực thi an toàn: Chạy tác nhân của bạn trong một VM hoặc vùng chứa được đưa vào hộp cát để tách tác nhân đó khỏi hệ thống lưu trữ và hạn chế tác động tiềm ẩn của tác nhân. Triển khai tham chiếu bao gồm một hộp cát dựa trên Docker mà bạn có thể sử dụng ngay làm điểm xuất phát.
  • Trình xử lý thao tác phía máy khách: Triển khai logic phía máy khách để thực thi toạ độ, nhập văn bản và chụp ảnh màn hình.

Các ví dụ bên dưới sử dụng trình duyệt web làm môi trường thực thi và Playwright làm trình xử lý phía máy khách.

0. Thiết lập Playwright

Trước tiên, hãy cài đặt các gói bắt buộc:

pip install google-genai playwright
playwright install chromium

Sau đó, hãy khởi chạy một phiên bản trình duyệt Playwright để sử dụng cho quá trình thực thi:

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. Gửi yêu cầu đến mô hình

Khởi chạy thư viện ứng dụng và định cấu hình công cụ Sử dụng máy tính. Xin lưu ý rằng bạn không cần chỉ định kích thước màn hình khi đưa ra yêu cầu; mô hình sẽ dự đoán toạ độ pixel được điều chỉnh theo chiều cao và chiều rộng của màn hình.

Gemini 3.x

Python

Sử dụng google-genai Python SDK (phiên bản 2.7.0 trở lên) để định cấu hình một yêu cầu nhắm đến môi trường trình duyệt:

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)

JavaScript

Sử dụng SDK @google/genai Node.js để định cấu hình một yêu cầu nhắm đến môi trường trình duyệt:

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

Sử dụng curl để gửi yêu cầu:

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 (Phiên bản cũ)

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)

JavaScript

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. Nhận câu trả lời của mô hình

Mô hình phản hồi đề xuất một lệnh gọi hàm. Đối với các mô hình Gemini 3.x, phản hồi chứa ý định suy luận phù hợp cùng với toạ độ. Sau đây là ví dụ về cả hai phản hồi:

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 (Phiên bản cũ)

{
  "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. Thực thi các hành động đã nhận

Ứng dụng của bạn phải phân tích cú pháp toạ độ phản hồi, thực thi thao tác và điều chỉnh tỷ lệ các toạ độ đó từ toạ độ 1000x1000 được chuẩn hoá.

Đoạn mã dưới đây xử lý cả lệnh của công cụ cũ (click_at, type_text_at) và lệnh hiện đại được tinh giản (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

JavaScript

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 === "type_text_at") {
                const actualX = args.x !== undefined ? denormalizeX(args.x, screenWidth) : null;
                const actualY = args.y !== undefined ? denormalizeY(args.y, screenHeight) : null;
                const text = args.text;
                const pressEnter = args.press_enter || false;

                if (actualX !== null && actualY !== null) {
                    await page.mouse.click(actualX, actualY);
                }
                // Clear field first
                await page.keyboard.press("Meta+A");
                await page.keyboard.press("Backspace");
                await page.keyboard.type(text);
                if (pressEnter) {
                    await page.keyboard.press("Enter");
                }
            } else if (fname === "navigate") {
                await page.goto(args.url);
            } else if (fname === "go_back") {
                await page.goBack();
            } else if (fname === "go_forward") {
                await page.goForward();
            } else if (fname === "wait") {
                await new Promise(resolve => setTimeout(resolve, (args.seconds || 1) * 1000));
            } else {
                console.log(`Warning: Custom or unhandled function ${fname}`);
            }

            await page.waitForLoadState('load', { timeout: 5000 }).catch(() => {});
            await new Promise(resolve => setTimeout(resolve, 1000));
        } catch (e) {
            console.log(`Error executing ${fname}: ${e}`);
            actionResult.error = e.message;
        }

        results.push([fname, functionCall.id, actionResult]);
    }

    return results;
}

4. Ghi lại trạng thái môi trường mới

Sau khi thực hiện các hành động, hãy gửi kết quả thực thi hàm trở lại mô hình để mô hình có thể sử dụng thông tin này để tạo hành động tiếp theo. Aware If multiple actions (parallel calls) were executed, you must send a function_result for each one in the subsequent user turn.

Python

import json
import base64

def get_function_responses(page, results):
    screenshot_bytes = page.screenshot(type="png")
    current_url = page.url
    function_responses = []
    for name, call_id, result in results:
        function_responses.append({
            "type": "function_result",
            "name": name,
            "call_id": call_id,
            "result": [
                {
                    "type": "text",
                    "text": json.dumps({"url": current_url, **result})
                },
                {
                    "type": "image",
                    "data": base64.b64encode(screenshot_bytes).decode("utf-8"),
                    "mime_type": "image/png"
                }
            ]
        })
    return function_responses

JavaScript

async function getFunctionResponses(page, results) {
    const screenshotBuffer = await page.screenshot({ type: 'png' });
    const screenshotBase64 = screenshotBuffer.toString('base64');
    const currentUrl = page.url();
    const functionResponses = [];

    for (const [name, callId, result] of results) {
        functionResponses.push({
            type: "function_result",
            name: name,
            call_id: callId,
            result: [
                {
                    type: "text",
                    text: JSON.stringify({ url: currentUrl, ...result })
                },
                {
                    type: "image",
                    data: screenshotBase64,
                    mime_type: "image/png"
                }
            ]
        });
    }
    return functionResponses;
}

Sau khi xác định cách ghi lại và định dạng trạng thái môi trường, bạn có thể kết hợp tất cả các bước này thành một vòng lặp thực thi liên tục.

Tạo vòng lặp tác nhân

Để bật các lượt tương tác nhiều bước, hãy kết hợp 4 bước trong phần Cách triển khai việc sử dụng máy tính thành một vòng lặp duy nhất. Vòng lặp này tiếp tục yêu cầu các hành động và truyền kết quả trở lại mô hình cho đến khi hoàn tất nhiệm vụ.

acteriaHãy nhớ quản lý nhật ký cuộc trò chuyện một cách chính xác bằng cách thêm cả câu trả lời của mô hình và câu trả lời của hàm vào nhật ký ở mỗi bước.

Python

import time
from typing import Any, List, Tuple
from playwright.sync_api import sync_playwright

from google import genai

client = genai.Client()

# Constants for screen dimensions
SCREEN_WIDTH = 1440
SCREEN_HEIGHT = 900

# Setup Playwright
print("Initializing browser...")
playwright = sync_playwright().start()
browser = playwright.chromium.launch(headless=False)
context = browser.new_context(viewport={"width": SCREEN_WIDTH, "height": SCREEN_HEIGHT})
page = context.new_page()

# Define helper functions. Copy/paste from steps 3 and 4
# def denormalize_x(...)
# def denormalize_y(...)
# def execute_function_calls(...)
# def get_function_responses(...)

try:
    # Go to initial page
    page.goto("https://ai.google.dev/gemini-api/docs")

    # Take initial screenshot
    initial_screenshot = page.screenshot(type="png")
    USER_PROMPT = "Go to ai.google.dev/gemini-api/docs and search for pricing."
    print(f"Goal: {USER_PROMPT}")

    # First interaction
    interaction = client.interactions.create(
        model='gemini-3.7-flash',
        input=[
            {"type": "text", "text": USER_PROMPT},
            {"type": "image", "data": base64.b64encode(initial_screenshot).decode("utf-8"), "mime_type": "image/png"}
        ],
        tools=[{
            "type": "computer_use",
            "environment": "browser",