[Agents for Amazon Bedrock] 簡素化された定義を試してみました

2024.05.24

1 はじめに

CX事業本部製造ビジネステクノロジー部の平内(SIN)です。

Agents for Amazon Bedrockでアクションの定義を行う場合、次の2種類の方法があります。

  1. Set up an OpenAPI schema
  2. Set up function details
    https://docs.aws.amazon.com/bedrock/latest/userguide/action-define.html

1.は、従来のOpenAPI標準のスキーマを準備する方法で、2.は、先月、新しく追加された簡素化された設定です。
Apr 23, 2024 - Amazon Bedrock のエージェントでエージェント作成が簡素化され、Return of Control 機能をリリース

今回は、最初にOpenAPIのスキーマを使用した従来の定義方法でエージェントを作成し、これを簡素化された定義に変更することで、その移行方法を確認してみました。

最初に、サンプルで作成したエージェントが動作している様子です。

このエージェントは、天気情報を取得して、服装をアドバイスするものです。 参照する地域が変わると、天気情報が変化するため、レコメンドも変化していることが分かると思います。

2 OpenAPIスキーマーによる設定

Action group typeでは、Define with API schemasを選択し、Action group schemaで、S3に配置されたOpenAPIスキーマーを指定しています。

Lambdaは、天気情報を取得するために使われています。

天気情報については、OpenWeatherMapから3時間毎の天気情報を取得し、9時間分を整形して配列で返しています。

[
  {"日時": "2024-05-24 09:00:00+09:00", "天気": "厚い雲", "気温(℃)": 21.58, "気圧": 1007, ・・・・},
  {"日時": "2024-05-24 12:00:00+09:00", "天気": "晴れ", "気温(℃)": 27.18, "気圧": 1007, ・・・},
  {"日時": "2024-05-24 15:00:00+09:00", "天気": "雨", "気温(℃)": 25.71, "気圧": 1006, "湿度": 33・・・}
]

なお、都市については環境変数で指定されており、使用場所に応じて変化させる想定です。

Lambda

import datetime
import json
import os
import requests
import pytz


def create_forecast_item(item):
    date_str = str(
        datetime.datetime.fromtimestamp(item["dt"], pytz.timezone("Asia/Tokyo"))
    )  # 日時
    weather = item["weather"][0]["description"]  # 天気
    feels_like = item["main"]["feels_like"]  # 体感温度
    pressure = item["main"]["pressure"]  # 気圧
    humidity = item["main"]["humidity"]  # 湿度
    wind = item["wind"]["speed"]  # 風速
    clouds = item["clouds"]["all"]  # 曇り率(%)
    rainfall = item.get("rain", {}).get("3h", 0)  # 雨量(mm)
    return {
        "日時": date_str,
        "天気": weather,
        "気温(℃)": feels_like,
        "気圧": pressure,
        "湿度": humidity,
        "風速": wind,
        "曇り率(%)": clouds,
        "雨量(mm)": rainfall,
    }


def get_weather_forecast(city, api_key):
    url = "http://api.openweathermap.org/data/2.5/forecast?q={}&appid={}&lang=ja&units=metric".format(
        city, api_key
    )
    forecast_data = requests.get(url).json()

    if "list" in forecast_data:
        list = forecast_data["list"]
        return [create_forecast_item(item) for i, item in enumerate(list) if i < 3]
    return []


def lambda_handler(event, context):

    city = os.getenv("CITY")
    api_key = os.getenv("API_KEY")
    forecast = get_weather_forecast(city, api_key)

    response = {
        "actionGroup": event["actionGroup"],
        "apiPath": event["apiPath"],
        "httpMethod": event["httpMethod"],
        "httpStatusCode": 200,
        "responseBody": {
            "application/json": {
                "body": json.dumps({"forecast": forecast}, ensure_ascii=False)
            }
        },
    }

    api_response = {"messageVersion": "1.0", "response": response}

    return api_response

OpenAPIのスキーマは、以下のとおりです。

openapi.yaml

openapi: 3.0.0
info:
  title: 天気取得API
  version: 1.0.0
  description: 3時間毎の天気情報を取得するAPI
paths:
  /get_weather:
    post:
      summary: 3時間毎の天気情報を取得するAPI
      description: 3時間毎の天気情報が配列で返されます
      operationId: get_weather
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        "200":
          description: articless response
          content:
            application/json:
              schema:
                type: object
                properties:
                  article:
                    type: string
                    description: 天気情報の配列

エージェント向けの指示

あなたは、外出の服装を、{天気}に合わせてアドバイスするファッションのプロです。
{天気}は{天気取得API}から取得できます。
ファッション・服装に関する事項は、エージェント自身で考えてください

アドバイスには、女性向けに具体的な服装を教えて下さい
アドバイスには、天気の情報や、注意事項を含めてください
アドバイスには、ちょっとした励ましの言葉を追加してください

### 会話の例

ユーザー:何を着て行けばいいでしょう?
エージェント:日中は穏やかですが、朝夕、気温が下がるので、少し上から羽織るものも用意したほうが良いでしょう。良い日になりますように!

ユーザー:今日、着ていく服のアドバイスを下さい
エージェント:今日は一日雨の予報です。小雨なので濡れる心配は少ないですが、長靴やレインコートを持っていくことをおすすめします。気温は朝が13度くらいで、日中は12度くらいに下がる見込みです。湿度も高いので、少し厚手の上着を羽織ることをおすすめします。楽しんで来てください!


ユーザー:どんな服装で出かければいいでしょう?
エージェント:朝は晴れですが、気温が低めですので、長袖の上着を羽織ることをおすすめします。 日中は高温多湿なので、半袖で過ごしやすいでしょう。日傘があると良いでしょう。 雨も少し降る可能性があるので、折り畳み傘を持参することをおすすめします。 楽しい1日になりますように!

3 簡素化された設定

続いて、簡素化された設定に変更してみます。

Action group typeでは、Define with function detailsの選択となり、Action group functionで、Lambdaの機能の説明や、パラメータ設定を行っています。(※今回は、Lambdaのパラメータは使用されていません)

実は、設定だけを変更してエージェントを使用すると、下記のようにLambdaの呼び出しが失敗します。

この原因は、簡素化された設定を使用する場合、Lmabdaのリクエスト及び、レスポンスの形式が変わるためです。

Lambdaのレスポンスを下記のように変更することで、エラー無く利用できるようになります。

def lambda_handler(event, context):

    city = os.getenv("CITY")
    api_key = os.getenv("API_KEY")
    forecast = get_weather_forecast(city, api_key)

    # 簡素化された設定の場合
    response = {
        "actionGroup": event["actionGroup"],
        "function": event["function"],
        "functionResponse": {
            "responseBody": {
                "TEXT": {"body": json.dumps({"forecast": forecast}, ensure_ascii=False)}
            }
        },
    }

    # OpenAPI Schemaの場合
    # response = {
    #     "actionGroup": event["actionGroup"],
    #     "apiPath": event["apiPath"],
    #     "httpMethod": event["httpMethod"],
    #     "httpStatusCode": 200,
    #     "responseBody": {
    #         "application/json": {
    #             "body": json.dumps({"forecast": forecast}, ensure_ascii=False)
    #         }
    #     },
    # }

    api_response = {"messageVersion": "1.0", "response": response}

    return api_response

今回は、Lambdaへのパラメータを使用していないので、上記の修正(レスポンス)だけで作業は完了でしたが、パラメータを使用している場合は、そこの修正も必要になります。

それぞれのパラメータ及び、レスポンスの形式については、下記にドキュメントがあります。
Configure Lambda functions to send information an Amazon Bedrock agent elicits from the user to fulfill an action groups in Amazon Bedrock

4 最後に

今回は、エージェントのアクション定義で「簡素化されたもの」を試してみました。 OpenAPIスキーマを準備するより、圧倒的に手軽だし、すべてがコンソール上で定義できるので、手返しも良くなって全然いい感じでした。

Set up function details 一択でいいのでは・・・って思ってしまってます。

5 参考にさせて頂いたリンク


Create an action group for an Amazon Bedrock agent PDF
【WebAPI】OpenWeatherMapで3時間ごとの天気を取りたい【json】