使用电脑

借助 Gemini 的计算机使用工具,您可以构建浏览器、移动设备和桌面设备控制智能体,这些智能体可与图形界面 (GUI) 交互并自动执行任务。启用计算机使用功能后,模型会使用屏幕截图来观察屏幕,并通过生成特定的界面操作(例如鼠标点击、滚动和键盘输入)来执行操作。

Gemini 支持多项高级计算机使用功能:

  • 多环境支持:为浏览器、移动和桌面环境构建智能体。
  • 通过 intent 简化操作:操作包含一个 intent 字段,用于解释模型在每个步骤背后的推理。
  • 可配置的安全政策:使用内置政策类别和替换项微调安全行为。
  • 提示词注入检测:选择启用屏幕截图扫描功能,以检测隐藏的对抗性指令。

您可以利用计算机使用功能构建能够执行以下操作的智能体:

  • 自动执行跨网站和桌面应用的数据录入或表单填写等重复性任务。
  • 对 Web、移动和桌面用户体验流程执行自动化测试。
  • 浏览网站和应用以收集研究信息(例如,比较商品信息、价格和评价)。
  • 通过跨应用执行多步骤操作序列来协助用户。

本指南包括:

与函数调用类似,您需要编写客户端应用代码,以接收计算机使用函数调用并执行相应操作。

本指南假定您使用的是 Google Gen AI SDK for Python,并且熟悉 Playwright API。

您可以在 GitHub 上找到计算机使用的参考实现。

支持的模型

以下模型支持计算机使用功能:

点击即可展开支持的模型

计算机使用功能的运作方式

计算机使用功能不会生成文本回答,而是确定何时执行特定的界面操作(例如鼠标点击),并返回执行这些操作所需的参数。您需要编写客户端应用代码,以接收计算机使用 function_call 并执行相应操作。

计算机使用互动遵循智能体循环流程:

  1. 向模型发送请求

    • 将计算机使用(以及任何其他可选工具)添加到您的 API 请求中。
    • 向模型发送提示,其中包含用户的请求和表示 GUI 当前状态的屏幕截图。
  2. 接收模型回答

    • 模型会分析用户请求和屏幕截图,并生成一个回答,其中包含一个表示界面操作(例如“点击坐标 (x,y)”或“输入‘文本’”)的建议 function_call。如需查看可与模型搭配使用的所有操作的列表,请参阅支持的操作。
    • API 响应还可能包含来自内部安全系统的 safety_decision,该系统已检查模型建议的操作。此 safety_decision 会将操作分类为:
      • 常规或允许:该操作被视为安全。这也可以通过不存在 safety_decision 来表示。
      • 需要确认:模型即将执行可能存在风险的操作(例如,点击“接受 Cookie 横幅”)。
  3. 执行收到的操作

    • 您的客户端代码会收到 function_call 以及任何随附的 safety_decision。
    • 如果 safety_decision 指示常规或允许(或者如果不存在 safety_decision),您的客户端代码可以在目标环境(例如网络浏览器)中执行指定的 function_call。
    • 如果 safety_decision 指示需要确认,则您的应用必须在执行 function_call 之前提示最终用户进行确认。如果用户确认,则继续执行操作。如果用户拒绝,请勿执行该操作。
  4. 捕获新环境状态

    • 如果操作已执行,客户端会捕获 GUI 和当前网址的新屏幕截图,并将其作为 function_response 的一部分发送回模型。
    • 如果某项操作被安全系统屏蔽或用户拒绝确认,您的应用可能会向模型发送其他形式的反馈,或结束互动。

系统会向模型发送一个包含更新后状态的新请求。该过程会从第 2 步开始重复,模型会使用新的屏幕截图(如果提供)和正在进行的目标来建议下一步操作。循环会一直持续,直到任务完成、发生错误或进程终止(例如,如果回答被安全过滤器或用户决定屏蔽)。

下图说明了计算机使用功能的运作方式:

流程图,展示了循环的计算机使用互动循环。首先是“初始任务”,然后是“屏幕截图 + 之前的上下文”。第 1 步:“向模型发送请求”将此数据发送到“模型”。第 2 步:“接收模型回答”将操作传递给“计算机环境(客户端应用)”。第 3 步:
“执行收到的操作”会更新“计算机环境(客户端应用)”。
第 4 步:“捕获新环境状态”会将更新后的屏幕截图和上下文反馈回循环的开头。

启用“操作电脑”

如需启用计算机使用功能,请确保您的应用使用的是受支持的模型之一,并将计算机使用功能添加到已启用工具的列表中:

Python

from google import genai
from google.genai import types
from google.genai.types import Content, Part

client = genai.Client(
    enterprise=True,
    project="PROJECT_ID",
    location="global",
)

# Add computer use to the list of tools
generate_content_config = types.GenerateContentConfig(
    tools=[
        types.Tool(
            computer_use=types.ComputerUse(
                environment=types.Environment.ENVIRONMENT_BROWSER,
            )
        ),
    ]
)

contents = [
    Content(
        role="user",
        parts=[
            Part(text="Go to google.com and search for 'weather in New York'"),
        ],
    )
]

response = client.models.generate_content(
    model="gemini-3.8-flash",
    contents=contents,
    config=generate_content_config,
)
print(response)
      

Node.js

import { GoogleGenAI, Environment } from '@google/genai';

const ai = new GoogleGenAI({
  enterprise: true,
  project: 'PROJECT_ID',
  location: 'global',
});

const response = await ai.models.generateContent({
  model: 'gemini-3.8-flash',
  contents: "Go to google.com and search for 'weather in New York'",
  config: {
    tools: [
      {
        computerUse: {
          environment: Environment.ENVIRONMENT_BROWSER,
        },
      },
    ],
  },
});

console.log(response);
      

REST API

curl -X POST "https://aiplatform.googleapis.com/v1/projects/PROJECT_ID/locations/global/publishers/google/models/gemini-3.8-flash:generateContent" \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "Content-Type: application/json" \
  -d '{
    "contents": [
      {
        "role": "user",
        "parts": [
          {
            "text": "Go to google.com and search for '\''weather in New York'\''"
          }
        ]
      }
    ],
    "tools": [
      {
        "computer_use": {
          "environment": "ENVIRONMENT_BROWSER"
        }
      }
    ]
  }'
      

设置执行环境

在使用计算机使用工具进行构建之前,请先设置:

  • 安全的执行环境:在沙盒化虚拟机 (VM) 或容器(例如 Docker)中运行智能体,使其与主机系统隔离。
  • 客户端操作处理程序:实现客户端逻辑,以执行鼠标点击、键盘击键和屏幕截图。

首先,安装 SDK 和浏览器依赖项,然后配置环境:

pip install --upgrade google-genai playwright termcolor
playwright install chromium

export GOOGLE_CLOUD_PROJECT="PROJECT_ID"
export GOOGLE_CLOUD_LOCATION="global"
export GOOGLE_GENAI_USE_ENTERPRISE=True

接下来,使用明确的视口尺寸初始化 Playwright 浏览器实例,以便准确缩放标准化坐标 (0-1000):

from playwright.sync_api import sync_playwright

SCREEN_WIDTH = 1440
SCREEN_HEIGHT = 900

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()
page.goto("https://www.google.com")

发送请求

配置计算机使用工具后,向模型发送提示,其中包含用户的目标和 GUI 的初始屏幕截图。

您还可以选择添加以下内容:

  • 排除的操作:如果支持的界面操作列表中有您不希望模型执行的操作,请在 excluded_predefined_functions 中指定这些操作。
  • 用户定义的函数:除了计算机使用之外,您可能还想添加自定义的用户定义的函数。

以下示例代码可启用计算机使用功能,并将请求发送给该模型:

Python

from google import genai
from google.genai import types
from google.genai.types import Content, Part

client = genai.Client()

# Specify predefined functions to exclude (optional)
excluded_functions = ["drag_and_drop"]

# Configuration for computer use with browser environment
generate_content_config = genai.types.GenerateContentConfig(
    tools=[
        # 1. Computer Use tool with browser environment
        types.Tool(
            computer_use=types.ComputerUse(
                environment=types.Environment.ENVIRONMENT_BROWSER,
                # Optional: Exclude specific predefined functions
                excluded_predefined_functions=excluded_functions
                )
              ),
        # 2. Optional: Custom user-defined functions (need to defined above)
        # types.Tool(
           # function_declarations=custom_functions
           #   )
    ],
)

# Create the content with user message
contents: list[Content] = [
    Content(
        role="user",
        parts=[
            Part(text="Search for highly rated smart fridges with touchscreen, 2 doors, around 25 cu ft, priced below 4000 dollars on Google Shopping. Create a bulleted list of the 3 cheapest options in the format of name, description, price in an easy-to-read layout."),
            # Optional: include a screenshot of the initial state
            # Part.from_bytes(
                 # data=screenshot_image_bytes,
                 # mime_type='image/png',
            # ),
        ],
    )
]

# Generate content with the configured settings
response = client.models.generate_content(
    model='gemini-3.8-flash',
    contents=contents,
    config=generate_content_config,
)

# Print the response output
print(response.text)
      

您还可以添加自定义的用户定义的函数,以扩展模型的功能。如需了解如何通过添加 open_app、long_press_at 和 go_home 等操作来配置移动用例的计算机使用,同时排除特定于浏览器的操作,请参阅 Gemini 3.5 Flash 或更高版本以及移动或桌面用例。

接收回复

如果模型确定需要执行界面操作或用户定义的函数才能完成任务,则会返回一个或多个 FunctionCalls。您的应用代码需要解析这些操作、执行这些操作并收集结果。计算机使用功能支持并行函数调用,这意味着模型可以在单轮对话中返回多个独立的操作。

对于 Gemini 3.5 Flash 及更高版本的模型,每个操作都包含一个 intent 实参,用于解释模型执行该步骤背后的推理:

{
  "content": {
    "parts": [
      {
        "function_call": {
          "name": "type",
          "args": {
            "x": 450,
            "y": 320,
            "text": "smart fridge touchscreen 2 doors 25 cu ft under $4000",
            "press_enter": true,
            "intent": "Type the search query into the Google search box and submit."
          }
        }
      }
    ]
  }
}

根据操作,API 响应可能还会在函数调用参数中返回 safety_decision:

{
  "content": {
    "parts": [
      {
        "function_call": {
          "name": "click",
          "args": {
            "x": 60,
            "y": 100,
            "intent": "Click the 'I'm not a robot' verification checkbox.",
            "safety_decision": {
              "explanation": "I have encountered a CAPTCHA challenge that requires interaction. I need you to complete the challenge by clicking the 'I'm not a robot' checkbox and any subsequent verification steps.",
              "decision": "require_confirmation"
            }
          }
        }
      }
    ]
  }
}

执行收到的操作

收到响应后,解析 function_call,将坐标从归一化的 0-1000 网格缩放到实际视口像素尺寸,然后执行操作:

import time
from typing import Any, Dict, List, Tuple
import termcolor


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 get_safety_confirmation(safety_decision: Dict[str, Any]) -> str:
    """Prompt user for confirmation when safety check is triggered."""
    termcolor.cprint("Safety service requires explicit confirmation!", color="red")
    print(safety_decision.get("explanation", ""))

    decision = ""
    while decision.lower() not in ("y", "n", "ye", "yes", "no"):
        decision = input("Do you wish to proceed? [Y]es/[N]o\n")

    if decision.lower() in ("n", "no"):
        return "TERMINATE"
    return "CONTINUE"


def execute_function_calls(
    response, page, screen_width: int, screen_height: int
) -> List[Tuple[str, Dict[str, Any]]]:
    """Extract and execute modern and legacy function calls from Gemini response."""
    candidate = response.candidates[0]
    function_calls = []
    thoughts = []

    for part in candidate.content.parts:
        if hasattr(part, "function_call") and part.function_call:
            function_calls.append(part.function_call)
        elif hasattr(part, "text") and part.text:
            thoughts.append(part.text)

    if thoughts:
        print(f"Model Reasoning: {' '.join(thoughts)}")

    results: List[Tuple[str, Dict[str, Any]]] = []
    for function_call in function_calls:
        fname = function_call.name
        args = function_call.args or {}
        action_result: Dict[str, Any] = {}

        print(f" -> Executing: {fname} (Intent: {args.get('intent', 'N/A')})")

        # Check for safety decision before executing
        if "safety_decision" in args:
            decision = get_safety_confirmation(args["safety_decision"])
            if decision == "TERMINATE":
                print("Terminating agent loop")
                break
            action_result["safety_acknowledgement"] = "true"

        try:
            if fname in ("open_web_browser", "open_app", "take_screenshot"):
                pass

            elif fname in (
                "click",
                "click_at",
                "double_click",
                "triple_click",
                "middle_click",
                "right_click",
                "mouse_down",
                "mouse_up",
                "move",
                "hover_at",
            ):
                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 == "triple_click":
                    page.mouse.click(actual_x, actual_y, click_count=3)
                elif fname == "middle_click":
                    page.mouse.click(actual_x, actual_y, button="middle")
                elif fname == "right_click":
                    page.mouse.click(actual_x, actual_y, button="right")
                elif fname == "mouse_down":
                    page.mouse.move(actual_x, actual_y)
                    page.mouse.down()
                elif fname == "mouse_up":
                    page.mouse.move(actual_x, actual_y)
                    page.mouse.up()
                elif fname in ("move", "hover_at"):
                    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)
                clear_before_typing = args.get("clear_before_typing", True)

                if actual_x is not None and actual_y is not None:
                    page.mouse.click(actual_x, actual_y)
                    time.sleep(0.1)

                if clear_before_typing:
                    page.keyboard.press("ControlOrMeta+A")
                    page.keyboard.press("Backspace")

                page.keyboard.type(text)
                if press_enter:
                    page.keyboard.press("Enter")

            elif fname in ("scroll", "scroll_at", "scroll_document"):
                if "x" in args and "y" in args:
                    page.mouse.move(denormalize_x(args["x"], screen_width), denormalize_y(args["y"], screen_height))
                direction = args.get("direction", "down")
                magnitude = args.get("magnitude_in_pixels", args.get("magnitude", 300))
                dx, dy = 0, 0
                if direction == "down":
                    dy = magnitude
                elif direction == "up":
                    dy = -magnitude
                elif direction == "right":
                    dx = magnitude
                elif direction == "left":
                    dx = -magnitude
                page.mouse.wheel(dx, dy)

            elif fname == "drag_and_drop":
                start_x = denormalize_x(args.get("start_x", args.get("x", 0)), screen_width)
                start_y = denormalize_y(args.get("start_y", args.get("y", 0)), screen_height)
                end_x = denormalize_x(args.get("end_x", args.get("destination_x", 0)), screen_width)
                end_y = denormalize_y(args.get("end_y", args.get("destination_y", 0)), screen_height)
                page.mouse.move(start_x, start_y)
                page.mouse.down()
                page.mouse.move(end_x, end_y)
                page.mouse.up()

            elif fname == "press_key":
                page.keyboard.press(args["key"])
            elif fname == "key_down":
                page.keyboard.down(args["key"])
            elif fname == "key_up":
                page.keyboard.up(args["key"])
            elif fname == "hotkey":
                page.keyboard.press("+".join(args.get("keys", [])))
            elif fname == "key_combination":
                page.keyboard.press(args["keys"])
            elif fname == "navigate":
                page.goto(args["url"])
            elif fname == "search":
                page.goto("https://www.google.com")
            elif fname == "go_back":
                page.go_back()
            elif fname == "go_forward":
                page.go_forward()
            elif fname in ("wait", "wait_5_seconds"):
                time.sleep(5 if fname == "wait_5_seconds" else args.get("seconds", 1))
            else:
                action_result["warning"] = f"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, action_result))

    return results

如果返回的 safety_decision 为 require_confirmation,您必须先让用户确认,然后才能继续执行操作。根据服务条款,您不得绕过人工确认请求。

捕获新状态

执行操作后,将每个操作结果和更新后的屏幕截图打包到 FunctionResponse 中,以返回给模型:

from google.genai import types
from google.genai.types import Content, FunctionResponse, Part


def get_function_responses(
    page, results: List[Tuple[str, Dict[str, Any]]]
) -> Content:
    """Capture screenshot and URL and package them as FunctionResponses."""
    screenshot = page.screenshot(type="png")
    current_url = page.url
    function_response_parts = []

    for name, action_result in results:
        function_response_parts.append(
            Part(
                function_response=FunctionResponse(
                    name=name,
                    response={
                        "url": current_url,
                        **action_result,
                    },
                    parts=[
                        types.FunctionResponsePart(
                            inline_data=types.FunctionResponseBlob(
                                mime_type="image/png",
                                data=screenshot,
                            )
                        )
                    ],
                )
            )
        )

    return Content(
        role="user",
        parts=function_response_parts,
    )

构建智能体循环

将这些步骤组合成一个端到端循环,在模型和执行环境之间持续迭代:

Python

from google import genai
from google.genai import types
from google.genai.types import Content, Part
from playwright.sync_api import sync_playwright

def has_function_calls(response) -> bool:
    """Check if model response contains any function calls."""
    candidate = response.candidates[0]
    return any(
        hasattr(part, "function_call") and part.function_call
        for part in candidate.content.parts
    )

def main():
    client = genai.Client(
        enterprise=True,
        project="PROJECT_ID",
        location="global",
    )

    generate_content_config = types.GenerateContentConfig(
        tools=[
            types.Tool(
                computer_use=types.ComputerUse(
                    environment=types.Environment.ENVIRONMENT_BROWSER,
                    enable_prompt_injection_detection=True,
                )
            )
        ],
    )

    screen_width, screen_height = 1440, 900

    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        context = browser.new_context(
            viewport={"width": screen_width, "height": screen_height}
        )
        page = context.new_page()
        page.goto("https://www.google.com")

        initial_screenshot = page.screenshot(type="png")
        contents: list[Content] = [
            Content(
                role="user",
                parts=[
                    Part(text="Search for flights from San Francisco to Honolulu departing June 30 and returning July 6."),
                    Part.from_bytes(data=initial_screenshot, mime_type="image/png"),
                ],
            )
        ]

        # Agent loop: iterate until model provides a final text response
        for iteration in range(10):
            print(f"\n--- Iteration {iteration + 1} ---")

            response = client.models.generate_content(
                model="gemini-3.8-flash",
                contents=contents,
                config=generate_content_config,
            )

            contents.append(response.candidates[0].content)

            if not has_function_calls(response):
                print(f"FINAL RESPONSE:\n{response.text}")
                break

            results = execute_function_calls(response, page, screen_width, screen_height)
            if not results:
                break

            user_feedback_content = get_function_responses(page, results)
            contents.append(user_feedback_content)

        browser.close()

if __name__ == "__main__":
    main()
      

Gemini 3.5 Flash 或更高版本以及移动设备或桌面设备应用场景

计算机使用支持设置移动设备 (ENVIRONMENT_MOBILE)、桌面设备 (ENVIRONMENT_DESKTOP) 或浏览器 (ENVIRONMENT_BROWSER) 环境。默认值为 ENVIRONMENT_BROWSER。

以下示例演示了如何为 Gemini 3.5 Flash 或更高版本的 Computer Use 配置执行环境:

REST API

在使用任何请求数据之前,请先进行以下替换:

  • PROJECT_ID:您的项目 ID。

HTTP 方法和网址:

POST https://aiplatform.googleapis.com/v1/projects/PROJECT_ID/locations/global/publishers/google/models/gemini-3.5-flash:generateContent

请求 JSON 正文:

{
  "contents": [
    {
      "role": "user",
      "parts": {
        "text": "find me a flight from SF to Hawaii on Jun 30th, coming back on Jul 6th. start by navigating directly to flights.google.com"
      }
    }
  ],
  "generation_config": {
    "candidateCount": 1
  },
  "tools": [
    {
      "computer_use": {
        "environment": "ENVIRONMENT_BROWSER"
      }
    }
  ]
}

如需发送您的请求,请展开以下选项之一:

您应该会收到一个成功的状态代码 (2xx) 和一个空响应。

Python

以下示例需要 python-genai 2.7.0 版或更高版本。

from google import genai
from google.genai.types import (
    Part,
    GenerateContentConfig,
    Content,
    Tool,
    ComputerUse,
    Environment,
    ThinkingConfig,
)
client = genai.Client()

response = client.models.generate_content(
    model="gemini-3.6-flash",
    contents=[
        Content(
            role="user",
            parts=[
                Part(text="find me a flight from SF to Hawaii on Jun 30th, coming back on Jul 6th"),
            ],
        )
    ],
    config=GenerateContentConfig(
        temperature=1,
        top_p=0.95,
        top_k=40,
        max_output_tokens=8192,
        tools=[
            Tool(
                computer_use=ComputerUse(
                    environment=Environment.ENVIRONMENT_MOBILE
                ),
            ),
        ],
        thinking_config=ThinkingConfig(
            include_thoughts=True
        ),
    )
)

自定义用户定义的函数

您可以将 computer_use 与自定义用户定义的函数 (function_declarations) 结合使用,以扩展模型的功能。例如,在人机协同 (HITL) 场景中,您可以使用 excluded_predefined_functions 排除特定的预定义操作,并注册自定义 yield_to_user 函数,以便代理在遇到 2FA 提示或不明确的屏幕时可以将控制权交还给人工:

Python

from google import genai
from google.genai import types
from google.genai.types import Content, Part

client = genai.Client()

def yield_to_user(reason: str) -> dict[str, str]:
    """Yields control back to the user for assistance or verification when an automated action is unsafe or ambiguous.

    Args:
        reason: The reason why the agent is yielding control to the human.
    """
    return {"status": "yielded", "reason": reason}

generate_content_config = types.GenerateContentConfig(
    tools=[
        types.Tool(
            computer_use=types.ComputerUse(
                environment=types.Environment.ENVIRONMENT_BROWSER,
                excluded_predefined_functions=["drag_and_drop"],
            )
        ),
        types.Tool(
            function_declarations=[
                types.FunctionDeclaration.from_callable(
                    client=client, callable=yield_to_user
                )
            ]
        ),
    ]
)

response = client.models.generate_content(
    model="gemini-3.8-flash",
    contents=[
        Content(
            role="user",
            parts=[
                Part(
                    text="Click the submit button. If you need a second-factor authentication code, ask me."
                ),
            ],
        )
    ],
    config=generate_content_config,
)
print(response)
      

支持的操作

计算机使用工具使模型能够使用 FunctionCall 请求以下操作。您的客户端代码必须实现这些操作的执行逻辑。如需查看示例,请参阅参考实现。下表列出了浏览器环境支持的操作。 Gemini 3 Flash 和 Gemini 3.5 Flash 或更高版本的模型具有不同的 FunctionCall 名称集。

Gemini 3.5 Flash 或更高版本

Gemini 3.5 Flash:您可以访问不同的函数调用集,具体取决于您选择的环境:

浏览器环境

命令名称 说明 参数(在函数调用中)
click 在指定坐标处左键点击。 y:int (0-999)
x:int (0-999)
intent:str
double_click 在指定坐标处双击。 y:int (0-999)
x:int (0-999)
intent:str
triple_click 在指定坐标处连击三次。 y:int (0-999)
x:int (0-999)
intent:str
middle_click 在指定坐标处中键点击。 y:int (0-999)
x:int (0-999)
intent:str
right_click 在指定坐标处右键点击。 y:int (0-999)
x:int (0-999)
intent:str
mouse_down 在相应坐标处按住鼠标按键。 y:int (0-999)
x:int (0-999)
intent:str
mouse_up 在指定坐标处松开鼠标按键。 y:int (0-999)
x:int (0-999)
intent:str
move 将光标移至指定位置。 y:int (0-999)
x:int (0-999)
intent:str
type 输入文本(可选择先点击 x、y)。 y:int(0-999,可选)
x:int(0-999,可选)
text:str
press_enter:bool(可选,默认值为 false)
intent:str
drag_and_drop 将某个内容从 (start_x, start_y) 拖动到 (end_x, end_y)。 start_y:int (0-999)
start_x:int (0-999)
end_y:int (0-999)
end_x:int (0-999)
intent:str
wait 等待指定的秒数。 seconds:int(可选,默认值为 1)
intent:str
press_key 按下并松开指定按键。 key:str
intent:str
key_down 按住指定键。 key:str
intent:str
key_up 释放指定的键。 key:str
intent:str
hotkey 按下指定的组合键。 keys:List[str]
intent:str
take_screenshot 返回当前屏幕的屏幕截图。 intent:str
scroll 在某个坐标处向上、向下、向左或向右滚动一定像素距离。 y:int (0-999)
x:int (0-999)
direction:str(“up”“down”“left”“right”)
magnitude_in_pixels:int(0-999,可选,默认值为 300)
intent:str
open_web_browser 打开网络浏览器。 intent:str
navigate 让浏览器直接转到指定的网址。 url:str
intent:str
go_back 返回浏览器历史记录中的上一个网页。 intent:str
go_forward 在浏览器浏览记录中向前导航到下一个网页。 intent:str

移动环境

命令名称 说明 参数(在函数调用中)
open_app 按名称打开应用。 intent: str
click 在坐标处左键点击。 y:int (0-999)
x:int (0-999)
intent:str
list_apps 列出设备上的可用应用,并返回其名称和软件包名称。 intent:str
wait 等待指定的秒数。 intent:str
seconds:int(可选,默认值为 1)
go_back 返回浏览器历史记录中的上一个网页。 intent:str
type 输入文字。 text:str
intent:str
press_enter:bool(可选,默认值为 false)
drag_and_drop 将内容从 start_y 和 start_x 拖动到 end_y 和 end_x start_y:int (0-999)
start_x:int (0-999)
end_y:int (0-999)
end_x:int (0-999)
intent:str
long_press 在屏幕上的特定 y (0-999)、x (0-999) 坐标处执行长按操作。 y:int (0-999)
x:int (0-999)
intent:str
seconds:int(可选,默认值为 2)
press_key 按下并松开指定按键。 key:str
intent:str
take_screenshot 返回当前屏幕的屏幕截图。 intent:str

桌面环境

命令名称 说明 参数(在函数调用中)
click 在坐标处左键点击。 y:int (0-999)
x:int (0-999)
intent:str
double_click 双击坐标。 y:int (0-999)
x:int (0-999)
intent:str
triple_click 在坐标处连击三次。 y:int (0-999)
x:int (0-999)
intent:str
middle_click 在坐标处点击鼠标中键。 y:int (0-999)
x:int (0-999)
intent:str
right_click 右键点击坐标。 y:int (0-999)
x:int (0-999)
intent:str
mouse_down 在相应坐标处按住鼠标按键。 y:int (0-999)
x:int (0-999)
intent:str
mouse_up 在指定坐标处松开鼠标按键。 y:int (0-999)
x:int (0-999)
intent:str
move 将光标移至指定位置。 y:int (0-999)
x:int (0-999)
intent:str
type 输入文字。 text:str
intent:str
press_enter:bool(可选,默认值为 false)
drag_and_drop 将内容从 start_y 和 start_x 拖动到 end_y 和 end_x。 start_y:int (0-999)
start_x:int (0-999)
end_y:int (0-999)
end_x:int (0-999)
intent:str
wait 等待指定的秒数。 intent:str
seconds:int(可选,默认值为 1)
press_key 按下并松开指定按键。 key:str
intent:str
key_down 按住指定键。 key:str
intent:str
key_up 释放指定的键。 key:str
intent:str
hotkey 按下指定的组合键。 keys:List[str]
intent:str
take_screenshot 返回当前屏幕的屏幕截图。 intent:str
scroll 在某个坐标处向上、向下、向左或向右滚动一段像素距离。 y:int (0-999)
x:int (0-999)
direction:str(“up”、“down”、“left”、“right”)
intent:str
magnitude_in_pixels:int(0-999,可选,默认值为 300)

Gemini 3 Flash

命令名称 说明 参数(在函数调用中) 函数调用示例
open_web_browser 打开网络浏览器。 无 {"name": "open_web_browser", "args": {}}
wait_5_seconds 暂停执行 5 秒,以便加载动态内容或完成动画。 无 {"name": "wait_5_seconds", "args": {}}
go_back 前往浏览器历史记录中的上一页。 无 {"name": "go_back", "args": {}}
go_forward 前往浏览器历史记录中的下一页。 无 {"name": "go_forward", "args": {}}
search 前往默认搜索引擎(例如 Google)的首页。适用于启动新的搜索任务。 无 {"name": "search", "args": {}}
navigate 让浏览器直接转到指定的网址。 url:str {"name": "navigate", "args": {"url": "https://www.wikipedia.org"}}
click_at 点击网页上的特定坐标。x 值和 y 值基于 1000x1000 网格,并会根据屏幕尺寸进行缩放。 y:int (0-999),x:int (0-999) {"name": "click_at", "args": {"y": 300, "x": 500}}
hover_at 521963309 将鼠标悬停在网页上的特定坐标处。适用于显示子菜单。x 和 y 基于 1000x1000 网格。 y:int (0-999),x:int (0-999) {"name": "hover_at", "args": {"y": 150, "x": 250}}
type_text_at 在特定坐标处输入文本,默认情况下会先清除字段,并在输入后按 Enter 键,但这些操作可以停用。x 和 y 基于 1000x1000 网格。 y:int (0-999),x:int (0-999),text:str,press_enter:bool(可选,默认值为 True),clear_before_typing:bool(可选,默认值为 True) {"name": "type_text_at", "args": {"y": 250, "x": 400, "text": "search query", "press_enter": false}}
key_combination 按下键盘按键或组合键,例如“Control+C”或“Enter”。适用于触发操作(例如按“Enter”键提交表单)或剪贴板操作。 keys:str(例如“enter”“control+c”)。如需查看允许的键的完整列表,请参阅 API 参考文档 {"name": "key_combination", "args": {"keys": "Control+A"}}
scroll_document 将整个网页“向上”“向下”“向左”或“向右”滚动。 direction:str(“up”“down”“left”或“right”) {"name": "scroll_document", "args": {"direction": "down"}}
scroll_at 在坐标 (x, y) 处,按指定方向和一定幅度滚动特定元素或区域。坐标和幅度(默认值为 800)基于 1000x1000 的网格。 y:int (0-999),x:int (0-999),direction:str(“up”“down”“left”“right”),magnitude:int(0-999,可选,默认值为 800) {"name": "scroll_at", "args": {"y": 500, "x": 500, "direction": "down", "magnitude": 400}}
drag_and_drop 将元素从起始坐标 (x, y) 拖动到目标坐标 (destination_x, destination_y) 并放置。所有坐标均基于 1000x1000 的网格。 y:int (0-999),x:int (0-999),destination_y:int (0-999),destination_x:int (0-999) {"name": "drag_and_drop", "args": {"y": 100, "x": 100, "destination_y": 500, "destination_x": 500}}

安全

本部分介绍了计算机使用工具为提高用户控制力和安全性而采取的保护措施。此外,还介绍了缓解该工具可能带来的潜在新风险的最佳实践。

确认安全决策

根据操作,模型的回答可能包含来自内部安全系统的 safety_decision。此决策会验证工具建议的操作是否安全。

{
  "content": {
    "parts": [
      {
        "text": "I have evaluated step 2. It seems Google detected unusual traffic and is asking me to verify I'm not a robot. I need to click the 'I'm not a robot' checkbox located near the top left (y=98, x=95)."
      },
      {
        "function_call": {
          "name": "click_at",
          "args": {
            "x": 60,
            "y": 100,
            "safety_decision": {
              "explanation": "I have encountered a CAPTCHA challenge that requires interaction. I need you to complete the challenge by clicking the 'I'm not a robot' checkbox and any subsequent verification steps.",
              "decision": "require_confirmation"
            }
          }
        }
      }
    ]
  }
}

如果 safety_decision 为 require_confirmation,则您必须先要求最终用户确认,然后才能继续执行操作。

以下代码示例会在执行操作之前提示最终用户进行确认。如果用户未确认操作,循环就会终止。如果用户确认该操作,系统会执行该操作,并将 safety_acknowledgement 字段标记为 True。

import termcolor

def get_safety_confirmation(safety_decision):
    """Prompt user for confirmation when safety check is triggered."""
    termcolor.cprint("Safety service requires explicit confirmation!", color="red")
    print(safety_decision["explanation"])

    decision = ""
    while decision.lower() not in ("y", "n", "ye", "yes", "no"):
        decision = input("Do you wish to proceed? [Y]es/[N]o\n")

    if decision.lower() in ("n", "no"):
        return "TERMINATE"
    return "CONTINUE"

def execute_function_calls(response, page, screen_width: int, screen_height: int):

    # ... Extract function calls from response ...

    for function_call in function_calls:
        extra_fr_fields = {}

        # Check for safety decision
        if 'safety_decision' in function_call.args:
            decision = get_safety_confirmation(function_call.args['safety_decision'])
            if decision == "TERMINATE":
                print("Terminating agent loop")
                break
            extra_fr_fields["safety_acknowledgement"] = "true" # Safety acknowledgement

        # ... Execute function call and append to results ...

如果用户确认,您必须在 FunctionResponse 中添加安全确认。

function_response_parts.append(
    FunctionResponse(
        name=name,
        response={"url": current_url,
                  **extra_fr_fields},  # Include safety acknowledgement
        parts=[
            types.FunctionResponsePart(
                inline_data=types.FunctionResponseBlob(
                    mime_type="image/png", data=screenshot
                )
             )
           ]
         )
       )

提示注入检测

Gemini 3.5 Flash 或更高版本中的计算机使用功能支持高级安全机制,可检测提示词注入攻击。启用后,此功能会检查添加的屏幕截图是否有可能引入提示词注入攻击。您可以在计算机使用配置中设置此功能。默认值为 false。

以下示例演示了如何启用计算机使用配置,以启用提示词注入检测:

REST API

在使用任何请求数据之前,请先进行以下替换:

  • PROJECT_ID:您的项目 ID。

HTTP 方法和网址:

POST https://aiplatform.googleapis.com/v1/projects/PROJECT_ID/locations/global/publishers/google/models/gemini-3.5-flash:generateContent

请求 JSON 正文:

{
  "contents": [
    {
      "role": "user",
      "parts": {
        "text": "find me a flight from SF to Hawaii on Jun 30th, coming back on Jul 6th. start by navigating directly to flights.google.com"
      }
    }
  ],
  "generation_config": {
    "candidateCount": 1
  },
  "tools": [
    {
      "computer_use": {
        "environment": "ENVIRONMENT_BROWSER",
        "enable_prompt_injection_detection": true
      }
    }
  ]
}

如需发送您的请求,请展开以下选项之一:

您应该会收到一个成功的状态代码 (2xx) 和一个空响应。

Python

以下示例需要 python-genai 2.7.0 版或更高版本。

from google import genai
from google.genai.types import (
    Part,
    GenerateContentConfig,
    Content,
    Tool,
    ComputerUse,
    Environment,
    ThinkingConfig,
)
client = genai.Client()

response = client.models.generate_content(
    model="gemini-3.6-flash",
    contents=[
        Content(
            role="user",
            parts=[
                Part(text="find me a flight from SF to Hawaii on Jun 30th, coming back on Jul 6th"),
            ],
        )
    ],
    config=GenerateContentConfig(
        temperature=1,
        top_p=0.95,
        top_k=40,
        max_output_tokens=8192,
        tools=[
            Tool(
                computer_use=ComputerUse(
                    environment=Environment.ENVIRONMENT_MOBILE,
                    enable_prompt_injection_detection=True
                ),
            ),
        ],
        thinking_config=ThinkingConfig(
            include_thoughts=True
        ),
    )
)

安全最佳实践

使用计算机存在一些风险,开发者应注意以下几点:

  • 不可信的内容和欺骗手段:当模型尝试实现用户的目标时,可能会依赖不可信的信息来源和屏幕上的指令。
  • 偶尔执行非预期操作:模型可能会误解用户的目标或网页内容,从而导致其执行错误的操作,例如点击错误的按钮或填写错误的表单。
  • 违反政策:该 API 的功能可能会被用于违反 Google 条款和政策的活动,例如绕过人机识别系统或破坏系统完整性。

为应对这些风险,您应实施以下安全措施和最佳实践:

  1. 人机协同 (HITL):
    • 实现用户确认:当安全响应指示 require_confirmation 时,您必须在执行前实现用户确认。
    • 提供自定义安全说明:除了内置的用户确认检查之外,开发者还可以选择添加自定义系统说明,以强制执行自己的安全政策,从而阻止某些模型操作,或要求用户在模型执行某些高风险不可逆操作之前进行确认。

    点击即可查看自定义安全系统指令示例

    ## **RULE 1: Seek User Confirmation (USER_CONFIRMATION)**
    
    This is your first and most important check. If the next required action falls
    into any of the following categories, you MUST stop immediately, and seek the
    user's explicit permission.
    
    **USER_CONFIRMATION Categories:**
    *   **Consent and Agreements:** Terms of Service, Privacy Policies, Cookie banners.
    *   **Robot Detection:** CAPTCHAs of any kind.
    *   **Financial Transactions:** Completing purchases or moving funds.
    *   **Sending Communications:** Emails, forum posts, or chat messages.
    *   **Accessing/Modifying Sensitive Information:** Healthcare, financial, or ID records.
    *   **User Data Management:** Downloading files, transferring user data.
    *   **Browser Data Usage:** Chrome history, bookmarks, autofill passwords.
    *   **Security and Identity:** Logging into accounts or impersonation.
    
    ## **RULE 2: Default Behavior (ACTUATE)**
    If an action does NOT fall under USER_CONFIRMATION, proactively perform all
    necessary steps to move the user's request forward.
        
  2. 安全的执行环境:在安全的沙盒化环境中运行代理,以限制其潜在影响(例如,沙盒化虚拟机 [VM]、容器 [如 Docker] 或权限受限的专用浏览器配置文件)。
  3. 输入清理:清理提示词中所有用户生成的文本,以降低意外指令或提示词注入的风险。这是一种有用的安全层,但不能替代安全执行环境。
  4. 内容护栏:使用护栏和内容安全 API(例如 Model Armor)评估用户输入、工具输入和输出以及智能体的回答,以检测其是否恰当、是否存在提示词注入和越狱。
  5. 许可清单和屏蔽清单:实施过滤机制,控制模型可以访问的位置和可以执行的操作。禁止访问的网站屏蔽清单是一个很好的起点,而限制性更强的许可清单则更加安全。
  6. 可观测性和日志记录:维护详细日志,以便进行调试、审核和突发事件响应。您的客户端应记录提示、屏幕截图、模型建议的操作 (function_call)、安全响应以及客户端最终执行的所有操作。
  7. 环境管理:确保 GUI 环境一致。意外的弹出式窗口、系统通知或布局偏移可能会让模型感到困惑。尽可能从已知、干净的状态开始执行每项新任务。

人机协同 (HITL) 确认

人机协同 (HITL) 确认是指在执行模型建议的操作之前,先征求用户确认的过程。当模型因安全问题而无法执行某项操作时,此过程必不可少。

Gemini 的计算机使用工具提供了以下机制来控制 HITL 确认:

覆盖 HITL 确认

您可以替换以下默认 HITL 确认:

  • FINANCIAL_TRANSACTIONS:完成金融交易的最后一步(例如付款、资金转账、下达汇票、开始或修改订阅,或完成预订)。
  • SENSITIVE_DATA_MODIFICATION:修改敏感信息,例如医疗保健、财务或政府记录。
  • COMMUNICATION_TOOL:访问或使用通信工具来发送、分享、发布或以其他方式传输通信内容。
  • ACCOUNT_CREATION:与创建或预配新用户或服务账号的注册或登录流程进行互动。
  • DATA_MODIFICATION:修改、管理、共享、存储、提交或删除浏览器数据或文件。
  • USER_CONSENT_MANAGEMENT:通过做出决定与用户意见征求对话框或横幅互动。
  • LEGAL_TERMS_AND_AGREEMENTS:与具有法律约束力的协议对话框(例如服务条款接受、隐私权政策对话框或法律声明)进行互动。

您可以在计算机使用配置的 disabled_safety_policies 字段中列出这些 HITL 确认,从而替换其中任何或所有确认:

Python

GenerateContent API

generate_content_config = genai.types.GenerateContentConfig(
    tools=[
        types.Tool(
            computer_use=types.ComputerUse(                
                environment=types.Environment.ENVIRONMENT_MOBILE,
                disabled_safety_policies=[
                    types.SafetyPolicy.FINANCIAL_TRANSACTIONS,
                    types.SafetyPolicy.COMMUNICATION_TOOL,
                ]
            )
        ),
    ],
)

contents = [
    types.Content(
        role="user",
        parts=[
            types.Part(text="Open the Maps app and find the nearest coffee shop."),
        ],
    )
]

response = client.models.generate_content(
    model='gemini-3.5-flash',
    contents=contents,
    config=generate_content_config,
)

Interactions API

from google import genai
client = genai.Client()

interaction = client.interactions.create(
    model='gemini-3.5-flash',
    input='Open the Maps app and find the nearest coffee shop.',
    tools=[
        {
            'type': 'computer_use',
            'environment': 'mobile',
            'disabled_safety_policies': [
                'financial_transactions',
                'communication_tool',
            ],
        }
    ]
)

REST

GenerateContent API

{
  "contents": [
    {
      "role": "user",
      "parts": [
        {
          "text": "Open the Maps app and find the nearest coffee shop."
        }
      ]
    }
  ],
  "tools": [
    {
      "computer_use": {
        "environment": "ENVIRONMENT_MOBILE",
        "disabled_safety_policies" : [
          "FINANCIAL_TRANSACTIONS",
          "COMMUNICATION_TOOL"
         ]
      }
    }
  ]
}

Interactions API

{
  "model": "gemini-3.5-flash",
  "input": "Open the Maps app and find the nearest coffee shop.",
  "tools": [
    {
      "type": "computer_use",
      "environment": "mobile",
      "disabled_safety_policies": [
        "financial_transactions",
        "communication_tool"
      ]
    }
  ]
}

创建组织政策

如果您是组织管理员,则可以使用Organization Policy Service创建组织级政策,以防止个别开发者停用部分或全部 HITL 确认。此政策会取代任何开发者级设置。

您可以使用 Google Cloud 控制台或 Google Cloud CLI 创建政策。限制条件 ID 为 vertexai.configurableComputerUseToolSafetyPolicies。 组织政策更改最长可能需要 1 小时才能生效。

如需详细了解如何创建和管理组织政策,请参阅创建组织政策。

价格

计算机使用功能的定价与 Gemini 相同,并使用相同的 SKU。如需拆分计算机使用费用,请使用自定义元数据标签。如需详细了解如何使用自定义元数据标签进行费用监控,请参阅自定义元数据标签。