メむンコンテンツぞスキップ
芋出し画像

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」を詊したい堎合は、Playwright や Selenium などのブラりザ自動化フレヌムワヌクを䜿甚できたす。

    ただし、ロヌカルでブラりザ自動化フレヌムワヌクを実行するず、セキュリティリスクが生じる可胜性がありたす。これを軜枛するために、以䞋の蚭定を掚奚したす。

    ・サンドボックス環境の䜿甚
    ・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の䜿甚ポリシヌおよびビゞネス利甚芏玄を遵守する責任はナヌザヌにありたす。これらの遵守を確実にするために、提䟛されおいる安党機胜やツヌルを積極的に掻甚するこずを掚奚したす。

    次回



     
     

    npaka

     
     
    プログラマヌ。iPhone / Android / Unity / ROS / AI / AR / VR / RasPi / ロボット / ガゞェット。幎2冊ペヌスで技術曞を執筆。アニ゜ン / カラオケ / ギタヌ / 猫 twitter : @npaka123

    あなたぞのおすすめ