🙆

ブラウザ操作型のAIエージェントのbrowser-use/browser-use のコードリーディングをしてみる

に公開

Cursorに色々と聞いてみて、今話題のBrowser Useというレポジトリの理解を深めてみたいと思います。

https://github.com/browser-use/browser-use

ちなみに、Browser UseはYC採択のスタートアップのようです。
https://browser-use.com/

レポジトリの説明

このレポジトリの説明をしてください。

まず、このレポジトリの内容を確認させていただきます。

Ran tool

READMEの内容を確認させていただきます。

Read file: README.md

このプロジェクトについて説明させていただきます:

Browser Useは、AIエージェントがウェブブラウザと簡単に連携できるようにするためのPythonライブラリです。主な特徴は以下の通りです:

  1. 主な機能:

    • ビジョン機能とHTML抽出
    • 自動マルチタブ管理
    • クリックされた要素のXPathの抽出とLLMアクションの再現
    • カスタムアクション機能(ファイル保存、データベース操作、通知など)
    • 自己修正機能
    • LangChainでサポートされている様々なLLM(GPT-4、Claude 3.5など)との互換性
    • 複数のエージェントの並列処理
  2. 技術スタック:

    • Python 3.11以上
    • Playwrightを使用したブラウザ操作
    • LangChainとの統合
  3. 使用例:

    • 求人検索と応募の自動化
    • 航空券の検索
    • Hugging Faceでのモデル検索
    • その他のウェブ自動化タスク
  4. ライセンス: MITライセンス

このプロジェクトは、AIエージェントがウェブブラウザを通じて実際のウェブサイトとインタラクションを行うことを可能にし、様々な自動化タスクを実行できるようにすることを目的としています。

ディレクトリの構成を説明して

はい、プロジェクトのディレクトリ構成を詳しく確認していきます。

Ran tool

主要なディレクトリの内容も確認させていただきます:

Ran tool

プロジェクトの主要なディレクトリ構成について説明いたします:

  1. メインディレクトリ:

    • browser_use/: メインのソースコードディレクトリ
      • agent/: AIエージェントの実装
      • browser/: ブラウザ操作の実装
      • controller/: コントロール機能の実装
      • dom/: DOM操作関連の実装
      • telemetry/: 使用統計の収集機能
      • utils.py: ユーティリティ関数
      • logging_config.py: ロギング設定
  2. 補助ディレクトリ:

    • static/: 静的ファイル(画像など)
    • tests/: テストコード
    • examples/: サンプルコード
  3. 設定ファイル:

    • pyproject.toml: Pythonプロジェクトの設定
    • pytest.ini: テスト設定
    • .env.example: 環境変数のテンプレート
    • .python-version: Python バージョン指定
  4. 開発環境関連:

    • .vscode/: VSCode設定
    • .github/: GitHub関連の設定
    • .gitignore: Git除外設定
    • .gitattributes: Gitの属性設定

この構成は、モジュール性が高く、テスト可能で、メンテナンスしやすい設計になっています。メインの機能はbrowser_useディレクトリに集約されており、各サブディレクトリが特定の責務を担当しています。

ディレクトリごとのフォルダはどのように相互作用しますか?

各ディレクトリ間の相互作用を理解するために、まず主要なコンポーネントの関係を確認させていただきます。

Search files...

主要なコンポーネント間の相互作用について説明いたします:

  1. Agent(エージェント):

    • システムの中心的な存在で、以下のコンポーネントを統括します:
    • Browserインスタンスを管理し、ウェブページとの対話を制御
    • Controllerを使用してアクションを実行
    • LLM(Language Model)を使用してタスクを理解し、次のアクションを決定
  2. Browser(ブラウザ):

    • Playwrightを使用してブラウザを制御
    • 複数のコンテキスト(タブ)を管理
    • ページの状態を取得し、DOMツリーを構築
    • ファイルアップロードやスクリーンショットなどの特殊な操作を処理
  3. Controller(コントローラー):

    • 様々なブラウザアクションを登録・管理(例:クリック、スクロール、テキスト入力など)
    • アクションの実行を制御し、結果をActionResultとして返す
    • カスタムアクションの登録機能を提供
  4. 相互作用の流れ:

  1. データの流れ:

    • Agent: タスクを受け取り、LLMを使用して解析
    • LLM: 次のアクションを決定
    • Controller: アクションを実行
    • Browser: ウェブページと対話し、結果を返す
    • Agent: 結果を評価し、次のステップを決定
  2. カスタマイズ可能なポイント:

    • カスタムアクションの追加
    • ブラウザの設定(ヘッドレスモード、セキュリティ設定など)
    • 複数のエージェントの並列実行
    • 異なるLLMモデルの使用

このアーキテクチャにより、AIエージェントがウェブブラウザを通じて効果的にタスクを実行できる柔軟で拡張可能なシステムが実現されています。

どのような設計思想やアーキテクチャで構成されていると思いますか?

このプロジェクトの設計思想とアーキテクチャについて分析させていただきます:

  1. クリーンアーキテクチャの採用:

    • 明確な関心の分離(Separation of Concerns)
    • 各コンポーネントが独立して動作可能
    • 依存性の方向が内側に向かう設計
  2. モジュラー設計:

browser_use/
├── agent/        # AIエージェントのコア機能
├── browser/      # ブラウザ操作の抽象化
├── controller/   # アクション制御と実行
├── dom/          # DOM操作とツリー構築
└── telemetry/    # 使用統計と監視
  1. デザインパターンの活用:

    • Factory Pattern: BrowserBrowserContextの生成
    • Registry Pattern: Controllerでのアクション登録
    • Command Pattern: アクションの実装方式
    • Observer Pattern: 状態変更の監視とイベント処理
  2. SOLID原則の適用:

    • 単一責任の原則: 各クラスが明確な役割を持つ
    • 開放閉鎖の原則: カスタムアクションの追加が容易
    • インターフェース分離: 明確なインターフェース定義
    • 依存性逆転: 抽象化に依存する設計
  3. 非同期処理の重視:

    • async/awaitを活用した非同期操作
    • 効率的なリソース管理
    • 並列処理のサポート
  4. 拡張性を考慮した設計:

@controller.action('Custom Action')
async def custom_action(params, browser):
    # カスタムアクションの実装
    pass
  1. 型安全性の重視:

    • Pydanticを使用したデータバリデーション
    • 明示的な型ヒント
    • カスタムモデルの定義
  2. エラー処理とリカバリー:

try:
    result = await self.controller.multi_act(
        model_output.action, self.browser_context
    )
except Exception as e:
    result = self._handle_step_error(e)
  1. 設定の柔軟性:
browser = Browser(
    config=BrowserConfig(
        headless=False,
        disable_security=True,
        extra_chromium_args=['--window-size=2000,2000'],
    )
)
  1. テスト容易性:

    • モジュラー設計によるユニットテストの容易さ
    • モック可能なインターフェース
    • テスト用の設定分離
  2. セキュリティ考慮:

    • 環境変数による機密情報の管理
    • セキュリティ設定のカスタマイズ
    • エラー時の安全な処理
  3. ロギングと監視:

    • 詳細なロギング機能
    • テレメトリーデータの収集
    • デバッグ情報の提供

この設計により、以下の利点が得られています:

  1. 保守性: モジュラー設計により、個々のコンポーネントの修正が容易
  2. 拡張性: 新機能の追加が簡単
  3. テスト容易性: ユニットテストとモックが容易
  4. 再利用性: コンポーネントの再利用が可能
  5. 理解しやすさ: 明確な責任分離により、コードの理解が容易

このアーキテクチャは、AIエージェントとブラウザの相互作用を効率的に管理しながら、将来の拡張性も考慮した堅牢な設計となっています。

コードのフロー

ユーザーはどのようにこのレポジトリを実行しますか?また、実行されるときのコードの流れの概観を教えて下さい。

ユーザーの実行方法と、コードの実行フローについて説明いたします。

1. 基本的な実行方法:

# 1. インストール
pip install browser-use

# 2. (オプション) Playwrightのインストール
playwright install

# 3. 環境変数の設定
# .envファイルに以下を設定
OPENAI_API_KEY=your_key_here
ANTHROPIC_API_KEY=your_key_here

# 4. 基本的な実行コード
from langchain_openai import ChatOpenAI
from browser_use import Agent
import asyncio

async def main():
    agent = Agent(
        task="Google Flightsで2025年1月12日のバリからオマーンへの片道フライトを検索し、最安値を返してください。",
        llm=ChatOpenAI(model="gpt-4"),
    )
    result = await agent.run()
    print(result)

asyncio.run(main())

2. コードの実行フロー:

3. 主要なコードパス:

  1. 初期化フェーズ:
# Agentの初期化
agent = Agent(
    task=task,
    llm=model,
    browser=browser,  # オプション
    controller=controller  # オプション
)
  1. 実行フェーズ:
# agent.run()の内部処理
async def run(self):
    while not self.is_done():
        # ブラウザの状態を取得
        state = await self.browser_context.get_state()
        
        # LLMに次のアクションを問い合わせ
        model_output = await self.get_next_action()
        
        # アクションを実行
        result = await self.controller.multi_act(
            model_output.action, 
            self.browser_context
        )
        
        # 結果を処理
        self._process_results(result)
  1. アクション実行フェーズ:
# Controllerでのアクション実行
async def act(self, action: ActionModel, browser_context: BrowserContext):
    # アクションの種類に応じた処理を実行
    result = await self.registry.execute_action(
        action_name, 
        params, 
        browser=browser_context
    )
    return ActionResult(...)

4. カスタマイズ可能なポイント:

  1. ブラウザ設定:
browser = Browser(
    config=BrowserConfig(
        headless=False,  # UIを表示
        disable_security=True,
        extra_chromium_args=['--window-size=2000,2000'],
    )
)
  1. カスタムアクション追加:
@controller.action('カスタムアクション')
async def custom_action(params, browser):
    # カスタムアクションの実装
    return ActionResult(...)
  1. 並列実行:
browser = Browser()
async with browser.new_context() as context:
    agent1 = Agent(task="タスク1", browser_context=context)
    agent2 = Agent(task="タスク2", browser_context=context)
    await asyncio.gather(agent1.run(), agent2.run())

このように、ユーザーは簡単な初期化コードで複雑なブラウザ操作を自動化でき、必要に応じて詳細なカスタマイズも可能な設計となっています。実行フローは非同期処理を活用し、効率的なリソース利用と柔軟な拡張性を実現しています。

このレポジトリを実行するための手順を教えて下さい。

このレポジトリを起動するための手順を説明いたします。

  1. 環境のセットアップ:
# 1. レポジトリをクローンしたディレクトリに移動
cd browser-use

# 2. Python環境の設定(.python-versionファイルから必要なバージョンを確認)

Read file: .python-version


# 3. 依存関係のインストール(開発用の依存関係も含む)
pip install . ."[dev]"

# 4. Playwrightのインストール
playwright install
  1. 環境変数の設定:

Read file: .env.example

# .envファイルを作成
cp .env.example .env

# .envファイルを編集して必要なAPIキーを設定
  1. 実行方法:

サンプルコードを実行する場合:

# examplesディレクトリのサンプルを実行
python examples/try.py --query "あなたのタスク"

または、カスタムスクリプトを作成して実行:

# custom_script.py
from langchain_openai import ChatOpenAI
from browser_use import Agent
import asyncio

async def main():
    agent = Agent(
        task="実行したいタスクの説明",
        llm=ChatOpenAI(model="gpt-4"),
    )
    result = await agent.run()
    print(result)

asyncio.run(main())

そして実行:

python custom_script.py
  1. デバッグモード:
# より詳細なログを表示する場合は、.envファイルで以下のように設定
BROWSER_USE_LOGGING_LEVEL=debug
  1. テストの実行:
# テストを実行する場合
pytest

注意点:

  • OpenAI APIキーまたはAnthropic APIキーが必要です
  • Python 3.11以上が必要です
  • ブラウザ(Chrome/Chromium)が自動的にインストールされます
  • テレメトリーは.envファイルで無効化できます

これらのコマンドで、レポジトリを実行する準備が整います。実行時にエラーが発生した場合は、主に以下を確認してください:

  • Python バージョンが3.11以上であること
  • 必要なAPIキーが正しく設定されていること
  • 依存関係が正しくインストールされていること

サンプルコードを実行する場合に、どのようなサンプルをどのようなプロンプトで実行できますか?すべてのパターンを教えて下さい。

examplesディレクトリのサンプルコードを確認させていただきます。

Ran tool

各サンプルの実行方法と使用例を説明いたします:

  1. 基本的な検索と操作:
# Amazonでの検索
python examples/amazon_search.py
# プロンプト例: "Search for wireless headphones on Amazon and find the top-rated option under $100"

# Google Flightsでの検索(web_voyager_agent.py)
python examples/web_voyager_agent.py
# プロンプト例:
# - "Find flights from Tokyo to New York from March 1-15, 2024"
# - "Find a hotel in Paris for 2 adults from April 1-5, 2024"
  1. マルチタブ処理:
# 複数タブの操作
python examples/multi-tab_handling.py
# プロンプト例: "Open three different news websites in separate tabs and summarize the top headlines"

# 複数エージェントでの同時操作
python examples/multiple_agents_same_browser.py
# プロンプト例: "Open Wikipedia articles about AI and summarize them in parallel"
  1. 求人検索と応募:
# 求人検索と応募の自動化
python examples/find_and_apply_to_jobs.py
# プロンプト例: "Find software engineering jobs in San Francisco and save the listings"
  1. カスタム機能:
# ファイルアップロード
python examples/file_upload.py
# プロンプト例: "Upload my resume to a job application site"

# カスタム出力形式
python examples/custom_output.py
# プロンプト例: "Search for products and format the results in a specific way"

# カスタムシステムプロンプト
python examples/custom_system_prompt.py
# プロンプト例: "Use a specialized prompt for specific search patterns"
  1. 特殊なユースケース:
# CAPTCHA処理
python examples/captcha.py
# プロンプト例: "Handle website with CAPTCHA verification"

# 予約確認
python examples/check_appointment.py
# プロンプト例: "Check available appointment slots for next week"

# スクロール処理
python examples/scrolling_page.py
# プロンプト例: "Scroll through a long webpage and collect all article titles"
  1. 結果処理と保存:
# 結果の処理
python examples/result_processing.py
# プロンプト例: "Search and save structured data from a website"

# Hugging Faceモデルの検索と保存
python examples/save_to_file_hugging_face.py
# プロンプト例: "Find and save information about specific ML models"

# トレース保存
python examples/save_trace.py
# プロンプト例: "Record and save the browser interaction sequence"
  1. 並列処理:
# 並列エージェント
python examples/parallel_agents.py
# プロンプト例: "Search multiple websites simultaneously for price comparison"
  1. 出力検証:
# 出力の検証
python examples/validate_output.py
# プロンプト例: "Perform a search with validated results"

一般的な使用方法:

# 汎用的な実行
python examples/try.py --query "あなたのタスク"

注意点:

  1. 各サンプルを実行する前に、必要な環境変数(APIキーなど)が設定されていることを確認
  2. 一部のサンプルは特定のウェブサイトやサービスに依存する場合があります
  3. CAPTCHAやログインが必要なサイトでは追加の設定が必要な場合があります
  4. 並列処理を行う場合は、システムリソースに注意が必要です

これらのサンプルは、ブラウザ自動化の様々なユースケースをカバーしており、必要に応じてカスタマイズすることも可能です。

エージェンテックフロー

python examples/amazon_search.pyを実行したときのコードの流れを具体的に教えて下さい。どのディレクトリのどのコードが順番に使われるのかを教えて下さい。

amazon_search.pyの実行フローを詳細に分析していきます。

まず、サンプルコードを確認します:

Read file: examples/amazon_search.py

実行フローを順番に説明します:

  1. 初期化フェーズ:
# 1. examples/amazon_search.py
llm = ChatOpenAI(model='gpt-4o')
agent = Agent(
    task='Go to amazon.com, search for laptop...',
    llm=llm,
)
  1. Agent初期化の内部フロー (browser_use/agent/service.py):
class Agent:
    def __init__(self, task, llm):
        # 1. エージェントIDの生成
        self.agent_id = str(uuid.uuid4())
        
        # 2. ブラウザの初期化
        self.browser = Browser()
        self.browser_context = BrowserContext(browser=self.browser)
        
        # 3. コントローラーの初期化
        self.controller = Controller()
        
        # 4. メッセージマネージャーの初期化
        self.message_manager = MessageManager(
            llm=self.llm,
            task=self.task,
            action_descriptions=self.controller.registry.get_prompt_description()
        )
  1. 実行フェーズ (agent.run()):
# browser_use/agent/service.py
async def run(self):
    while not self.is_done():
        # 1. ブラウザの状態を取得
        state = await self.browser_context.get_state()
        
        # 2. LLMに次のアクションを問い合わせ
        model_output = await self.get_next_action()
        
        # 3. アクションを実行
        result = await self.controller.multi_act(
            model_output.action,
            self.browser_context
        )
  1. 具体的なアクション実行フロー:

a. Amazonへの移動:

# browser_use/controller/service.py
@controller.action('Navigate to URL')
async def go_to_url(params: GoToUrlAction, browser: BrowserContext):
    page = await browser.get_current_page()
    await page.goto(params.url)  # "https://amazon.com"に移動

b. 検索の実行:

# browser_use/controller/service.py
@controller.action('Input text')
async def input_text(params: InputTextAction, browser: BrowserContext):
    element_node = state.selector_map[params.index]
    await browser._input_text_element_node(element_node, "laptop")

c. ソートとデータ取得:

# browser_use/controller/service.py
@controller.action('Click element')
async def click_element(params: ClickElementAction, browser: BrowserContext):
    element_node = state.selector_map[params.index]
    await browser._click_element_node(element_node)
  1. DOM操作 (browser_use/dom/):
# browser_use/dom/service.py
class DomService:
    async def get_dom_tree(self):
        # ページのDOM構造を取得
        return await self.page.evaluate(self.BUILD_DOM_TREE_JS)
  1. 結果の処理と返却:
# browser_use/agent/service.py
class Agent:
    def _process_results(self, result):
        if result.is_done:
            self.final_result = result.extracted_content

実行時の具体的なファイル呼び出し順序:

  1. examples/amazon_search.py

    • メインのエントリーポイント
  2. browser_use/__init__.py

    • 必要なクラスとモジュールのインポート
  3. browser_use/agent/service.py

    • Agentクラスの初期化と実行
  4. browser_use/browser/browser.py

    • ブラウザインスタンスの作成
  5. browser_use/controller/service.py

    • アクションの実行管理
  6. browser_use/dom/service.py

    • DOM操作の実行
  7. browser_use/browser/context.py

    • ブラウザコンテキストの管理

このフローで、以下のような順序でアクションが実行されます:

  1. Amazonのウェブサイトを開く
  2. 検索バーを見つけて「laptop」と入力
  3. 評価順でソート
  4. 最初の結果の価格を取得
  5. 結果を返却

各ステップで、LLMがページの状態を解析し、次に実行すべきアクションを決定します。これらのアクションはControllerを通じて実行され、結果がAgentに返されます。

task='Go to amazon.com, search for laptop, sort by best rating, and give me the price of the first result',を受け取って、どのようにそれらのアクションが選ばれるのですか?

タスクがどのようにアクションに変換されるかのプロセスを説明いたします。

  1. まず、タスクの処理がどのように始まるかを確認します

Search files...

Read file: browser_use/agent/prompts.py

タスクからアクションへの変換プロセスを説明します:

  1. 初期化フェーズ:
agent = Agent(
    task='Go to amazon.com, search for laptop, sort by best rating, and give me the price of the first result',
    llm=ChatOpenAI(model="gpt-4")
)
  1. タスク解析とプロンプト生成:
  • SystemPromptクラスがLLMへの指示を生成
  • 主要なルール:
    {
      "current_state": {
        "evaluation_previous_goal": "Success|Failed|Unknown...",
        "memory": "これまでの行動の記録",
        "next_goal": "次に実行すべきこと"
      },
      "action": [
        {
          "action_name": {
            // アクション固有のパラメータ
          }
        }
      ]
    }
    
  1. ステップごとの実行:
async def step(self):
    # 1. 現在のブラウザ状態を取得
    state = await self.browser_context.get_state()
    
    # 2. LLMに状態を送信して次のアクションを決定
    model_output = await self.get_next_action()
    
    # 3. アクションを実行
    result = await self.controller.multi_act(
        model_output.action,
        self.browser_context
    )
  1. 具体的なアクションシーケンス:
# 例:Amazonでの検索タスク
[
    # 1. Amazonに移動
    {"go_to_url": {"url": "https://amazon.com"}},
    
    # 2. 検索バーを見つけて入力
    {"input_text": {"index": "検索バーのインデックス", "text": "laptop"}},
    
    # 3. 検索ボタンをクリック
    {"click_element": {"index": "検索ボタンのインデックス"}},
    
    # 4. ソートオプションを選択
    {"click_element": {"index": "ソートボタンのインデックス"}},
    {"click_element": {"index": "評価順のオプションのインデックス"}},
    
    # 5. 最初の結果の価格を取得
    {"extract_page_content": {"value": "text"}},
    
    # 6. タスク完了を通知
    {"done": {"text": "最初の商品の価格は$XXXです"}}
]
  1. アクション選択の基準:
  • 利用可能な要素のインデックスを確認
  • 要素の種類(ボタン、入力フィールドなど)を考慮
  • ページの状態変化を予測
  • エラー処理とリカバリー戦略
  • 最大ステップ数の制限を考慮
  1. フィードバックループ:
  • 各アクション後の結果を評価
  • 必要に応じて戦略を修正
  • エラーが発生した場合の代替アプローチを検討

このように、タスクは段階的に実行可能なアクションに分解され、各ステップでLLMが現在の状態を評価して次のアクションを決定します。この過程は、ブラウザの状態やユーザーのタスクに応じて動的に調整されます。

SystemPromptを全文日本語で教えて下さい。また、browser_contextではなにを確認していますか?アクションシーケンスのプロンプトも使い方を分類して、全文日本語で教えて下さい。

まず、SystemPromptの全文を日本語で説明し、その後browser_contextとアクションシーケンスについて説明いたします。

1. SystemPromptの全文(日本語):

# メインの指示
あなたは、構造化されたコマンドを通じてウェブサイトと対話する正確なブラウザ自動化エージェントです。
あなたの役割は:
1. 提供されたウェブページの要素と構造を分析する
2. 与えられたタスクを達成するためのアクションシーケンスを計画する
3. アクションシーケンスと状態評価を含む有効なJSONで応答する

# 重要なルール
1. レスポンスフォーマット:
   必ず以下の形式の有効なJSONで応答してください:
   {
     "current_state": {
       "evaluation_previous_goal": "成功|失敗|不明 - 現在の要素と画像を分析し、前のゴール/アクションがタスクの意図通りに成功したかを確認。アクション結果は無視し、ウェブサイトが真実。入力フィールドの新しい提案など、予期せぬことが起きた場合も言及。理由を簡潔に説明",
       "memory": "これまでに実行したことと、タスク終了まで覚えておく必要があることの説明",
       "next_goal": "次のアクションで何をする必要があるか"
     },
     "action": [
       {
         "action_name": {
           // アクション固有のパラメータ
         }
       }
     ]
   }

2. アクション:
   複数のアクションを順序通りに実行するように指定できます。

3. 要素との対話:
   - 提供された要素リストに存在するインデックスのみを使用
   - 各要素には一意のインデックス番号がある(例:"33[:]<button>"
   - "_[:]"でマークされた要素は非対話的(コンテキスト用のみ)

4. ナビゲーションとエラー処理:
   - 適切な要素が存在しない場合、他の機能を使用してタスクを完了
   - 行き詰まった場合、代替アプローチを試行
   - ポップアップ/クッキーは受け入れるか閉じる
   - 探している要素を見つけるためにスクロールを使用

5. タスク完了:
   - タスクが完了次第、最後のアクションとしてdoneアクションを使用
   - 存在しないアクションを作り出さない
   - タスクが特定の情報を必要とする場合、done関数にすべてを含める
   - ステップ数が残り少ない場合、効率化を考え、必ずdoneアクションを最後に使用

6. ビジュアルコンテキスト:
   - 画像が提供された場合、ページレイアウトの理解に使用
   - バウンディングボックスとラベルは要素インデックスに対応
   - 各バウンディングボックスとラベルは同じ色
   - ラベルは通常、バウンディングボックス内の右上に配置
   - 視覚的コンテキストは要素の位置と関係の確認に役立つ
   - ラベルが重なることがあるため、コンテキストで正しい要素を確認

7. フォーム入力:
   - 入力フィールドに入力後、アクションシーケンスが中断された場合、
     通常はフィールドの下に提案リストが表示され、
     提案リストから適切な要素を選択する必要がある

8. アクションシーケンス:
   - アクションはリストの順序通りに実行
   - 各アクションは前のアクションから論理的に続く必要がある
   - ページが変更された場合、シーケンスは中断され新しい状態を取得
   - コンテンツが消えるだけの場合はシーケンスは継続
   - ページが変更されると予想されるまでのアクションシーケンスのみ提供
   - 効率的な実行を心がける(フォームの一括入力、保存/抽出/チェックボックスなどの連鎖)
   - 意味がある場合のみ複数のアクションを使用

2. browser_contextで確認している内容:

class BrowserState:
    # 1. 現在のページ情報
    url: str                  # 現在のURL
    title: str               # ページタイトル
    
    # 2. タブ管理
    tabs: List[TabInfo]      # 開いているすべてのタブの情報
    
    # 3. ページコンテンツ
    element_tree: DOMElementNode  # DOMツリー構造
    selector_map: SelectorMap    # 要素のセレクターマップ
    
    # 4. ビジュアル情報
    screenshot: Optional[str]    # ページのスクリーンショット(Base64)

3. アクションシーケンスの分類と使い方(日本語):

  1. ナビゲーション系アクション:
# URLへの移動
{"go_to_url": {"url": "https://example.com"}}

# 新しいタブを開く
{"open_tab": {"url": "https://example.com"}}

# タブの切り替え
{"switch_tab": {"page_id": 1}}

# 戻る
{"go_back": {}}
  1. 入力系アクション:
# テキスト入力
{"input_text": {
    "index": 1,        # 入力フィールドのインデックス
    "text": "検索語句"  # 入力するテキスト
}}

# キー入力
{"send_keys": {
    "keys": "Enter"    # 特殊キーの送信
}}
  1. クリック系アクション:
# 要素のクリック
{"click_element": {
    "index": 2,        # クリックする要素のインデックス
    "xpath": "..."     # (オプション)要素のXPath
}}
  1. スクロール系アクション:
# ページスクロール
{"scroll": {
    "amount": 500      # スクロール量(ピクセル)
}}
  1. コンテンツ抽出系アクション:
# ページコンテンツの抽出
{"extract_page_content": {
    "value": "text"    # 抽出形式(text/markdown/html)
}}
  1. タスク完了アクション:
# タスクの完了
{"done": {
    "text": "タスク結果の説明"  # ユーザーに返す結果
}}
  1. フォーム操作系アクション:
# フォーム送信の例
[
    {"input_text": {"index": 1, "text": "ユーザー名"}},
    {"input_text": {"index": 2, "text": "パスワード"}},
    {"click_element": {"index": 3}}  # 送信ボタン
]
  1. 検索系アクション:
# Google検索の例
{"search_google": {
    "query": "検索キーワード"
}}

これらのアクションは、以下の原則に従って使用されます:

  1. 連続性: アクションは論理的な順序で実行
  2. 効率性: 必要最小限のアクションで目的を達成
  3. 堅牢性: エラー発生時の代替手段を用意
  4. 状態認識: ページの状態変化を考慮したアクション選択
  5. 目的指向: タスクの完了を最優先に考慮

これらのレスポンスはそれぞれどのようなロジックで決定され、保持され、次回のエージェントに持ち越されますか?

"current_state": {
  "evaluation_previous_goal": "成功|失敗|不明 - 現在の要素と画像を分析し、前のゴール/アクションがタスクの意図通りに成功したかを確認。アクション結果は無視し、ウェブサイトが真実。入力フィールドの新しい提案など、予期せぬことが起きた場合も言及。理由を簡潔に説明",
  "memory": "これまでに実行したことと、タスク終了まで覚えておく必要があることの説明",
  "next_goal": "次のアクションで何をする必要があるか"
},
"action": [
  {
    "action_name": {
      // アクション固有のパラメータ
    }
  }
]

レスポンスの処理と状態管理について説明いたします。

  1. 状態管理の基本構造:

Search files...

レスポンスの処理と状態管理について、以下のように説明します:

  1. 状態管理の基本構造:
class AgentBrain(BaseModel):
    evaluation_previous_goal: str  # 前回のゴールの評価
    memory: str                   # 記憶
    next_goal: str               # 次のゴール
  1. 状態の決定ロジック:

a. evaluation_previous_goalの決定:

# 1. 前回のアクションの結果を評価
if 'Success' in response.current_state.evaluation_previous_goal:
    emoji = '👍'
elif 'Failed' in response.current_state.evaluation_previous_goal:
    emoji = '⚠'
else:
    emoji = '🤷'

b. memoryの管理:

# 1. メモリに保持する情報
class MessageManager:
    def add_state_message(self, state, result, step_info):
        # 状態とアクション結果をメモリに追加
        if result and result.include_in_memory:
            # メモリに含めるべき結果を保持

c. next_goalの決定:

# LLMが現在の状態を分析して次のゴールを決定
model_output = await self.get_next_action(input_messages)
  1. 状態の保持と引き継ぎ:

a. 履歴の保存:

class AgentHistory(BaseModel):
    model_output: AgentOutput | None  # LLMの出力
    result: list[ActionResult]       # アクションの結果
    state: BrowserStateHistory       # ブラウザの状態

b. 状態の引き継ぎ:

class Agent:
    def __init__(self):
        self.history: AgentHistoryList = AgentHistoryList(history=[])
        self._last_result = None
        
    async def step(self):
        # 1. 現在の状態を取得
        state = await self.browser_context.get_state()
        
        # 2. メッセージマネージャーに状態を追加
        self.message_manager.add_state_message(state, self._last_result)
        
        # 3. 次のアクションを取得
        model_output = await self.get_next_action()
  1. エラー処理と再試行:
def _handle_step_error(self, error: Exception):
    # エラー回数をカウント
    self.consecutive_failures += 1
    
    # トークン制限に達した場合
    if 'Max token limit reached' in error_msg:
        self.message_manager.max_input_tokens -= 500
        self.message_manager.cut_messages()
  1. 状態の永続化:
def save_history(self, file_path: Optional[str | Path] = None):
    # 履歴をファイルに保存
    if not file_path:
        file_path = 'AgentHistory.json'
    self.history.save_to_file(file_path)
  1. 状態の再利用:
async def rerun_history(self, history: AgentHistoryList):
    # 保存された履歴を再実行
    for history_item in history.history:
        await self._execute_history_step(history_item)

このように、エージェントは以下の方法で状態を管理しています:

  1. 短期記憶: memoryフィールドで現在のコンテキストを保持
  2. 長期記憶: AgentHistoryListで全アクションの履歴を保持
  3. 状態評価: evaluation_previous_goalで前回のアクションの成功/失敗を評価
  4. 目標管理: next_goalで次に実行すべきアクションを決定
  5. エラー回復: 失敗時の再試行とメモリ管理の最適化

これにより、エージェントは一貫性のある行動を維持しながら、効率的にタスクを実行できます。


以上のように、browser-useは、決められたDOM操作をシステムプロンプトに仕込み、それをツールユースでエージェントが選んで、メモリに入れつつ、アクションを実行していっているみたいです。

割とオーソドックスな作りながらも、基本的なブラウザ操作と、ユーザーごとにアクションをカスタムできる拡張性についての設計力がイケてる、といった感じでしょうか。

試しに下記のカスタムエージェントを実行してみました。みなさんもレポジトリにこのようなファイルを置いて実行すれば同じ結果が得られるでしょう。

import asyncio
import os
from langchain_openai import ChatOpenAI
from browser_use.agent.service import Agent
from browser_use.browser.browser import Browser

async def main():
    browser = Browser()
    async with await browser.new_context() as context:
        agent = Agent(
            task='永谷園の競合企業を探してください。以下の情報を収集してください:1. 主要な競合企業名 2. 各企業の主力商品 3. 市場シェア(もし見つかれば)',
            llm=ChatOpenAI(model='gpt-4o', temperature=0.0),
            browser_context=context,
        )
        await agent.run()
    await browser.close()

if __name__ == "__main__":
    asyncio.run(main())
$ python3 search_nagatanien_competitors.py
INFO     [browser_use] BrowserUse logging setup complete with level info
INFO     [root] Anonymized telemetry enabled. See https://github.com/gregpr07/browser-use for more information.
INFO     [agent] 🚀 Starting task: 永谷園の競合企業を探してください。以下の情報を収集してください:1. 主要な競合企業名 2. 各企業の主力商品 3. 市場シェア(もし見つかれば)
INFO     [agent] 
📍 Step 1
INFO     [agent] 🤷 Eval: Unknown - The current page is blank, so no previous actions have been taken.
INFO     [agent] 🧠 Memory: Need to search for 永谷園's competitors and gather information about their main products and market share.
INFO     [agent] 🎯 Next goal: Search for 永谷園's competitors and gather the required information.
INFO     [agent] 🛠️  Action 1/1: {"search_google":{"query":"永谷園 競合企業"}}
INFO     [controller] 🔍  Searched for "永谷園 競合企業" in Google
INFO     [agent] 
📍 Step 2
INFO     [agent] 👍 Eval: Success - Found initial information about 永谷園's competitors: キッコーマン, 味の素, and キューピー.
INFO     [agent] 🧠 Memory: Need to gather more detailed information about the main products and market share of キッコーマン, 味の素, and キューピー.
INFO     [agent] 🎯 Next goal: Search for detailed information on the main products and market share of キッコーマン, 味の素, and キューピー.
INFO     [agent] 🛠️  Action 1/3: {"search_google":{"query":"キッコーマン 主力商品 市場シェア"}}
INFO     [agent] 🛠️  Action 2/3: {"search_google":{"query":"味の素 主力商品 市場シェア"}}
INFO     [agent] 🛠️  Action 3/3: {"search_google":{"query":"キューピー 主力商品 市場シェア"}}
INFO     [controller] 🔍  Searched for "キッコーマン 主力商品 市場シェア" in Google
INFO     [controller] 🔍  Searched for "味の素 主力商品 市場シェア" in Google
INFO     [controller] 🔍  Searched for "キューピー 主力商品 市場シェア" in Google
INFO     [agent] 
📍 Step 3
INFO     [agent] 👍 Eval: Success - Found information about キューピー's main products and some market share details.
INFO     [agent] 🧠 Memory: キューピー's main products include mayonnaise and dressings. Need to gather similar information for キッコーマン and 味の素.
INFO     [agent] 🎯 Next goal: Extract detailed information about キッコーマン and 味の素's main products and market share.
INFO     [agent] 🛠️  Action 1/2: {"search_google":{"query":"キッコーマン 主力商品 市場シェア 詳細"}}
INFO     [agent] 🛠️  Action 2/2: {"search_google":{"query":"味の素 主力商品 市場シェア 詳細"}}
INFO     [controller] 🔍  Searched for "キッコーマン 主力商品 市場シェア 詳細" in Google
INFO     [controller] 🔍  Searched for "味の素 主力商品 市場シェア 詳細" in Google
INFO     [agent] 
📍 Step 4
INFO     [agent] 👍 Eval: Success - Found detailed information about 味の素's main products and market share.
INFO     [agent] 🧠 Memory: 味の素's main products include seasonings and frozen foods. They have a significant market share globally, especially in nucleic acid-based seasonings.
INFO     [agent] 🎯 Next goal: Compile the gathered information about 永谷園's competitors, including キッコーマン, 味の素, and キューピー, with their main products and market share.
INFO     [agent] 🛠️  Action 1/1: {"done":{"text":"永谷園の主要な競合企業とその情報は以下の通りです:\n\n1. **キッコーマン**\n   - **主力商品**: 醤油、調味料、食品関連製品\n   - **市場シェア**: 醤油市場での強い存在感を持ち、グローバルに展開しています。\n\n2. **味の素**\n   - **主力商品**: 調味料、冷凍食品\n   - **市場シェア**: 核酸系調味料で世界トップクラスのシェアを持ち、冷凍食品でも高いシェアを誇ります。\n\n3. **キューピー**\n   - **主力商品**: マヨネーズ、ドレッシング\n   - **市場シェア**: マヨネーズ市場でのリーダー的存在です。\n\nこれらの企業はそれぞれの分野で強い市場シェアを持ち、永谷園の主要な競合とされています。"}}
INFO     [agent] 📄 Result: 永谷園の主要な競合企業とその情報は以下の通りです:

1. **キッコーマン**
   - **主力商品**: 醤油、調味料、食品関連製品
   - **市場シェア**: 醤油市場での強い存在感を持ち、グローバルに展開しています。

2. **味の素**
   - **主力商品**: 調味料、冷凍食品
   - **市場シェア**: 核酸系調味料で世界トップクラスのシェアを持ち、冷凍食品でも高いシェアを誇ります。

3. **キューピー**
   - **主力商品**: マヨネーズ、ドレッシング
   - **市場シェア**: マヨネーズ市場でのリーダー的存在です。

これらの企業はそれぞれの分野で強い市場シェアを持ち、永谷園の主要な競合とされています。
INFO     [agent] ✅ Task completed successfully
git-lfs filter-process: git-lfs: command not found                                                         
fatal: the remote end hung up unexpectedly

AnthropicもComputer UseのAPIはありますが、ブラウザの操作の成功確率はまだまだ低いと記憶しており、このレポジトリでどこまで実行できるかは検証していませんが、そこの差分が気になるところです。複雑な操作を試した方がいたらぜひ教えて下さい!


About me

現在、市場調査やデスクリサーチの生成AIエージェントを作っています 仲間探し中 / Founder of AI Desk Research Agent @deskrex , https://deskrex.ai

ぜひお気軽にチャットしましょう!
https://x.com/ItaruTomita9779/status/1856471446614356395

生成AIデスクリサーチサービス Deskrex | サービスページ

https://lp.deskrex.ai/

生成AIデスクリサーチエージェント Deskrex App | アプリケーションサイト

https://app.deskrex.ai/

DeskrexAIリサーチ | メディア

https://media.deskrex.ai/

株式会社Deskrex | 会社概要

https://www.deskrex.ai/

Deskrex | Xページ

https://x.com/deskrex

Discussion