素人でもBedrockでAIにブラウザ利用させたい

この記事は以下のAWS Communityの翻訳記事です。この記事では、browser-use-agent-awsリポジトリのセットアップ方法や動かし方がまとめられています。リポジトリとしては、PlaywrightとClaudeモデルを使用して、生成AIにブラウザ操作を通じた検索を自動化させる試みが実装されています。

記事:
https://community.aws/content/2qK7ftoNiq9vk7St8as2KOmSIU2/enhancing-ai-agent-capabilities-with-browser-use-and-amazon-bedrock

なお、この翻訳記事では、後続者の実装しやすさやわかりやすさのため、セットアップ方法の解説を含めたり、環境に関する補足などを行っています。

---

# GenAI、Playwright、Claudeを活用し、Browser UseとAmazon Bedrockでウェブ操作を自動化するAIエージェントの構築方法

AIによる自動化はウェブとのインタラクションのあり方を変えていますが、多くのソリューションは複雑すぎたり柔軟性に欠けたりします。**Browser Use**は、AIエージェントがウェブサイトとシームレスにやり取りできるシンプルかつ強力なツールです。HTML抽出、要素のナビゲーション、マルチステップワークフローのサポートなど、直感的なAPIを提供します。

**Browser Use**
https://docs.browser-use.com/quickstart

これに**Amazon Bedrock**（AWSのフルマネージドな生成AIサービス）を組み合わせることで、BedrockのファウンデーションモデルとBrowser Useの自動化機能を活用し、ウェブを巡回・データ抽出・自律的なアクションを実行するインテリジェントなエージェントを構築できます。

このガイドでは、Browser UseとAmazon Bedrockの統合方法をステップバイステップで解説します。セットアップの詳細は[Browser Useドキュメント](https://docs.browser-use.com/quickstart)をご参照ください。

---

## ユースケース

AI駆動のブラウザ自動化の代表的な応用例の一つがイベントプランニングです。ここでは、**Amazon Bedrock**と**Browser Use**を使い、**Google**でスポーツイベントを検索し、ユーザーの好みに合った最適な選択肢を自動で見つける方法を紹介します。

---

### シナリオ1: 市内で子供向けスポーツイベントを探す

ユーザーがサンフランシスコで以下の条件に合うスポーツワークショップやトレーニングイベントを探したいとします。

1. サンフランシスコで特定のスポーツ（例：バレーボール）のイベントを検索
2. 種類：Boot Camp、Workshop、Tryout trainings
3. 対象年齢：11～15歳
4. イベント会場が半径15マイル以内
5. イベント名・日付・時間・場所・連絡先・対象年齢・費用などを含む表形式のリストで出力

---

## なぜAmazon BedrockとBrowser Useを組み合わせるのか？

このタスクには、構造化された推論とブラウザ操作の両方が必要です。

- **Amazon Bedrock**は、ユーザーの意図を解釈し、必要な情報を抽出し、ブラウザエージェント向けにクエリを構造化する強力な生成AIモデルを提供します。
- **Browser Use**は、ウェブ操作を自動化し、Google Flightsなどから情報を抽出し、希望の形式で結果を返すことができます。

---

## セットアップ

この部分は実際の記事には含まれていないものの、リポジトリをご自身の環境で使用するために必要な全てを解説しています。

### AWSでの環境整備

#### EC2

仮想サーバを用意して、リポジトリが動くために必要な環境を作成します。
自身の結論としては、**バージニア北部**(`us-east-1`)リージョンで、*パブリックIP*をもった**Amazon Linux 2023**の`t3.medium`インスタンスを作成しました。考慮した条件は以下のとおりです。

**バージニア北部**
- Bedrockで、Claude 3.5 Sonnet V2が使用できること

**t3.medium**
- 使用するライブラリが多いため、十分なメモリ量を確保したかった
- 短時間でできるので、コストが少額で済むと思われ、快適性の観点から、性能を重視したい

**AL2023**
- 個人的に使い慣れたOSであるので、環境整備に支障が出たときに解決が早い

リージョンに関してはModel Accessがある場合、そのリージョンを優先したほうが早く実装できますので、固定ではありません。インスタンスファミリーなどについても、無料枠の`t2-micro`でもできるので、好みでいいと思います。自分は多少の課金に抵抗がないので、そのあたりにシビアな方はもう少し検討したほうがいいと思います。OSについてはご自由にどうぞ。

#### Bedrock

モデルIDには、`us.anthropic.claude-3-5-sonnet-20241022-v2:0`を使用します。
記事を発行した現在は、リポジトリに埋め込まれているモデルIDで十分ですが、変更したい場合などに対応して、モデルIDの取得方法を案内します。

:::details モデルIDの取得方法
1. コンソールで、Amazon Bedrockにアクセスします。
2. 左側のメニューから、「Inference and Acessment」>「Cross-region inference」を選択します。
3. Inference profilesの欄に表示されたテーブルで、「Model=Claude 3.5 Sonnet v2」を指定します。
4. Inference profile IDの列をコピーします。
:::

条件としては次のとおりです。
- `Browser Use`では、画像をLLMに渡す必要があり、画像を直接渡せるモデルであるべき
- 合理的な推論を維持できる、より「賢い」モデルが要求される
- 何回も推論を繰り返して結果にたどり着けるタスクなので、コストパフォーマンスが重要

#### IAM

##### ロール作成・付与

リポジトリに指定があるため、CLIでの権限設定となります。ユーザに付与する権限は以下が便利です。
- AmazonBedrockFullAccess
    - 今回の実装に対して、**最小権限の原則には従っていない**が、一時的に利用するにはある程度絞られており、マネージドポリシーなので便利です。

:::details AmazonBedrockFullAccess
```JSON
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "BedrockAll",
            "Effect": "Allow",
            "Action": [
                "bedrock:*"
            ],
            "Resource": "*"
        },
        {
            "Sid": "DescribeKey",
            "Effect": "Allow",
            "Action": [
                "kms:DescribeKey"
            ],
            "Resource": "arn:*:kms:*:::*"
        },
        {
            "Sid": "APIsWithAllResourceAccess",
            "Effect": "Allow",
            "Action": [
                "iam:ListRoles",
                "ec2:DescribeVpcs",
                "ec2:DescribeSubnets",
                "ec2:DescribeSecurityGroups"
            ],
            "Resource": "*"
        },
        {
            "Sid": "MarketplaceModelEndpointMutatingAPIs",
            "Effect": "Allow",
            "Action": [
                "sagemaker:CreateEndpoint",
                "sagemaker:CreateEndpointConfig",
                "sagemaker:CreateModel",
                "sagemaker:DeleteEndpoint",
                "sagemaker:UpdateEndpoint"
            ],
            "Resource": [
                "arn:aws:sagemaker:*:*:endpoint/*",
                "arn:aws:sagemaker:*:*:endpoint-config/*",
                "arn:aws:sagemaker:*:*:model/*"
            ],
            "Condition": {
                "StringEquals": {
                    "aws:CalledViaLast": "bedrock.amazonaws.com",
                    "aws:ResourceTag/sagemaker-sdk:bedrock": "compatible"
                }
            }
        },
        {
            "Sid": "MarketplaceModelEndpointAddTagsOperations",
            "Effect": "Allow",
            "Action": [
                "sagemaker:AddTags"
            ],
            "Resource": [
                "arn:aws:sagemaker:*:*:endpoint/*",
                "arn:aws:sagemaker:*:*:endpoint-config/*",
                "arn:aws:sagemaker:*:*:model/*"
            ],
            "Condition": {
                "ForAllValues:StringEquals": {
                    "aws:TagKeys": [
                        "sagemaker-sdk:bedrock",
                        "bedrock:marketplace-registration-status",
                        "sagemaker-studio:hub-content-arn"
                    ]
                },
                "StringLike": {
                    "aws:RequestTag/sagemaker-sdk:bedrock": "compatible",
                    "aws:RequestTag/bedrock:marketplace-registration-status": "registered",
                    "aws:RequestTag/sagemaker-studio:hub-content-arn": "arn:aws:sagemaker:*:aws:hub-content/SageMakerPublicHub/Model/*"
                }
            }
        },
        {
            "Sid": "MarketplaceModelEndpointDeleteTagsOperations",
            "Effect": "Allow",
            "Action": [
                "sagemaker:DeleteTags"
            ],
            "Resource": [
                "arn:aws:sagemaker:*:*:endpoint/*",
                "arn:aws:sagemaker:*:*:endpoint-config/*",
                "arn:aws:sagemaker:*:*:model/*"
            ],
            "Condition": {
                "ForAllValues:StringEquals": {
                    "aws:TagKeys": [
                        "sagemaker-sdk:bedrock",
                        "bedrock:marketplace-registration-status",
                        "sagemaker-studio:hub-content-arn"
                    ]
                },
                "StringLike": {
                    "aws:ResourceTag/sagemaker-sdk:bedrock": "compatible",
                    "aws:ResourceTag/bedrock:marketplace-registration-status": "registered",
                    "aws:ResourceTag/sagemaker-studio:hub-content-arn": "arn:aws:sagemaker:*:aws:hub-content/SageMakerPublicHub/Model/*"
                }
            }
        },
        {
            "Sid": "MarketplaceModelEndpointNonMutatingAPIs",
            "Effect": "Allow",
            "Action": [
                "sagemaker:DescribeEndpoint",
                "sagemaker:DescribeEndpointConfig",
                "sagemaker:DescribeModel",
                "sagemaker:ListTags"
            ],
            "Resource": [
                "arn:aws:sagemaker:*:*:endpoint/*",
                "arn:aws:sagemaker:*:*:endpoint-config/*",
                "arn:aws:sagemaker:*:*:model/*"
            ],
            "Condition": {
                "StringEquals": {
                    "aws:CalledViaLast": "bedrock.amazonaws.com"
                }
            }
        },
        {
            "Sid": "MarketplaceModelEndpointInvokingOperations",
            "Effect": "Allow",
            "Action": [
                "sagemaker:InvokeEndpoint",
                "sagemaker:InvokeEndpointWithResponseStream"
            ],
            "Resource": [
                "arn:aws:sagemaker:*:*:endpoint/*"
            ],
            "Condition": {
                "StringEquals": {
                    "aws:CalledViaLast": "bedrock.amazonaws.com",
                    "aws:ResourceTag/sagemaker-sdk:bedrock": "compatible"
                }
            }
        },
        {
            "Sid": "DiscoveringMarketplaceModel",
            "Effect": "Allow",
            "Action": [
                "sagemaker:DescribeHubContent"
            ],
            "Resource": [
                "arn:aws:sagemaker:*:aws:hub-content/SageMakerPublicHub/Model/*",
                "arn:aws:sagemaker:*:aws:hub/SageMakerPublicHub"
            ]
        },
        {
            "Sid": "AllowMarketplaceModelsListing",
            "Effect": "Allow",
            "Action": [
                "sagemaker:ListHubContents"
            ],
            "Resource": "arn:aws:sagemaker:*:aws:hub/SageMakerPublicHub"
        },
        {
            "Sid": "PassRoleToSageMaker",
            "Effect": "Allow",
            "Action": [
                "iam:PassRole"
            ],
            "Resource": [
                "arn:aws:iam::*:role/*SageMaker*ForBedrock*"
            ],
            "Condition": {
                "StringEquals": {
                    "iam:PassedToService": [
                        "sagemaker.amazonaws.com",
                        "bedrock.amazonaws.com"
                    ]
                }
            }
        },
        {
            "Sid": "PassRoleToBedrock",
            "Effect": "Allow",
            "Action": [
                "iam:PassRole"
            ],
            "Resource": "arn:aws:iam::*:role/*AmazonBedrock*",
            "Condition": {
                "StringEquals": {
                    "iam:PassedToService": [
                        "bedrock.amazonaws.com"
                    ]
                }
            }
        }
    ]
}
```
:::

##### ユーザ作成

1. EC2でのCLI実行に使用するユーザを作成します。
2. 作成後、アクセスキーを発行し、アクセスキーとシークレットアクセスキーを保管します。

#### 実行環境の整備

あくまで一例ですが、紹介します。とりあえず分からなくても動くと思います。
1. EC2 Instance Connect経由で、EC2にログイン。
2. Gitを導入
    `sudo dnf install -y git`
    https://git-scm.com/downloads/linux
4. uv を導入
    `curl -LsSf https://astral.sh/uv/install.sh | sh`
5. リポジトリをクローン
    `git clone https://github.com/rjesh-git/browser-use-agent-aws.git`
6. 仮想環境の作成
    `cd browser-use-agent-aws/`
    `uv venv .venv`
7. 仮想環境のアクティベーション
    `source .venv/bin/activate`
8. 仮想環境の依存関係を設定
    `uv sync`
9. Playwrightのセットアップ
    `playwright install`

:::details AL2023でエラーが出る場合への対応
以下のエラーが出る場合があります。

```log
Playwright Host validation warning: 
╔══════════════════════════════════════════════════════╗
║ Host system is missing dependencies to run browsers. ║
║ Please install them with the following command:      ║
║                                                      ║
║     sudo playwright install-deps                     ║
║                                                      ║
║ Alternatively, use apt:                              ║
║     sudo apt-get install libatk1.0-0\                ║
║         libatk-bridge2.0-0\                          ║
║         libcups2\                                    ║
║         libx11-6\                                    ║
║         libxcomposite1\                              ║
║         libxdamage1\                                 ║
║         libxext6\                                    ║
║         libxfixes3\                                  ║
║         libxrandr2\                                  ║
║         libgbm1\                                     ║
║         libxcb1\                                     ║
║         libxkbcommon0\                               ║
║         libpango-1.0-0\                              ║
║         libcairo2\                                   ║
║         libasound2\                                  ║
║         libatspi2.0-0                                ║
║                                                      ║
║ <3 Playwright Team                                   ║
╚══════════════════════════════════════════════════════╝
```

その場合、以下の方法でライブラリを導入でき、解決できます。
```sh
sudo dnf install \
  atk \
  at-spi2-atk \
  cups-libs \
  libXcomposite \
  libXdamage \
  libXfixes \
  libXrandr \
  mesa-libgbm \
  libxkbcommon \
  pango \
  alsa-lib \
  at-spi2-core
```
:::

10. CLI認証情報の設定
    `aws configure`実行後、インタラクティブに設定できます。
    アクセスキー、シークレットアクセスキーは、IAMユーザ作成で取得したものを利用しましょう
    リージョンについては、EC2のリージョン（`us-east-1`）を書きます。
    出力形式は、`json`とすればOKです。
12. `event.py`の編集
    `vi event.py`を実行し、スクリプトを編集します。
    ```py
    llm = ChatBedrock(
        model_id="us.anthropic.claude-3-5-sonnet-20241022-v2:0",
    )
    ```
    このような箇所があるのですが、このままだとリージョン指定がないというエラーになる可能性がありますので、`region="us-east-1"`を追加しましょう。
    追加後、以下のスクリプトになります。
    ```py
    llm = ChatBedrock(
        model_id="us.anthropic.claude-3-5-sonnet-20241022-v2:0",
        region="us-east-1"
    )
    ```
    設定の詳細や理由については、以下のLangChainドキュメントのページが役立ちます。
    https://python.langchain.com/api_reference/aws/chat_models/langchain_aws.chat_models.bedrock.ChatBedrock.html#langchain_aws.chat_models.bedrock.ChatBedrock.region_name
14. スクリプトの実行
    `uv run event.py`を行いましょう。適切に設定されていれば、以下の記事どおりに動いてきます。

---

## エージェントの実装

### Amazon Bedrock LLMの設定

```python
from langchain_aws import ChatBedrock
llm = ChatBedrock(
    model_id="us.anthropic.claude-3-5-sonnet-20241022-v2:0",
)
```
ここではLangChainのChatBedrockを使い、Amazon Bedrockに接続し、Claude 3.5 Sonnetをファウンデーションモデルとして選択しています。BedrockはClaude、Titan、MistralなどのLLMをアプリケーションにシームレスに統合できます。

Claude 3.5 Sonnetは推論やタスク実行に最適化されており、検索クエリの理解や出力の構造化に適しています。

---

### イベントエージェントの定義

```python
from browser_use import Agent
import asyncio
```
`browser_use`からAgentをインポートし、非同期処理のために`asyncio`もインポートします。
https://pypi.org/project/browser-use/

```python
agent = Agent(
    task="""
    1. Find all volleyball events in San Francisco.
    2. Events may be of the following types:
    - Boot camp
    - Workshop
    - Tryout trainings
    3. Find events suitable for age group 11 to 15.
    4. All event should be in 15 miles radius.
    5. Provide me the list of events with details like event name, date, time, location, contact details and age group.
    6. Format result in a table.
    """,
    browser=Browser(config=BrowserConfig(headless=True)),
    llm=llm,
)
```
- `task`文字列がAIモデルへのプロンプトとなり、スポーツイベント検索のための構造化指示を与えます。
- `llm`パラメータでAmazon BedrockのClaude 3.5を利用し、タスクの理解と処理を行います。

---

### エージェントの実行

GitHubリポジトリをクローン後、プロジェクトディレクトリで以下を実行します。

https://github.com/rjesh-git/browser-use-agent-aws

```sh
uv run event.py
```

**エージェント実行コンソールビュー**

![Sports Event Agents Tasks](https://community.aws/_next/image?url=https%3A%2F%2Fassets.community.aws%2Fa%2F2v8TJxI3HfDloHoKytANFVf9FRJ%2Fscre.webp%3FimgSize%3D1000x808&w=3840&q=75)

**レスポンス例**

![Sports Event Response](https://community.aws/_next/image?url=https%3A%2F%2Fassets.community.aws%2Fa%2F2v8TTv2vhU08q4SONysTf6ml7Zc%2FScre.webp%3FimgSize%3D1000x460&w=3840&q=75)

---

### シナリオ2: 休暇用の最適なフライトを探す

ユーザーがサンフランシスコ（SFO）からチェンナイ（MAA）への安価なフライトを予約したい場合、今回はChromiumブラウザを使ってフライト検索プロセスを可視化します。

```python
agent = Agent(
    task="""
    1. Find me low price flight from San Francisco to Chennai with shortest duration for my vacation.
    2. I want to travel in last week of May and return in June 3rd week, any day is fine.
    3. Economy or Economy plus is fine.
    4. Use google.com/flights to find the flight.
    5. Provide me the top 3 flights with the details like price, duration, and departure time.
    6. Format result in a table with columns: Flight, Price, Duration, Departure Time, Return date.
    7. Provide me the source link to book the flight.
    """,
    llm=llm,
)
```

以下のコマンドでエージェントを実行します。

```sh
uv run main.py
```

このコマンドは、Amazon BedrockのClaude 3.5 Sonnetを搭載したBrowser Useエージェントを起動し、Playwright経由でChromiumブラウザを立ち上げてGoogle Flightsを開きます。

1. PlaywrightでChromiumを起動
2. Google Flights（https://www.google.com/flights）にアクセス
3. ユーザープロンプトに従いフライト情報を入力
    - 出発地：サンフランシスコ（SFO）
    - 到着地：チェンナイ（MAA）
    - 出発：5月最終週
    - 帰国：6月第3週
    - キャビンクラス：Economy/Economy Plus
    - 最低価格・最短時間でソート
    - 上位3件のフライト詳細を抽出し、Markdownテーブルで出力
    - 予約用のリンクも提供

**エージェント実行Chromeビュー**

![Agent Execution Chrome View](https://community.aws/_next/image?url=https%3A%2F%2Fassets.community.aws%2Fa%2F2v6kw80gLtMMEhrU95yxjwDf7pK%2FScre.webp%3FimgSize%3D1000x676&w=3840&q=75)

**レスポンス例**

![Agent Response](https://community.aws/_next/image?url=https%3A%2F%2Fassets.community.aws%2Fa%2F2v6l4fTVnQMENFyfPvxn9JUGk6R%2FScre.webp%3FimgSize%3D1000x335&w=3840&q=75)

---

## 結論

Amazon BedrockとBrowser Useを組み合わせることで、先進的なAI駆動のブラウザ自動化アプリケーションを開発できます。この統合により、複雑なタスクを効率的に処理し、両プラットフォームの強みを活かした堅牢かつスケーラブルなソリューションを構築できます。

---

## リポジトリを動かした感想

### 自身の実行した環境では、スロットリングが多く発生した

![](https://storage.googleapis.com/zenn-user-upload/ef7865faada5-20250506.png)

EC2の出力をみていると、途中までうまく計画してブラウザを使用しているのだが、とにかくスロットリングによるリトライが頻発しており、LLMに画像を捌かせるうえでは実務上の課題があるのだと理解した。実際に、過去の画像処理LLMアプリ開発経験でも似たような課題が出ていた。つまり、OpenAIだろうと、Anthropicだろうと、また、Bedrock（のクロスリージョンインファレンス）だろうと、ブラウザのスクリーンショットをLLMに与えて判断させる仕組みには現在のAIインフラが完全には対応できない可能性があると推測できる。

![](https://storage.googleapis.com/zenn-user-upload/7619fe6c7972-20250506.png)

ただし、Amazon Bedrockには、provisioned throughputがあるため、こうした迂回方法を検討できるのが強みとなる可能性が高い。Azureなどでは、そのようなオプションを容易に得ることができず（20250506現在）、エンドポイントの並列化などで対応せざるを得ないので、アプリケーションの管理が複雑化する。本格的に画像を処理させたい場合、[Amazon SageMaker JumpStart](https://aws.amazon.com/jp/sagemaker-ai/jumpstart/)なども検討できるとの話であり、実際にユースケースもあることから、生成AIアプリケーションの実務利用において、Amazon Bedrock/AWSを選択肢とする強い利点があると思われる。

### Web検索という単純なタスクに対する時間が多く掛かる

![](https://storage.googleapis.com/zenn-user-upload/e1e8c06508f8-20250506.png)

生成AIアプリケーションでは、巷でいわれているように、AI エージェントの制御やエージェントループの効率的な稼働の確保が課題となる。実際に、生成AIはReAct構成を取ったとしても、ユーザの望むような速度と効率で現実世界からリソースを調達して、推論して結論を出してくれるわけではない。

この課題の主な原因として、コンテクスト不足が挙げられると考えた。つまり、生成AIは仮に十分な推論性能がああり、ReActプロンプトなどを設定したとしても、一度の呼び出しで不十分な範囲の情報しかなければ、本来は俯瞰的に判断できることも、局所的で煩雑なタスク実行になりがちであるという推測である。

実際に、今回のリポジトリを動かしてみると、検索過程で何度か行き詰まってしまい、ある程度戻って検索を再開するという挙動もみられた。これ自体は通常かつ期待された動きではあるものの、これが繰り返されて一向に目的を達成できない様にみえると、当初の計画の甘さや実行過程での評価の誤りに考えられてしまう。無論、モデルの推論性能の責任にもできるが、実際は当初からの実行過程をコンテクストに含めているわけではないので、そのような「行き当たりばったりな」ReActになっている可能性も指摘できる。

RAGについても言えることだが、LLMによる応用的な生成や判断に関しては、文脈不足や全体感のなさ（情報の分断）を補うためのアプリケーションロジックやアーキテクチャが検討されるべきである。

---

## 参考

GitHubリポジトリ:
https://github.com/rjesh-git/browser-use-agent-aws

ReAct:
https://arxiv.org/pdf/2210.03629

CodeAct:
https://arxiv.org/pdf/2402.01030