Computer Use APIの接続前に、動作制御をオフラインでテストする
Pythonの19件のテストで操作の検証、スクリーンショットの呼び出しID、フォームの完了条件を確認。未実行の接続用コードと検証済み範囲を分けて説明します。
Computer Useの実装では、モデルが対応する操作を返せるかと、アプリが操作を実行して完了を正しく判断できるかを分けて考えます。本記事は後者から始めます。Pythonのコントローラーと19件のオフラインテストを、APIキーやブラウザー、モデル料金なしで実行できます。
コントローラーキットをダウンロード。Python 3.9.6で通過し、新しく解凍したコピーでも再実行済みです。ただし同梱の run_live.py は実行も実プロバイダーとの検証もしていません。実際のAPI連携で取得した画像、使用量、互換性の結果はありません。
テストを先に実行する
Python 3.9以降の標準ライブラリだけで動きます。api-kit 内で実行してください。
python3 -B -m unittest discover -s . -p 'test_*.py' -v
15件がコントローラー、4件が受信記録の検証です。応答とランタイムは模擬で、通信やブラウザー起動はありません。画像の代用バイト列は実画像ではなく、APIへ送信できません。
| ファイル | 役割 |
|---|---|
controller.py | 操作を検証し、観察を返し、完了時に停止 |
test_controller.py | 模擬応答とランタイムによるテスト |
test_receiver.py | メモリー上の受信記録の差分を検証 |
run_live.py | 今後のPlaywright・HTTPS Responses接続用。実接続は未検証 |
README.md | 実行方法と実接続に必要な条件 |
モデル・実行・検証を分離する
モデルが次の操作を選び、ランタイムがブラウザーを操作し、別の検証処理が保存結果を調べます。QA練習用フォームでは、毎回異なる @example.test のアドレスを使います。
開始前と実行中の /submissions を比べ、古い記録がそのまま残り、期待するアドレスがちょうど1件だけ追加された場合に限って完了とします。以前から存在する一致記録、重複保存、別のアドレス、成功メッセージだけでは完了と認めません。これは教材固有の条件です。実際のアプリでは保存された下書きIDなど、その仕事に合った結果を検証します。
ひとつのツール仕様に合わせる
コードはOpenAI Computer Useガイドの構造化操作の流れを参考にしています。最初のスクリーンショットを送り、computer_call の操作を順に実行し、対応する call_id とともに computer_call_output の画像を返します。次の要求には previous_response_id も渡します。
画像と呼び出しの対応が重要です。単に画像を返しても、IDが違えば正しいツール結果にはなりません。仕様の参照は、特定のモデルとの接続成功を意味しません。
実接続前にモデル、エンドポイント、ツールのスキーマを組み合わせて確認します。テキスト要求が通るだけではComputer Use対応の証明になりません。既定のモデルやプロバイダーは選んでおらず、Ofox経由の互換性も主張していません。
操作を実行前に制限する
対応するのは左クリック、200文字以内の入力、指定の単独キー、範囲を制限したスクロール、画像取得です。座標は画像寸法内に制限し、真偽値、不正な数値、構造が違う入力を拒否します。1応答あたり12操作、モデル呼び出しは既定で4回が上限です。未対応操作では停止します。
1応答につきcomputer callは1つです。呼び出しIDの重複、不完全な応答、未処理の安全確認は自動承認せず停止します。全操作や一般的な承認システムを実装したものではありません。
操作の前後で完了を確認するため、非同期の保存が終わった後に同じバッチの次のクリックを実行し続けることを防ぎます。接続用コードはクリック・キー入力後に受信記録を短時間確認しますが、実ブラウザーでの動作証明には別の試験が必要です。
ひとつの操作が処理される流れを追う
コントローラーはモデルの応答とブラウザー実行部の間にあります。非対応の操作を拒否し、要求と観察の対応を保ち、アプリ側で完了を確認できたら停止します。その境界を実装する開発者向けの例であり、そのまま本番運用できるエージェントではありません。
以下はローカル実装が受け取る形に合わせた合成応答です。座標は仮の100×100画面のもので、QAページのボタン位置ではありません。
{
"id": "response_demo_1",
"status": "completed",
"output": [{
"type": "computer_call",
"call_id": "call_demo_1",
"actions": [{"type": "click", "button": "left", "x": 10, "y": 20}]
}]
}
外側の status は応答生成の完了を示します。クリック実行や保存の成功ではありません。コントローラーは操作の配列を検証し、許可する操作を順番に実行して受信結果を確認します。続ける場合の画像出力は call_demo_1 に対応し、previous_response_id は response_demo_1 を参照します。この2つを混同すると要求と結果の対応が崩れます。
モデルもブラウザーも使わず動かす
次を controller.py と同じ場所に walkthrough.py として保存し、python3 -B walkthrough.py を実行します。本体のコントローラーに簡単な模擬の実行環境を渡し、1操作後に完了させて、2回目のクリックが飛ばされることを確認します。
from controller import run
class DemoRuntime:
width, height = 100, 100
def __init__(self):
self.actions = []
self.done = False
def screenshot(self):
return b"offline-placeholder-not-a-real-png"
def assert_allowed(self):
pass # Fake only: a real runtime must enforce its allowed surface.
def complete(self):
return self.done
def perform(self, action):
self.actions.append(action)
self.done = True # Simulated outcome, not receiver verification.
runtime = DemoRuntime()
def transport(payload):
return {
"id": "response_demo_1",
"status": "completed",
"output": [{
"type": "computer_call",
"call_id": "call_demo_1",
"actions": [
{"type": "click", "x": 10, "y": 20},
{"type": "click", "x": 30, "y": 40}
]
}]
}
result = run(transport, runtime, "Synthetic controller walkthrough")
assert len(runtime.actions) == 1
print(result["status"], result["turns"], len(runtime.actions))
ローカルで確認した出力は verified 1 1 です。成功状態、1回の模擬応答、実行された1操作を意味します。ただし、ここでは DemoRuntime.complete() が簡単に真になるため、フォームが保存された証拠ではありません。実接続では独立した結果検証に置き換えます。仮の画像バイトも有効なPNGではなく、実APIに送れません。
仮の完了条件を受信記録に置き換える
同梱のブラウザーアダプターでは、以前の記録が変わらず、今回固有のアドレスが1件だけ追加されることを条件にします。
| 前後の変化 | 判定 | 理由 |
|---|---|---|
| 以前の記録+今回のアドレス1件 | 受理 | 一致する追加1件 |
| 変化なし | 継続確認または未確定で停止 | 保存の証拠なし |
| 以前の記録+同じ新規記録2件 | 拒否 | 重複送信 |
| 以前の記録を変更+今回のアドレス | 拒否 | 基準が変更された |
| 以前の記録+別のアドレス | 拒否 | 入力と不一致 |
4件の受信側テストは正しい追加、別アドレス、余分な記録、既存記録の変更をメモリー内で検証します。「変化なし」は実装の継続条件であり、5件目の単体テストではありません。本番では時間、同時操作、記録取得失敗も扱う必要があります。この独立した演習環境のルールを同時利用される本番基盤と混同しないでください。QA演習では人が同じ前後証拠を集めます。
19件で確認したこと
不正構造、座標範囲、未対応入力、呼び出しと画像の対応、ターン上限、重複呼び出し、途中停止、受信記録の一致を検査します。完了後の残りの操作を止め、重複や違うアドレスでは失敗する回帰テストも含みます。
完了済みで有効なIDを持つ応答について、操作のない最終応答も含め使用量を監査に残します。実行失敗時には試みた操作も記録します。模擬使用量は請求実績ではなく、すべての起動失敗で記録を作れるという保証もありません。モデル精度や実環境の成功率はこのテストからは分かりません。
停止した境界から原因を調べる
| メッセージ | 確認箇所 | 次の行動 |
|---|---|---|
Coordinates outside current viewport | 座標検証 | 現在の実画像寸法と座標を比較 |
Unsupported action type | 対応する操作 | 未実装操作を勝手に実行せず内容を確認 |
Missing or repeated call id | 呼び出し対応 | 応答ID、call ID、再試行履歴を確認 |
Safety check requires human review | 承認待ち | 停止する。例には承認UIがない |
Model stopped before receiver verification | 完了判定 | モデルの文章ではなく受信記録を見る |
Turn limit reached | 上限 | 再試行前に送信済みかを確認 |
配列全体を実行前に検証するため、後半に未対応操作があれば最初の操作前に停止します。ただし実行開始後の失敗では、先に行った操作の影響が残る場合があります。監査ログは操作の試行と、エラーなく処理を終えた操作を区別しますが、変更を元に戻せません。再開前に受信結果を調べます。
接続の問題は権限の確認手順を参照してください。フォーム以外なら別の完了条件を決めます。競合表の例では、出典URLを含む解析可能な証拠ファイルが成果物になります。
実接続の条件は別に確認する
オフラインテストで確認できるのは、対象となったコントローラーの処理だけです。実行環境を接続する前に、プロバイダーの仕様と独立して検証できる完了条件を決めます。
run_live.py は新しいPlaywright Chromiumコンテキスト、ローカル教材のオリジン、明示したHTTPS Responses URLを使用し、個人のブラウザープロファイルには接続しません。通常のページリクエストを教材のオリジンに制限し、予期しないオリジンや新しいタブを検出すると停止します。ただし、汎用的なセキュリティサンドボックスではありません。
Playwrightの手順に従って独立環境へ導入し、実際のバージョンとブラウザービルドを記録します。本キットの実接続依存関係はまだ検証・固定していません。COMPUTER_RESPONSES_URL、COMPUTER_MODEL、COMPUTER_API_KEY は環境変数で渡し、秘密値を保存・共有しないでください。
ブラウザー利用とAPI費用の許可が必要です。既存のアクセス拒否を迂回してはいけません。毎回新しいアドレスと出力先を使います。4回の呼び出しや出力トークン上限は金額上限ではないため、プロバイダーの料金とアカウント側の制限を別途確認します。タイムアウトでも課金される可能性があるので、再試行前に使用量と保存結果を確認してください。
実接続は実際の証拠で判定する
モデルID、エンドポイントのホスト、各バージョン、タスク、秘密情報を除いた応答と使用量、呼び出しID、画像、受信記録を保存し、共有前に内容を確認します。失敗は失敗として報告してください。ツールが動かないときに通常のテキスト応答へ切り替えても、Computer Useが成功したことにはなりません。
別の架空アドレスを使い、クリーンな環境からもう一度実行します。2回の結果と実際の使用量は別々に記録してください。現時点で確認できるのは19件のオフラインテストであり、実際のプロバイダーとブラウザーの接続は未検証です。
よくある質問
- そのまま実接続済みのAPIサンプルとして使えますか?
- いいえ。19件のオフラインテストは通過していますが、接続用コード、プロバイダー互換性、実ブラウザーと使用料金は未検証です。
- APIキーなしでテストできますか?
- はい。標準ライブラリのテストは合成応答と模擬の実行環境を使い、APIやブラウザーには接続しません。
- verifiedは何を意味しますか?
- 渡された実行環境が完了と判定した意味です。本例では模擬結果であり、実接続では独立したアプリの証拠で判定する必要があります。
- 回数制限で費用も保証できますか?
- できません。ループ回数と金額は別です。実行前に料金、使用量記録、アカウント側の支出制限を確認します。


