Browser use toolのバッチアクション — 1ターンで複数操作をまとめる実装
browser_toolsetのバッチアクションで、クリック・入力・Enterを1回のtool_useにまとめ往復回数を減らす実装を解説します。
browser_toolsetは、独立した複数の操作を1回のtool_useにまとめてClaudeに返させる設計を持ちます。これがバッチアクションです。検索ボックスをクリックし、クエリを入力し、Enterを押すといった一連の操作を1ターンで返せるため、Messages APIとの往復回数を減らせます。
tool_useバッチの実行順序依存・失敗時のis_error処理・disable_parallel_tool_useによる抑止は、Computer Useツールを自前実装する最小構成の「バッチアクションでつまずきやすい3つの落とし穴」にまとまっています。ここではbrowser_toolset特有の設計と、ブラウザ操作の具体例に絞ります。
バッチアクションで往復回数が減る仕組み
バッチアクションとは、Claudeが独立した複数のメンバーツール呼び出しを1回の応答にまとめて返す仕組みです。応答の形はparallel tool useと同じで、違いはブロックを並列ではなく順番に実行する点だけです。
browser_toolset_20260801を1エントリ宣言すると、Claudeはnavigate・read_page・left_click・screenshotを含む27個のメンバーツールを既定で使えます。個々のメンバーは1操作しか表しませんが、Claudeは複数のメンバー呼び出しを1つのtool_use配列にまとめて返せます。
検索ボックスへの入力なら、クリック・入力・Enterの3操作が1ターンで返ります。バッチがなければ、tool_useとtool_resultのやり取りが3回に分かれる場面です。
アプリケーション側が1ターンぶんの応答を受け取ってからの動きは、次の4段階です。
バッチ1ターンぶんのエグゼキュータの動き
- 1
レスポンスの tool_use をすべて取り出す
response.contentのtool_useブロックを全部拾います。ブロックは1つとは限りません。ストリーミング時も各メンバーのinputは1つの完全なinput_json_deltaとして届くため、ターンの完了を待ってから実行します。 - 2
出現順に1つずつ実行する
後ろのブロックは前のブロックの結果を前提にしがちです。クリックで当たったフォーカスに、次の
typeが文字を入れる、といった関係です。並列には走らせません。 - 3
失敗したらそこで止める
成功したブロックは通常の結果、失敗したブロックは
is_error: trueとエラー文、それ以降はすべて打ち切りの文言で答えます。 - 4
全ブロックぶんの結果を1つの user メッセージで返す
どの
tool_resultにもtoolset_name: "browser"を付けます。1つでも答えが欠けると、次のリクエストが拒否されます。
クリック・入力・Enterを1回のtool_useにまとめる例
Claudeが返すバッチは、toolset_name: "browser"を持つtool_useブロックが複数並んだ配列です。先に見つけた検索ボックスをクリックし、クエリを入力し、Enterを押す例は次の形になります。
{
"role": "assistant",
"content": [
{
"type": "tool_use",
"id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
"name": "left_click",
"toolset_name": "browser",
"input": { "target": { "type": "ref", "ref": "ref_3" } }
},
{
"type": "tool_use",
"id": "toolu_01Ez4kLb1nQ2vXo8sJ9pWm3c",
"name": "type",
"toolset_name": "browser",
"input": { "text": "install" }
},
{
"type": "tool_use",
"id": "toolu_01FkP8rTz6uYh2mNq4LsXw7v",
"name": "key",
"toolset_name": "browser",
"input": { "text": "Enter" }
}
]
}実行後、アプリケーションは3つのtool_resultブロックを1つのuserメッセージにまとめて返します。それぞれがtoolset_name: "browser"と、Clicked element ref_3.のような短い実行確認テキストを持ちます。Enterで検索結果ページに遷移したなら、keyの結果にはタブの最新URLを示すbrowser_stateブロックも添えられます。
ディスパッチと打ち切りを書く
エグゼキュータでは、どのメンバーを実行するかをnameだけでなく(toolset_name, name)の組で振り分けます。自前のツールがnavigateのような名前を持っていても、toolset_nameが異なるため衝突しません。
バッチを順に回して、最初の失敗以降を打ち切るループは次のように書けます。有効にしていないメンバーが呼ばれたときも、エラー結果で答えます。
type Block = { id: string; name: string; input: Record<string, unknown> };
type Handler = (input: Record<string, unknown>) => Promise<string>;
const result = (id: string, content: string, isError = false) => ({
type: "tool_result" as const,
tool_use_id: id,
toolset_name: "browser",
content,
...(isError ? { is_error: true } : {}),
});
async function runBatch(blocks: Block[], handlers: Record<string, Handler>) {
const results = [];
let halted = false;
for (const b of blocks) {
if (halted) {
results.push(result(b.id, "Not executed: an earlier action in this turn failed.", true));
continue;
}
const handler = handlers[b.name];
if (!handler) {
halted = true;
results.push(result(b.id, `Error: ${b.name} is not enabled in this environment.`, true));
continue;
}
try {
results.push(result(b.id, await handler(b.input)));
} catch (e) {
halted = true;
results.push(result(b.id, `Error: ${(e as Error).message}`, true));
}
}
return { role: "user", content: results };
}人が確認する工程をはさむなら、その確認は各ブロックを実行する直前に置きます。browser use toolのドキュメントは、1ターンに複数の呼び出しが乗りうるため、各呼び出しの前に確認するよう求めています。ターンの先頭で1回だけ確認すると、後ろのブロックは承認なしで走ります。
ループ全体の組み立て方は、Python SDKのtool_runnerでツール呼び出しの自動実行ループを組む節にまとまっています。
途中で失敗したとき、Claudeには何が見えるか
3操作のバッチで、先頭のleft_clickがref_3の失効で失敗したとします。Claudeに返す結果は次の3つです。
| ブロック | is_error | content |
|---|---|---|
left_click | is_errortrue | contentError: ref_3 is stale or not found on the current page. Re-read the page to get fresh references. |
type | is_errortrue | contentNot executed: an earlier action in this turn failed. |
key | is_errortrue | contentNot executed: an earlier action in this turn failed. |
Claudeはどこで止まったかを見て、次のターンでread_pageなどからやり直します。打ち切られたブロックの結果が欠けると、invalid_request_errorになります。
参照の有効期間のルールから、バッチの組み方にも影響が出ます。参照は発行したタブが遷移するかDOMが大きく変わるまで有効なので、ページ遷移を起こす操作の後ろに、遷移前に発行された参照を使う呼び出しが続くと、後ろの呼び出しが失敗します。エグゼキュータ側では、タブが遷移するまで発行済みの参照番号を振り直さないようにします。Claudeがまだ持っている参照が黙って別の要素を指すようになるためです。
失敗したブロックの最中に新しいタブが開いた場合、その呼び出しの結果はエラーなのでbrowser_stateを持てません。タブの存在は、次に成功した結果のtabs一覧に現れます。
観察結果とbrowser_stateを結果に添える
Claudeは通常、バッチの最後をscreenshot・read_page・get_page_textのいずれかで締めくくり、実行結果を目視してから次のアクションを決めます。締めくくりの呼び出しが無いバッチが返ってきた場合、アプリケーション側からスクリーンショットや最新のアクセシビリティツリーを最後の結果に追加のコンテンツブロックとして添えられます。Claudeが改めてscreenshotを要求する往復を1回省ける形です。
添える先は選びます。タブ管理系の結果はbrowser_stateブロック1つだけに固定されているため、観察結果はタブ管理呼び出し以外の最後の結果に添えます。
browser_stateのレンダリングには、バッチならではの注意点が3つあります。
- 画像だけの結果(
screenshotのようにテキストを持たない結果)には、Claudeに見えるタブ情報の「Tab Context」フッターが付きません。タブの変化を同じ結果で見せたいなら、画像に短いテキストを添えます zoomの結果には、browser_stateを付けてもフッターが付きません- 同じタブ状態はフッターが重複排除されるので、
browser_stateは多めに付けても追加コストがかかりません
バッチの中でタブの状態が変わったときは、変化が起きた呼び出しの結果にブロックを付けます。タブ管理系の結果が成功したら、直前の結果が同じ状態を報告済みでも、それぞれ自分のブロックを持ちます。
毎回のバッチを必ずスクリーンショットで終わらせたいときは、アプリケーション側で添える代わりに、システムプロンプトでClaudeに依頼する方法もあります。画像を撮る処理は、Claudeのscreenshot呼び出しとして実行されます。computer use toolのドキュメントには、次の指示文が例として載っています。
End each group of actions with a screenshot so you can verify the result before continuing.画像を積み上げるときは上限にも注意します。APIは画像を縮小しないため、モデルごとの画像サイズ上限を超える画像は拒否されます。リクエストに20枚を超える画像が含まれると、さらに厳しい1枚あたりの上限が適用され、それまでの結果に含まれる画像も数えられます。
タブ管理呼び出しをバッチに混ぜるときの制約
new_tab・list_tabs・switch_tab・close_tabの4つは、成功時にbrowser_stateブロックをちょうど1つだけ返し、テキストや画像は持てません。これは31個のメンバーのうちタブ管理系の4つだけに課された制約です。Claudeが読むテキストはAPIがブロックから組み立てます。
クリックやスクリーンショットの結果には短い確認テキストや画像を添えられますが、タブ管理の結果はタブの一覧・アクティブタブ・URLといった状態だけを運びます。new_tabの結果では、state_changesのtab_openedがactive: trueのタブと一致している必要があります。タブを開く操作と通常の操作を混在させるときは、この形の違いを踏まえてエグゼキュータの分岐を書きます。
disable_parallel_tool_useを使うとバッチの形はどう変わるか
エグゼキュータが1往復につき1呼び出ししか処理できない設計なら、tool_choiceにdisable_parallel_tool_use: trueを指定します。Claudeは1ターンにつきメンバー呼び出しを最大1つしか返さなくなり、往復回数が増えるのと引き換えに、打ち切りの処理が要らなくなります。
このオプションを有効にしても、結果のcontentの規約は通常のバッチと変わりません。
tool_choiceには落とし穴もあります。typeがtoolでbrowserやメンバー名を指定すると、リクエストエラーになります。1つのメンバーだけを使わせたいときは、configsでほかのメンバーを無効にする形で絞ります。
要素参照と座標、2つのターゲット指定をバッチ内で使い分ける
バッチ内のleft_clickやhoverのようなポインタ系メンバーは、targetにviewportピクセルの座標(CoordinateTarget)か、read_pageやfindが返した要素参照(RefTarget)のどちらかを渡します。アクセシビリティツリーが使えるページでは参照を優先すると、レイアウトのずれに強く、座標では狙いにくい要素にも作用できます。
キャンバス描画のUIや埋め込み動画、クロスオリジンのiframe内の要素はツリーに現れないことがあり、その場合Claudeはscreenshotやzoomを見て座標クリックに切り替えます。1つのバッチの中で参照クリックと座標クリックが混在しても構いません。エグゼキュータ側はtarget.typeが"ref"か"coordinate"かで分岐すれば足ります。
参照はエグゼキュータが発行し、参照とDOMノードの対応もエグゼキュータが持ちます。Claudeが渡した参照をエグゼキュータが認識できなければ、Error: ref_3 is stale or not found on the current page. Re-read the page to get fresh references.のようなエラー結果を返すと、Claudeはページを読み直してから参照を作り直します。APIの側では失効した参照を検知できません。
仮想化されたリストや、スクロールのたびに再描画されるページでは、安定した参照が得られないことがあります。そうしたページでClaudeが座標クリックに寄るのは、想定された動きです。
Computer use toolのバッチアクションとの違い
browser_toolsetのバッチアクションは、computer use toolのバッチアクションと同じ「順番に実行し、最初の失敗で残りを打ち切る」という骨格を共有します。computer use toolから実装を移すときに書き換える点を並べます。
同じ骨格で変わる4点
Computer use tool
- メンバーは17個で、
toolset_nameは"computer" - 座標は
"coordinate": [640, 60]の配列で渡す - 打ち切りの文言は
Not executed: an earlier computer action in this turn failed. screenshot・zoom以外の成功結果はOKのような短いテキストで足りる
Browser use tool
- メンバーは既定27個(任意の4つを足すと31個)で、
toolset_nameは"browser" - 座標は
targetオブジェクト(type・x・y)か、要素参照のrefで渡す - 打ち切りの文言は
Not executed: an earlier action in this turn failed. - タブ管理系の成功結果は
browser_stateブロック1つに固定され、ほかはbrowser_stateを添えられる
打ち切りの文言はcomputerの1語があるかないかの違いですが、文字列は完全一致で返す指定です。実装を使い回すときは、この文言をtoolsetごとに切り替えます。
自前のツールやcomputer use toolと組み合わせる場合
browser use toolは、自前のカスタムツールやcomputer use toolと同じtools配列の中に宣言して組み合わせられます。browserという名前の別のツールを置くことはできず、ブラウザのツールセットのエントリも1つのリクエストに1つだけです。
computer use toolと併用すると、両者は別々の座標系で動きます。browser use toolはビューポートピクセル、computer use toolはデスクトップのスクリーンショットピクセルが基準で、screenshotやkeyのように名前が重なるメンバーもtoolset_nameで見分けます。1つのバッチに両方のツールセットのブロックが混ざることもあるため、エグゼキュータのディスパッチはname単独ではなくtoolset_name込みで組みます。
プロンプトキャッシュを使うなら、バッチ内のcache_controlの扱いも押さえます。computer use toolのドキュメントでは、バッチ内の複数ブロックに付けたマーカーは1つのブレークポイントとして働きます。ただし、それぞれが上限の4つにも数えられるため、1ターンにつき1つに絞るよう勧めています。
Message Batches APIと混同しないために
「バッチ」という語は、Anthropic APIのもう1つの機能であるMessage Batches APIとも重なります。両者は別の仕組みです。
browser use toolのバッチアクションは、1回のターンに複数のtool_use呼び出しをまとめて往復回数を減らす仕組みです。一方でMessage Batches APIは、多数の独立したMessagesリクエストをまとめて非同期に処理する機能で、リアルタイムの会話ではなく大量データの一括処理に向きます。実装の作法はClaudeのMessage Batches SDKをPython・TypeScript・Ruby・Javaで実装するにまとめています。
料金への影響
browser_toolset_20260801を既定のメンバーで宣言すると、ツール定義とツール使用のシステムプロンプト分として入力トークンが加わります。
宣言だけで加わる入力トークンの目安
既定のメンバー
約6,600
Claude Fable 5・Claude Mythos 5・Claude Opus 5・Claude Opus 4.8は約6,610
Claude Sonnet 5
約6,670
ツール定義とシステムプロンプトの合計
任意の4メンバーを足す
+約880
javascript_exec・file_upload・read_console・read_network
バッチアクション自体はこの宣言コストを下げる仕組みではなく、あくまで往復の回数を減らす設計です。configsでメンバーを無効化すれば、その分だけ宣言コストは減ります。正確なトークン数はレスポンスのusageに返るため、事前に見積もる場合はtoken counting endpointを使います。
返したスクリーンショットやzoomの画像は画像入力として、アクセシビリティツリーやページテキスト、コンソール・ネットワークのエントリはテキスト入力として課金対象になります。バッチの最後に毎回画像を添える運用は、この追加分と引き換えです。
対応モデルとプラットフォーム、セキュリティ上の注意
browser use toolは、Claude APIとGoogle Cloud(Vertex AI)経由で使えます。Claude Platform on AWS・Amazon Bedrock・Microsoft Foundryでは提供されていません。
対応モデルは次の9つです。
- claude-fable-5-1・claude-mythos-5-1・claude-fable-5・claude-mythos-5
- claude-opus-5-5・claude-opus-5・claude-opus-4-8
- claude-sonnet-5-5・claude-sonnet-5
上記以外のモデルでbrowser_toolset_20260801を指定すると、リクエストエラーになります。
ZDR(ゼロデータリテンション)の対象です。ただし、データ保持に個別の要件があるモデルは除かれます。ブラウザのセッションやダウンロード、アップロードしたファイルは自分の環境に残ります。返したスクリーンショットやページテキスト、タブ状態はAPIリクエストの一部なので、通常の保持ポリシーに従います。
Claudeは開いたウェブページの内容をそのまま読み取ります。ページ側に操作を誘導する文言が仕込まれていることもあります。タブのタイトルやURLも、Claudeが読むテキストにそのまま描画されるため、ページ由来のURLはbrowser_stateに入れる前に無害化します。専用のコンテナや仮想マシンで、資格情報を持たないプロフィールを使って隔離する運用が前提になります。
まとめ
エグゼキュータが順次実行と最初の失敗での打ち切りを持てるなら、Claudeが返すバッチをそのまま受けられます。持てないなら、disable_parallel_tool_use: trueで1往復1呼び出しに止めるのが切り分けです。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。