パソコンの使用

Gemini のコンピュータ使用ツールを使用すると、グラフィカル ユーザー インターフェース(GUI)を操作してタスクを自動化するブラウザ、モバイル、デスクトップの制御エージェントを構築できます。コンピュータの使用が有効になっている場合、モデルはスクリーンショットを使用して画面を観察し、マウスのクリック、スクロール、キーボード入力などの特定の UI アクションを生成して動作します。

Gemini は、いくつかの高度なコンピュータ使用機能をサポートしています。

  • マルチ環境のサポート: ブラウザ、モバイル、デスクトップ環境用のエージェントを構築します。
  • インテントを使用した効率的なアクション: アクションには、各ステップの背後にあるモデルの推論を説明する intent フィールドが含まれています。
  • 構成可能な安全ポリシー: 組み込みのポリシー カテゴリとオーバーライドを使用して、安全動作を微調整します。
  • プロンプト インジェクションの検出: スクリーンショットのスキャンを有効にして、隠れた敵対的な指示を検出します。

コンピュータ使用を活用して、次のことができるエージェントを構築できます。

  • ウェブサイトやデスクトップ アプリケーションでのデータ入力やフォームへの記入など、繰り返し発生する作業を自動化します。
  • ウェブ、モバイル、デスクトップのユーザーフローの自動テストを実行します。
  • ウェブサイトやアプリケーションを操作して調査を収集する(商品情報、価格、レビューの比較など)。
  • アプリケーション間で複数のステップからなる一連のアクションを実行して、ユーザーを支援します。

このガイドの内容は、次のとおりです。

関数呼び出しと同様に、クライアントサイドのアプリケーション コードを記述して、コンピュータ使用関数呼び出しを受信し、対応するアクションを実行する必要があります。

このガイドは、Google Gen AI SDK for Python を使用しており、Playwright API に精通していることを前提としています。

GitHub でコンピュータ使用のリファレンス実装を確認できます。

サポートされているモデル

コンピュータの使用は、次のモデルでサポートされています。

クリックしてサポートされているモデルを開く

コンピュータ使用の仕組み

テキスト レスポンスを生成する代わりに、コンピュータ使用は、マウスのクリックなどの特定の UI アクションを実行するタイミングを判断し、これらのアクションを実行するために必要なパラメータを返します。クライアントサイドのアプリケーション コードを記述して、コンピュータ使用 function_call を受け取り、対応するアクションを実行する必要があります。

コンピュータ使用のインタラクションは、エージェント ループ プロセスに従います。

  1. モデルにリクエストを送信する

    • API リクエストに、コンピュータ使用(および必要に応じて別のツール)を追加します。
    • ユーザーのリクエストと、GUI の現在の状態を表すスクリーンショットを含むプロンプトをモデルに送信します。
  2. モデル レスポンスを受信する

    • モデルはユーザーのリクエストとスクリーンショットを分析し、UI アクションを表す function_call(「座標(x,y)をクリック」、「テキスト text を入力」など)を含むレスポンスを生成します。モデルで使用できるすべてのアクションの一覧については、サポートされているアクションをご覧ください。
    • 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 の新しいスクリーンショットと現在の URL をキャプチャし、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

次に、正規化された座標(0 ~ 1000)が正確にスケーリングされるように、明示的なビューポート寸法で Playwright ブラウザ インスタンスを初期化します。

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 の最初のスクリーンショットを含むプロンプトをモデルに送信します。

必要に応じて、次の情報を追加することもできます。

  • 除外するアクション: サポートされている UI アクションのリストに、モデルに実行させたくないアクションがある場合は、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 以降とモバイルまたはデスクトップのユースケースをご覧ください。

レスポンスの受信

モデルは、タスクを完了するために UI アクションまたはユーザー定義関数が必要であると判断した場合、1 つ以上の FunctionCalls を返します。アプリのコードで、これらのアクションを解析して実行し、結果を収集する必要があります。コンピュータ使用は並列関数呼び出しをサポートしています。つまり、モデルは 1 回のターンで複数の独立したアクションを返すことができます。

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 以降でコンピュータを使用するための実行環境を構成する方法を示しています。

REST API

リクエストのデータを使用する前に、次のように置き換えます。

  • PROJECT_ID: プロジェクト ID。

HTTP メソッドと URL:

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 に直接移動します。 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 に直接移動します。 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 メソッドと URL:

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 の機能が、CAPTCHA のバイパスやシステムの整合性の侵害など、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: 利用規約の同意、プライバシー ポリシーのダイアログ、法的通知など、法的拘束力のある契約ダイアログとのやり取り。

これらの HITL 確認の一部またはすべてをオーバーライドするには、コンピュータ使用構成の disabled_safety_policies フィールドにリストします。

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"
      ]
    }
  ]
}

組織のポリシーを作成する

組織管理者は、組織ポリシー サービスを使用して、個々のデベロッパーが一部またはすべての HITL 確認を無効にできないようにする組織レベルのポリシーを作成できます。このポリシーは、デベロッパー レベルの設定よりも優先されます。

ポリシーは、Google Cloud コンソールまたは Google Cloud CLI を使用して作成できます。制約 ID は vertexai.configurableComputerUseToolSafetyPolicies です。組織のポリシーの変更が反映されるまでに、最大 1 時間かかることがあります。

組織のポリシーを作成して管理する方法の詳細については、組織のポリシーを作成するをご覧ください。

料金

コンピュータの使用は Gemini と同じ料金で、同じ SKU を使用します。コンピュータの使用費用を分割するには、カスタム メタデータ ラベルを使用します。費用のモニタリングにカスタム メタデータ ラベルを使用する方法については、カスタム メタデータ ラベルをご覧ください。