見出し画像

OpenAI Responses API 入門 (11) - Computer use

「Responses API」の「Computer use」の使い方についてまとめました。

Computer use - OpenAI API


前回

1. Computer use

Computer use」は、「CUA」(Computer-Using Agent)の実用的な応用であり、「GPT-4o」の視覚機能と高度な推論を組み合わせて、コンピューターインターフェースの操作やタスクの実行をシミュレートします。

2. Computer use のしくみ

Computer use」は、連続ループで動作します。このツールは click(x, y)type(text) のようなコンピュータ操作を送信し、ユーザーのコードがそれをコンピュータやブラウザ環境で実行します。その後、結果のスクリーンショットがモデルに返されます。

このしくみにより、ユーザーのコードは人間がコンピュータインターフェースを操作する動作をシミュレートし、モデルはスクリーンショットを分析して環境の状態を理解し、次のアクションを提案します。

このループを活用することで、クリック、タイピング、スクロールなどの操作を自動化できます。たとえば、航空券の予約、商品の検索、フォームの入力などのタスクを実行できます。

3. 環境の設定

このツールを統合する前に、スクリーンショットを取得し、推奨される操作を実行できる環境を準備する必要があります。安全性の観点から、サンドボックス環境の使用を推奨します。

3-1. ローカルブラウジング環境のセットアップ

最小限のセットアップで「Computer use」を試したい場合は、PlaywrightSelenium などのブラウザ自動化フレームワークを使用できます。

ただし、ローカルでブラウザ自動化フレームワークを実行すると、セキュリティリスクが生じる可能性があります。これを軽減するために、以下の設定を推奨します。

・サンドボックス環境の使用
・env を空のオブジェクトに設定し、ホスト環境変数がブラウザに露出しないように設定
・拡張機能やファイルシステムを無効にするフラグを設定

対応するSDKをインストールすることで、好みのプログラミング言語でブラウザインスタンスを起動できます。

例えば、Playwright のブラウザインスタンスを起動する手順は、次のとおりです。

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(
        headless=False,
        chromium_sandbox=True,
        env={},
        args=[
            "--disable-extensions",
            "--disable-file-system"
        ]
    )
    page = browser.new_page()
    page.set_viewport_size({"width": 1024, "height": 768})
    page.goto("https://bing.com")

    page.wait_for_timeout(10000)

3-2. ローカル仮想マシン環境のセットアップ

Dockerのようなツールを使用して、ローカルで仮想マシンを構築・実行できます。その後、このローカルマシンに接続して「Computer use」アクションを実行できます。

(1) Dockerの起動
Dockerがインストールされていない場合は、公式サイトからインストールできます。インストール後、Dockerが正常に動作していることを確認してください。

(2) Dockerfileの作成
仮想マシンの構成を定義するために、Dockerfileを作成します。
以下は、VNCサーバーを備えたUbuntu仮想マシンを起動する例のDockerfileです。

FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive

# 1) Install Xfce, x11vnc, Xvfb, xdotool, etc., but remove any screen lockers or power managers
RUN apt-get update && apt-get install -y     xfce4     xfce4-goodies     x11vnc     xvfb     xdotool     imagemagick     x11-apps     sudo     software-properties-common     imagemagick  && apt-get remove -y light-locker xfce4-screensaver xfce4-power-manager || true  && apt-get clean && rm -rf /var/lib/apt/lists/*

# 2) Add the mozillateam PPA and install Firefox ESR
RUN add-apt-repository ppa:mozillateam/ppa  && apt-get update  && apt-get install -y --no-install-recommends firefox-esr  && update-alternatives --set x-www-browser /usr/bin/firefox-esr  && apt-get clean && rm -rf /var/lib/apt/lists/*

# 3) Create non-root user
RUN useradd -ms /bin/bash myuser     && echo "myuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
USER myuser
WORKDIR /home/myuser

# 4) Set x11vnc password ("secret")
RUN x11vnc -storepasswd secret /home/myuser/.vncpass

# 5) Expose port 5900 and run Xvfb, x11vnc, Xfce (no login manager)
EXPOSE 5900
CMD ["/bin/sh", "-c", "    Xvfb :99 -screen 0 1280x800x24 >/dev/null 2>&1 &     x11vnc -display :99 -forever -rfbauth /home/myuser/.vncpass -listen 0.0.0.0 -rfbport 5900 >/dev/null 2>&1 &     export DISPLAY=:99 &&     startxfce4 >/dev/null 2>&1 &     sleep 2 && echo 'Container running!' &&     tail -f /dev/null "]

(3) Docker イメージのビルド
Dockerfile があるディレクトリで、以下のコマンドを実行して Docker イメージをビルドします。

docker build -t cua-image .

(4) Docker コンテナをローカルで実行
以下のコマンドを実行して、Docker コンテナを起動します。

docker run --rm -it --name cua-image -p 5900:5900 -e DISPLAY=:99 cua-image

(5) コンテナ内でコマンドを実行
コンテナが起動したら、コマンドを実行できます。
例えば、次のステップで使用する補助関数を定義し、コンテナ内でコマンドを実行できます。

def docker_exec(cmd: str, container_name: str, decode=True) -> str:
    safe_cmd = cmd.replace('"', '\"')
    docker_cmd = f'docker exec {container_name} sh -c "{safe_cmd}"'
    output = subprocess.check_output(docker_cmd, shell=True)
    if decode:
        return output.decode("utf-8", errors="ignore")
    return output

class VM:
    def __init__(self, display, container_name):
        self.display = display
        self.container_name = container_name

vm = VM(display=":99", container_name="cua-image")

4. CUAループの統合

アプリケーションに「Computer use」を統合する手順は、次のとおりです。

(1) モデルにリクエストを送信
「Computer use」ツールを利用可能なツールとして含め、表示サイズや環境を指定します。初回のリクエストでは、環境の初期状態を示すスクリーンショットを含めることも可能です。

(2) モデルからの応答を受信
レスポンスに computer_call アイテムが含まれているか確認します。これには、指定された目標に向けて実行すべきアクション(クリック、テキスト入力、スクロール、待機など)が含まれています。

(3) 要求されたアクションを実行
受け取ったアクションをコードを通じてコンピュータまたはブラウザ環境で実行します。

(4) 更新された状態をキャプチャ
アクションを実行した後、環境の最新の状態をスクリーンショットとして取得します。

(5) 繰り返し
更新後の状態を computer_call_output として含めて新たなリクエストを送信し、このプロセスを繰り返します。モデルがアクションのリクエストを停止するか、任意のタイミングで停止するまでこのループを続けます。

4-1. モデルにリクエストを送信

「Computer use」ツール (computer_use_preview) を備えた 「computer-use-preview」モデルを使用して、レスポンスを作成するリクエストを送信します。このリクエストには、環境の詳細情報と初期入力プロンプトを含める必要があります。また、オプションとして環境の初期状態を示すスクリーンショットを含めることもできます。

from openai import OpenAI
client = OpenAI()

response = client.responses.create(
    model="computer-use-preview",
    tools=[{
        "type": "computer_use_preview",
        "display_width": 1024,
        "display_height": 768,
        "environment": "browser" # other possible values: "mac", "windows", "ubuntu"
    }],
    input=[
        {
            "role": "user",
            "content": "Check the latest OpenAI news on bing.com."
        }
        # Optional: include a screenshot of the initial state of the environment
        # {
        #     type: "input_image",
        #     image_url: f"data:image/png;base64,{screenshot_base64}"
        # }
    ],
    truncation="auto"
)

print(response.output)

4-2. モデルからの応答を受信

モデルは、会話の状態に応じて、computer_call アイテム、単なるテキスト、または他のTool Callingを含む出力を返します。computer_call アイテムの例としては、クリック、スクロール、キー押下、その他 API リファレンスで定義されたイベントなどがあります。

今回の例では、computer_call アイテムとして クリックアクション が含まれています。

"output": [
    {
        "type": "reasoning",
        "id": "rs_67cc...",
        "content": []
    },
    {
        "type": "computer_call",
        "id": "cu_67cc...",
        "call_id": "call_zw3...",
        "action": {
            "type": "click",
            "button": "left",
            "x": 156,
            "y": 50
        },
        "pending_safety_checks": [],
        "status": "completed"
    }
]

・Reasoningアイテム

モデルは一部のアクションに対して、レスポンス出力内に Reasoning アイテムを含めることがあります。この場合、次回 CUA モデルにリクエストを送信する際に、Reasoning アイテムを必ず含める必要があります。

・セーフティーチェック
モデルは pending_safety_check パラメータとともに セーフティチェック を返すことがあります。セーフティチェックの承認方法については、後ほど説明します。

4-3. 要求されたアクションを実行

対応するアクションをコンピュータまたはブラウザ上で実行します。
computer_call をコードを通じてどのようにアクションにマッピングするかは、使用する環境によって異なります。

最も一般的なコンピュータアクションの実装例は、次のとおりです。

def handle_model_action(page, action):
    """
    Given a computer action (e.g., click, double_click, scroll, etc.),
    execute the corresponding operation on the Playwright page.
    """
    action_type = action.type
    
    try:
        match action_type:

            case "click":
                x, y = action.x, action.y
                button = action.button
                print(f"Action: click at ({x}, {y}) with button '{button}'")
                # Not handling things like middle click, etc.
                if button != "left" and button != "right":
                    button = "left"
                page.mouse.click(x, y, button=button)

            case "scroll":
                x, y = action.x, action.y
                scroll_x, scroll_y = action.scroll_x, action.scroll_y
                print(f"Action: scroll at ({x}, {y}) with offsets (scroll_x={scroll_x}, scroll_y={scroll_y})")
                page.mouse.move(x, y)
                page.evaluate(f"window.scrollBy({scroll_x}, {scroll_y})")

            case "keypress":
                keys = action.keys
                for k in keys:
                    print(f"Action: keypress '{k}'")
                    # A simple mapping for common keys; expand as needed.
                    if k.lower() == "enter":
                        page.keyboard.press("Enter")
                    elif k.lower() == "space":
                        page.keyboard.press(" ")
                    else:
                        page.keyboard.press(k)
            
            case "type":
                text = action.text
                print(f"Action: type text: {text}")
                page.keyboard.type(text)
            
            case "wait":
                print(f"Action: wait")
                time.sleep(2)

            case "screenshot":
                # Nothing to do as screenshot is taken at each turn
                print(f"Action: screenshot")

            # Handle other actions here

            case _:
                print(f"Unrecognized action: {action}")

    except Exception as e:
        print(f"Error handling action {action}: {e}")

4-4. 更新された状態をキャプチャ

アクションを実行した後、環境の最新の状態をスクリーンショットとして取得します。スクリーンショットの取得方法は、使用する環境によって異なります。

def get_screenshot(page):
    """
    Take a full-page screenshot using Playwright and return the image bytes.
    """
    return page.screenshot()

4-5. 繰り返し

スクリーンショットを取得したら、それを computer_call_output としてモデルに送信し、次のアクションを取得できます。レスポンスに computer_call アイテムが含まれている限り、このプロセスを繰り返します。

import time
import base64
from openai import OpenAI
client = OpenAI()

def computer_use_loop(instance, response):
    """
    Run the loop that executes computer actions until no 'computer_call' is found.
    """
    while True:
        computer_calls = [item for item in response.output if item.type == "computer_call"]
        if not computer_calls:
            print("No computer call found. Output from model:")
            for item in response.output:
                print(item)
            break  # Exit when no computer calls are issued.

        # We expect at most one computer call per response.
        computer_call = computer_calls[0]
        last_call_id = computer_call.call_id
        action = computer_call.action

        # Execute the action (function defined in step 3)
        handle_model_action(instance, action)
        time.sleep(1)  # Allow time for changes to take effect.

        # Take a screenshot after the action (function defined in step 4)
        screenshot_bytes = get_screenshot(instance)
        screenshot_base64 = base64.b64encode(screenshot_bytes).decode("utf-8")

        # Send the screenshot back as a computer_call_output
        response = client.responses.create(
            model="computer-use-preview",
            previous_response_id=response.id,
            tools=[
                {
                    "type": "computer_use_preview",
                    "display_width": 1024,
                    "display_height": 768,
                    "environment": "browser"
                }
            ],
            input=[
                {
                    "call_id": last_call_id,
                    "type": "computer_call_output",
                    "output": {
                        "type": "input_image",
                        "image_url": f"data:image/png;base64,{screenshot_base64}"
                    }
                }
            ],
            truncation="auto"
        )

    return response

4-6. 会話履歴の取り扱い

previous_response_id パラメータを使用すると、現在のリクエストを前回のレスポンスと関連付けることができます。会話履歴を自分で管理したくない場合は、この方法の使用を推奨します。

このパラメータを使用しない場合は、前回のリクエストのレスポンス出力に含まれていたすべてのアイテム(Reasoning アイテムを含む場合はそれも)を、inputs 配列に含める必要があります。

4-7. セーフティチェックの承認

API には、プロンプトインジェクションやモデルの誤動作を防ぐためのセーフティチェックが実装されています。

・悪意のある指示の検出
スクリーンショット画像を評価し、モデルの挙動を変化させる可能性のある 敵対的なコンテンツ が含まれていないか確認します。

・無関係なドメインの検出
current_url(提供されている場合)を評価し、会話履歴に照らして 現在のドメインが適切かどうか を確認します。

・機密性の高いドメインの検出
current_url(提供されている場合)をチェックし、機密性の高いドメイン にアクセスしている場合は警告を表示します。

上記のいずれか、または複数のチェックに該当した場合、次回の computer_call のレスポンスで pending_safety_checks パラメータ を伴うセーフティチェックが発生します。

"output": [
    {
        "type": "reasoning",
        "id": "rs_67cb...",
        "content": [
            {
                "type": "reasoning_summary",
                "text": "Exploring 'File' menu option."
            }
        ]
    },
    {
        "type": "computer_call",
        "id": "cu_67cb...",
        "call_id": "call_nEJ...",
        "action": {
            "type": "click",
            "button": "left",
            "x": 135,
            "y": 193
        },
        "pending_safety_checks": [
            {
                "id": "cu_sc_67cb...",
                "code": "malicious_instructions",
                "message": "We've detected instructions that may cause your application to perform malicious or unauthorized actions. Please acknowledge this warning if you'd like to proceed."
            }
        ],
        "status": "completed"
    }
]

次のリクエストを送信する際に、acknowledged_safety_checks としてセーフティチェックを承認しないと、処理を継続できません。pending_safety_checks が返された場合は、すべてのアクションをエンドユーザーに確認させ、モデルの動作と正確性を確認する必要があります。

・malicious_instructionsとirrelevant_domain
エンドユーザーがモデルのアクションを確認し、意図したとおりに動作しているか検証します。

・sensitive_domain
エンドユーザーがモデルのアクションを積極的に監視していることを保証します。「監視モード」の具体的な実装方法はアプリケーションによって異なりますが、一例として サイト上でのユーザーの操作データを収集し、エンドユーザーがアクティブに関与していることを確認する方法 などが考えられます。

from openai import OpenAI
client = OpenAI()

response = client.responses.create(
    model="computer-use-preview",
    previous_response_id="<previous_response_id>",
    tools=[{
        "type": "computer_use_preview",
        "display_width": 1024,
        "display_height": 768,
        "environment": "browser"
    }],
    input=[
        {
            "type": "computer_call_output",
            "call_id": "<call_id>",
            "acknowledged_safety_checks": [
                {
                    "id": "<safety_check_id>",
                    "code": "malicious_instructions",
                    "message": "We've detected instructions that may cause your application to perform malicious or unauthorized actions. Please acknowledge this warning if you'd like to proceed."
                }
            ],
            "output": {
                "type": "computer_screenshot",
                "image_url": "<image_url>"
            }
        }
    ],
    truncation="auto"
)

4-8. 最終コード

まとめると、最終的なコードには次の内容が含まれるようになります。

(1) 環境の初期化
実行環境(コンピュータまたはブラウザ)をセットアップします。

(2) 最初のリクエストをモデルに送信
computer ツールを含むリクエストを送信し、環境の初期状態を設定します。

(3) ループ処理の実装
モデルのレスポンスに基づき、提案されたアクション(クリック、スクロール、入力など)を実行します。実行後、最新の環境状態を取得し、再度モデルに送信します。

(4) セーフティチェックの承認とエンドユーザー確認
pending_safety_checks を処理し、必要に応じて acknowledged_safety_checks を送信します。ユーザーにアクションを確認させ、モデルの動作が正しいかをチェックできるようにします。

エンドツーエンドの統合例を確認するには、CUA サンプルアプリリポジトリを参照してください。

5. 制限事項

ブラウザベースのタスクには、computer-use-previewモデルの使用を推奨します。ただし、このモデルは、特にブラウザ以外の環境では使用頻度が低いため、意図せず誤った結果を出す可能性があります。

例えば、computer-use-previewのOSWorldでのパフォーマンスは現在38.1%であり、OS上のタスクを自動化するにはまだ十分に信頼できるレベルではありません。

また、以下のような制限事項にも注意が必要です。

・computer-use-previewモデルには、レート制限や機能サポートの制約があり、詳細はモデルの説明ページに記載されています。
・このツールは zero data retention (data retention policies) をサポートしていません。

6. リスクと安全性

「Computer use」には、標準的なAPI機能やチャットインターフェースとは異なる特有のリスクがあり、特にインターネットと連携する際に注意が必要です。

以下に、これらのリスクを軽減するためのベストプラクティスを示します。

6-1. 高リスクなタスクには人間の確認を挟む

高リスクなタスクや高精度が求められるタスクは避けてください。モデルは誤った判断をする可能性があり、特にブラウザ以外の環境ではミスが発生しやすくなります。重要な決定の前にユーザー確認を求めることを期待していますが、完全には信頼できません。モデルの動作が現実世界に影響を与える場合は、必ず人間が介入し確認してください。

6-2. プロンプトインジェクションに注意

プロンプトインジェクションとは、AIモデルが入力内の不正な指示に従ってしまう現象です。computer-use-previewモデルの場合、提供されたスクリーンショット内の悪意のあるウェブサイトやメールの指示に誤って従う可能性があります。このリスクを避けるため、信頼できる隔離環境(サンドボックス化されたブラウザやコンテナなど)でのみ使用してください。

6-3. ブロックリストと許可リストを活用

Webサイト、アクション、ユーザーのブロックリストまたは許可リストを設定を推奨します。
例:チケット予約ツールとして使用する場合、許可リストに特定の予約サイトのみを登録し、他のサイトへのアクセスを制限。

6-4. ユーザーIDの送信

OpenAIが不正行為を監視・検出できるよう、エンドユーザーのID(任意のパラメータ)を送信することを推奨します。

6-5. セーフティチェックの活用

以下のセーフティチェック機能を活用し、プロンプトインジェクションやモデルの誤作動を防ぎましょう。

・悪意のある指示の検出
・関連性のないドメインの検出
・機密性の高いドメインの検出

pending_safety_checkを受け取った場合、監視を強化してください。具体的には、タスクの実行をユーザーに委ね、ユーザーが明示的に確認した後に進行するようにします。また、「監視モード」(Operatorのような監視モード)を導入し、ユーザーがエージェントの動作をリアルタイムで監視できるようにします。セーフティチェックが発動した場合は、人間が介入するのが基本ルールです。

6-6. 安全性向上のための追加推奨事項

可能であれば、computer_call_output の一部として current_url(現在のURL)を送信してください。これにより、セーフティチェックの精度を向上させることができます。

{
    "type": "computer_call_output",
    "call_id": "call_7OU...",
    "acknowledged_safety_checks": [],
    "output": {
        "type": "computer_screenshot",
        "image_url": "..."
    },
    "current_url": "https://openai.com"
}

6-7. 追加の安全対策

「Computer use」ループと並行してガードレールを実装する など、アプリケーションに最適な追加の安全対策を導入してください。

6-8. 使用ポリシーの遵守

OpenAIの使用ポリシーおよびビジネス利用規約を遵守する責任はユーザーにあります。これらの遵守を確実にするために、提供されている安全機能やツールを積極的に活用することを推奨します。

次回



いいなと思ったら応援しよう!