第2章 アーキテクチャ ── エージェントループの解剖
全体像
browser-useの内部構造を理解するには、「LLMとブラウザの間にあるもの」を一層ずつ剥がして見る必要がある。
graph TD
subgraph BU["browser-use スタック"]
TASK["タスク指示(自然言語)"]
AGENT["エージェントコア<br/>(ループ管理・状態追跡)"]
LLM["LLMインテグレーション層<br/>(ChatBrowserUse / Claude / GPT-4 / Gemini)"]
PERCEIVE["知覚層<br/>(Screenshot + Accessibility Tree + DOM)"]
PW["Playwrightアダプター<br/>(click / type / scroll / navigate)"]
BROWSER["ブラウザ<br/>(ローカルChromium / クラウドブラウザ)"]
end
TASK --> AGENT
AGENT --> LLM
LLM --> PERCEIVE
PERCEIVE --> AGENT
AGENT --> PW
PW --> BROWSER
BROWSER --> PERCEIVE
エージェントコアが全体のループを管理し、LLMとブラウザの間を仲介する。LLMは「何をするか」を決め、Playwrightアダプターが「実際にする」。
エージェントループ:Observe → Think → Act → Repeat
browser-useの動作原理は「Observe → Think → Act → Repeat」の繰り返しだ。
flowchart TD
START["タスク開始<br/>(自然言語指示)"]
OBS["① Observe<br/>ページのスクリーンショット<br/>+ Accessibility Tree<br/>+ 現在のURL・タイトル"]
THINK["② Think<br/>LLMが現在状態を分析し<br/>次のアクションを決定"]
ACT["③ Act<br/>click / type / scroll / navigate<br/>などを実行"]
CHECK["④ Check<br/>タスク完了か?<br/>エラーが起きたか?"]
DONE["タスク完了・結果返却"]
START --> OBS
OBS --> THINK
THINK --> ACT
ACT --> CHECK
CHECK -- 継続 --> OBS
CHECK -- 完了 --> DONE
CHECK -- エラー回復 --> OBS
各ステップを詳しく見る。
① Observe:ページをどう「見るか」
これがbrowser-useの技術的核心だ。「ページを見る」にはいくつかの方法があり、browser-useはそれらを組み合わせる。
スクリーンショット(視覚情報)
ブラウザの現在状態を画像として撮影し、マルチモーダルLLMに渡す。人間が「画面を見る」のと同じだ。
強み:Canvas要素・カスタムレンダリング・CSSビジュアル・画像内テキストを認識できる。HTMLでは表現されない視覚的情報を把握できる。
弱み:座標依存(ピクセル位置でクリックするため、レイアウト変更に弱い)。推論コストが高い。
Accessibility Tree(意味情報)
ブラウザが内部的に保持するアクセシビリティツリーをテキストとして取得する。役割(role)・ラベル・状態・インタラクション可能かどうかがコンパクトに表現される。
# Accessibility Tree の例(一部)
main[role=main]
heading[level=1] "browser-use/browser-use"
link[href=/browser-use/browser-use/stargazers] "81.2k stars"
link[href=/browser-use/browser-use/forks] "8.7k forks"
button[expanded=false] "Star"
強み:構造化・コンパクト・クリック対象の特定が安定している。DOM変更に対してスクリーンショットより堅牢。
弱み:視覚的なレイアウト・位置関係・スタイル情報は含まれない。
DOM(構造情報)
生のHTMLではなく、整形・フィルタリングされたDOM表現。
browser-useは三つの表現を状況に応じて組み合わせる。通常時はAccessibility Tree + スクリーンショット、DOM要素の特定が難しいときはDOMを追加参照する。これにより「スクリーンショットだけ」でも「DOMだけ」でもない、ハイブリッドな高精度な認識が実現される。
graph LR
PAGE["Webページ"]
SS["スクリーンショット<br/>視覚情報・Canvas・画像"]
AT["Accessibility Tree<br/>意味情報・構造・クリック対象"]
DOM["DOM<br/>HTML構造・属性・テキスト"]
LLM["LLM<br/>(統合して判断)"]
PAGE --> SS
PAGE --> AT
PAGE --> DOM
SS --> LLM
AT --> LLM
DOM --> LLM
② Think:LLMが判断する
LLMへのプロンプトには以下の情報が含まれる。
LLMへの入力(1ステップあたり)
1. タスク指示(ユーザーが最初に与えた自然言語)
2. 現在のページ状態(スクリーンショット + Accessibility Tree)
3. これまでに実行したアクション履歴
4. 利用可能なアクション一覧(click, type, scroll, navigate, ...)
5. AGENTS.md / システムプロンプト(カスタマイズがある場合)
LLMへの要求:
- 現在の状態を分析し
- タスクを完了するために次に取るべき最善のアクションを1つ選び
- 構造化された形式(JSON)で返す
LLMは思考過程とともに次のアクションをJSON形式で出力する。
{
"thought": "検索ボックスが見えている。タスクに必要なリポジトリ名を入力する",
"action": {
"type": "click",
"element_ref": "search-box-ref-14"
}
}
③ Act:Playwrightが実行する
LLMが出力したアクション指示をPlaywrightのAPIに変換して実行する。
| LLMのアクション指示 | Playwrightのコール |
|---|---|
click(element_ref=...) | page.click(selector) |
type(text=...) | page.fill(selector, text) |
scroll(direction=down, amount=3) | page.evaluate("window.scrollBy(0, 300)") |
navigate(url=...) | page.goto(url) |
screenshot() | page.screenshot() |
extract_content() | DOM読み取り |
④ Check:エラー回復とタスク完了判定
各アクションの後、エージェントは状態をチェックする。
タスク完了の判定:LLMが「タスクが完了した」と判断するか、明示的な完了条件(max_stepsに達した、期待する情報が取得できたなど)に達したとき。
エラー回復(Self-Healing):browser-useの重要機能の一つだ。アクションが失敗した場合(要素が見つからない、タイムアウト、予期しないポップアップなど)、エラー情報をLLMに渡して別のアプローチを試みる。
エラー回復の例
実行:button[label="閉じる"] をクリック
結果:要素が見つからない(Timeout)
→ エラー情報をLLMに渡す
LLMが再判断:「モーダルダイアログが閉じボタンの代わりにESCキーで閉じるかもしれない」
→ keyboard.press("Escape") を実行
→ 成功
メモリと状態管理
browser-useはタスク実行中の状態を複数の形で管理する。
状態管理の種類
エージェント実行中メモリ:
- アクション履歴(今まで何をしたか)
- 収集済み情報(スクレイピングしたデータ等)
- エラー履歴(何が失敗したか)
セッション間の継続性:
- ブラウザプロファイル(Cookieやログイン状態の保持)
- ワークフロー記録(成功したアクションシーケンスの保存)
ブラウザプロファイルの再利用:既存のChromeプロファイルを引き継ぐことで、Googleやnotionなど既にログイン済みのサービスにもエージェントが直接アクセスできる。認証フローを自動化する必要がなくなる。
パフォーマンスとコストの現実
エージェントループは「1ステップ = 1回のLLM呼び出し」だ。
コスト試算(参考)
平均タスク所要時間:約62秒(BU 2.0)
平均ステップ数:5〜15ステップ
1ステップあたりのLLMコスト:
GPT-4o 約$0.01〜0.05
Claude 3 約$0.01〜0.03
1タスクあたり:$0.05〜$0.50程度
高ボリューム(月1万タスク):$500〜$5,000/月
このコスト構造は「決定論的なPlaywrightスクリプトと比べて桁違いに高い」という評価に直結している。Playwrightでできる単純な繰り返し作業をbrowser-useでやるのは非合理。browser-useが正当化されるのは「ページ構造が変わっても動く必要がある」「手動でスクリプトを書けないほど複雑な判断が必要」なケースだ。
二モードの設定
browser-useには二つの動作モードがある。
# モード1:ローカルブラウザ(OSS)
from browser_use import Browser, BrowserConfig
browser = Browser(config=BrowserConfig(
headless=False, # ブラウザウィンドウを表示
))
# モード2:クラウドブラウザ(Browser Use Cloud)
browser = Browser(config=BrowserConfig(
cdp_url="wss://connect.browseruse.com/...", # クラウドブラウザに接続
))
# または
browser = Browser(config=BrowserConfig(use_cloud=True))
次章でこの二モードの違いと使い分けを詳しく扱う。