Amazon Bedrock Agents を触ってみる

記事タイトルとURLをコピーする

はじめに

こんにちは、アプリケーションサービス本部ディベロップメントサービス3課の北出です。

最近、AIエージェントという言葉をよく耳にするようになりました。Amazon Bedrock AgentCoreは聞きますが、調べてもなかなか理解しづらかったです。 AIエージェントの理解のために、まずはGUIベースでAIエージェントを作ることができるということで、Amazon Bedrock Agents を使って「天気を教えてくれるエージェント」を作ってみました。

コードを書くのは AWS Lambda 関数だけで、あとはマネジメントコンソールからの設定で完結するので、エージェントの仕組みを理解するのにちょうど良い題材だと思います。

「AIエージェントが気になるけど触ったことがない」という方の参考になれば幸いです。

今回作るもの

ユーザーが「東京の天気を教えて」と聞くと、エージェントが天気APIを呼び出して日本語で回答してくれるチャットエージェントです。

アーキテクチャ

ユーザー → Bedrock Agent(Claude) → Action Group → Lambda 関数 → Open-Meteo API
  • 基盤モデル: Anthropic Claude 3.5 Sonnet

  • 天気API: Open-Meteo(APIキー不要・全世界対応・無料)

  • リージョン: アジアパシフィック(東京)ap-northeast-1

前提条件

  • AWSアカウント

  • Bedrock のモデルアクセスで Claude が有効化されていること

Bedrock Agents の仕組み

手順に入る前に、今回使う Bedrock Agents の仕組みを簡単に説明します。

全体の流れ

ユーザー
「東京の天気教えて」
    │
    ▼
基盤モデル(Claude)
  推論: "天気を取得する関数を呼ぼう"
    │
    ▼
アクショングループ(GetWeather)
  関数: get_current_weather
  パラメータ: latitude, longitude
    │
    ▼
Lambda 関数(weather-agent-function)
  [latitude, longitude]を受け取って、天気APIを呼び出して結果を返す
    │
    ▼
Open-Meteo API(天気データ取得)
    │
    ▼
基盤モデル(Claude)
  結果を自然言語に整形
    │
    ▼
ユーザーに回答
「東京は一部曇り、気温14.4°C...」

ポイントは、エージェント自身は天気APIを直接叩くわけではないということです。Claude が「この質問に答えるには天気情報が必要だ」と推論し、アクショングループに定義された関数を呼び出す判断をします。(MCPのtoolsをAIが判断して実行するイメージに近いです)

アクショングループとは

アクショングループは、エージェントに「あなたはこういう操作ができますよ」と教えるインターフェース定義です。

もう少し具体的に言うと:

  • エージェントへの指示文(プロンプト) = エージェントの「考え方」を定義する

  • アクショングループ = エージェントの「行動」を定義する(何ができるか、どう実行するか)

レストランで例えると:

概念 例え
エージェント(Claude) シェフ
指示文 「あなたは和食専門です」という役割説明
アクショングループ メニュー表(何が作れるかの一覧)
Lambda 関数 厨房(実際に料理を作る場所)

今回の天気エージェントでは、アクショングループに以下を定義します:

アクショングループ: GetWeather
  └── 関数: get_current_weather
        ├── パラメータ: latitude(緯度)必須
        └── パラメータ: longitude(経度)必須
        → 実行先: Lambda 関数

エージェントはこの定義を見て、「ユーザーが天気を聞いている → get_current_weather を呼べばいい → 緯度と経度が必要だ → 東京なら35.6762と139.6503だ」と推論して Lambda を呼び出します。

処理の流れ

  1. ユーザーが「東京の天気教えて」と入力
  2. Claude が推論:「get_current_weatherlatitude=35.6762, longitude=139.6503 で呼ぼう」
  3. Bedrock が Lambda 関数を呼び出し、パラメータを渡す
  4. Lambda が天気APIを叩いてデータを返す
  5. Claude が結果を受け取り、自然言語に整形して回答を生成

この「推論 → ツール呼び出し → 回答生成」のループがエージェントの基本的な動作です。

手順

1. Lambda関数の作成

まず、天気APIを呼び出す Lambda 関数を作成します。

Lambda コンソールから以下の設定で関数を作成します。

  • 関数名: weather-agent-function

  • ランタイム: Python 3.14

  • アーキテクチャ: arm64

コードを以下に置き換えます。

import json
import urllib.request


def get_weather(latitude, longitude):
    """Open-Meteo APIで天気情報を取得する"""
    url = (
        f"https://api.open-meteo.com/v1/forecast?"
        f"latitude={latitude}&longitude={longitude}"
        f"&current=temperature_2m,weather_code,wind_speed_10m,relative_humidity_2m"
        f"&timezone=auto"
    )
    req = urllib.request.Request(url)
    with urllib.request.urlopen(req) as res:
        return json.loads(res.read().decode())


WEATHER_CODES = {
    0: "快晴", 1: "おおむね晴れ", 2: "一部曇り", 3: "曇り",
    45: "霧", 48: "着氷性の霧",
    51: "弱い霧雨", 53: "霧雨", 55: "強い霧雨",
    61: "弱い雨", 63: "雨", 65: "強い雨",
    71: "弱い雪", 73: "雪", 75: "強い雪",
    80: "弱いにわか雨", 81: "にわか雨", 82: "激しいにわか雨",
    95: "雷雨", 96: "雹を伴う雷雨", 99: "激しい雹を伴う雷雨",
}


def lambda_handler(event, context):
    action_group = event.get("actionGroup", "")
    function_name = event.get("function", "")
    parameters = event.get("parameters", [])

    params = {p["name"]: p["value"] for p in parameters}
    latitude = params.get("latitude", "35.6762")
    longitude = params.get("longitude", "139.6503")

    weather_data = get_weather(latitude, longitude)
    current = weather_data.get("current", {})

    temperature = current.get("temperature_2m", "不明")
    weather_code = current.get("weather_code", 0)
    wind_speed = current.get("wind_speed_10m", "不明")
    humidity = current.get("relative_humidity_2m", "不明")
    weather_desc = WEATHER_CODES.get(weather_code, "不明")

    result = (
        f"現在の天気: {weather_desc}\n"
        f"気温: {temperature}°C\n"
        f"湿度: {humidity}%\n"
        f"風速: {wind_speed} km/h"
    )

    return {
        "messageVersion": "1.0",
        "response": {
            "actionGroup": action_group,
            "function": function_name,
            "functionResponse": {
                "responseBody": {
                    "TEXT": {
                        "body": result
                    }
                }
            }
        }
    }

デプロイしたら、「設定」→「一般設定」からタイムアウトを 30秒 に変更しておきます。

Lambda単体テスト

エージェントと連携する前に、Lambda 単体で動作確認しておくと安心です。

テストイベントに以下を設定して実行します。

{
  "messageVersion": "1.0",
  "agent": {"name": "weather-agent", "id": "test", "alias": "test", "version": "1"},
  "inputText": "東京の天気を教えて",
  "sessionId": "test-session",
  "actionGroup": "GetWeather",
  "function": "get_current_weather",
  "parameters": [
    {"name": "latitude", "type": "string", "value": "35.6762"},
    {"name": "longitude", "type": "string", "value": "139.6503"}
  ]
}

「現在の天気: ○○」のようなレスポンスが返ってくれば成功です。

2. Bedrock Agent の作成

Bedrock コンソールから「エージェント」→「エージェントを作成」で以下を設定します。

  • エージェント名: weather-agent

  • 説明: 天気情報を教えてくれるエージェント

モデルと指示文の設定

エージェントビルダー画面で、モデルに Anthropic Claude 3.5 Sonnet を選択し、以下の指示文を設定します。

あなたは天気情報を提供するアシスタントです。

ユーザーから場所を聞かれたら、その場所の緯度・経度を推定して天気情報を取得してください。

主要都市の緯度・経度:
- 東京: 緯度 35.6762, 経度 139.6503
- 大阪: 緯度 34.6937, 経度 135.5023
- 名古屋: 緯度 35.1815, 経度 136.9066
- 札幌: 緯度 43.0618, 経度 141.3545
- 福岡: 緯度 33.5904, 経度 130.4017
- ニューヨーク: 緯度 40.7128, 経度 -74.0060
- ロンドン: 緯度 51.5074, 経度 -0.1278

回答のルール:
1. 必ず日本語で回答する
2. 天気情報を分かりやすくフォーマットして表示する
3. 場所が曖昧な場合はユーザーに確認する
4. 天気に基づいたアドバイス(傘が必要か等)も添える

アクショングループの追加

「アクショングループ」セクションから「追加」をクリックし、以下を設定します。

  • アクショングループ名: GetWeather

  • 説明: 指定された緯度・経度の現在の天気情報を取得する

  • アクショングループタイプ: 関数の詳細で定義

  • Lambda関数: weather-agent-function

関数の定義:

項目
関数名 get_current_weather
説明 指定された緯度と経度の現在の天気情報(気温、天候、湿度、風速)を取得します

パラメータ:

名前 説明 タイプ 必須
latitude 天気を取得したい場所の緯度(例: 35.6762) string はい
longitude 天気を取得したい場所の経度(例: 139.6503) string はい

3. Lambda のリソースベースポリシー設定

ここが注意が必要なポイントでした。Bedrock Agents が Lambda 関数を呼び出すには、リソースベースポリシーの追加が必要です。

Lambda コンソール → weather-agent-function →「設定」→「アクセス権限」→「リソースベースのポリシーステートメント」→「アクセス権限を追加」で以下を設定します。

項目
ポリシーステートメント AllowBedrockAgentInvoke
プリンシパル bedrock.amazonaws.com
ソースARN arn:aws:bedrock:ap-northeast-1:<アカウントID>:agent/<エージェントID>
アクション lambda:InvokeFunction

エージェントIDは、Bedrock コンソールのエージェント画面上部で確認できます。

この設定を忘れると、テスト時に Access denied while invoking Lambda function エラーになります。

4. テスト

エージェントビルダー画面で「準備」をクリックし、右側のテストパネルから動作確認します。

東京の天気を教えて

と入力すると、以下のような回答が返ってきます。

東京の現在の天気をお知らせします:

- 天候: 一部曇り
- 気温: 14.4°C
- 湿度: 69%
- 風速: 5.4 km/h

アドバイス:
今日は一部曇りですが、比較的穏やかな天気です。気温は14.4°Cとやや涼しいので、
軽めのジャケットや上着があると快適に過ごせるでしょう。

プロンプトで指示した通り、日本語で回答し、天気に基づいたアドバイスも添えてくれています。

5. エイリアス作成とAPIからの呼び出し

テストが成功したら、エイリアスを作成してプログラムから呼び出せるようにします。

エージェント画面の「エイリアス」タブ →「エイリアスを作成」で、エイリアス名 prod を作成します。

必要なIDの確認

APIからの呼び出しには以下の2つのIDが必要です。

ID 確認場所
エージェントID エージェント画面上部
エイリアスID 「エイリアス」タブ → prod の「エイリアスID」列

AWS CLI でも確認できます。

# エージェントID確認
aws bedrock-agent list-agents --region ap-northeast-1

# エイリアスID確認
aws bedrock-agent list-agent-aliases --agent-id <エージェントID> --region ap-northeast-1

Python(boto3)での呼び出し

Bedrock Agents はストリーミングレスポンスを返すため、AWS CLI では直接呼び出せません。Python SDK(boto3)の Amazon Bedrock Agent Runtime クライアントを使います。

import boto3

AGENT_ID = "<エージェントID>"
ALIAS_ID = "<エイリアスID>"
REGION = "ap-northeast-1"

client = boto3.client("bedrock-agent-runtime", region_name=REGION)

response = client.invoke_agent(
    agentId=AGENT_ID,
    agentAliasId=ALIAS_ID,
    sessionId="test-session-001",
    inputText="東京の天気を教えて",
)

completion = ""
for event in response.get("completion"):
    chunk = event["chunk"]
    completion += chunk["bytes"].decode()

print(completion)

実行すると、コンソールのテストパネルと同じ回答が返ってきます。

同じ sessionId を使い続けると会話の文脈が保持されるので、連続した質問も可能です。

まとめ

今回は Amazon Bedrock Agents を使って天気エージェントを作成しました。

  • Lambda 関数1つとコンソール設定だけでAIエージェントが作れる

  • アクショングループで「エージェントができること」を定義し、Lambda で実装する

  • リソースベースポリシーの設定を忘れずに

  • boto3 の invoke_agent でプログラムからも呼び出せる

エージェントの基本的な仕組み(推論 → ツール呼び出し → 回答生成)を体験するのに良い題材だと思います。次は AgentCore も試してみます。

北出 宏紀(執筆記事の一覧)

アプリケーションサービス本部ディベロップメントサービス3課

2024年9月中途入社です。