5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Amazon Bedrockエージェント実践】Next.js使ってチャットアプリを作る

Last updated at Posted at 2024-11-24

この記事を読んで何を作れる?

agent.gif

レスポンス帰って来るまでちょっと時間かかります。

Amazon BedrockエージェントとNext.jsアプリを連携し、通常の会話はもちろん、
都市の天気についての質問にも最新の情報を取得して答えできるアプリが作れます。

アーキテクチャ

hi.drawio.png

ローカル開発時のアーキテクチャーは上記の図になります。

もしご好評でしたら、次回の記事でcdk使ってデプロイまでやります:relaxed:

そもそもBedrockって何?

AWSが提供する基盤モデルを使用して生成 AI アプリケーションを構築およびスケーリングする最も簡単な方法らしいです。

詳しく知りたい方はこちらの資料をご覧ください。

事前準備

AWSのアカウント

BedRock モデルの有効化

AWSアカウントが準備できましたら、コンソールからAmazon Bedrockを開いて、
BADCA02A-F687-4F63-9937-3C59F7C936C2_4_5005_c.jpeg

モデルアクセスから今回使用するClaude 3.5 Sonnetモデルへのアクセス申請を行ってください。

60A03F76-4A1B-4F48-AF82-9247117ED8D2.jpeg

いくつかの質問に回答すると、しばらくしてアクセスが付与されます。

OpenWeather - APIキー

A4289034-AA03-41E6-9785-37C054599468.jpeg

OpenWeatherMapは、Webやモバイルアプリケーションの開発者に、現在の天候や予測履歴を含む各種気象データの無料APIを提供するオンラインサービスである。

アカウントを作ったらメニューバーのMy API KeysからApiKeyを入手できます。

E3DD8F4B-A9C3-49A7-A275-9B8D39BE4528_1_105_c.jpeg

:point_up_tone1: 一点注意すべきなのはApiKey生成後、しばらく待たないと使用できないことです。

エージェント作成

Amazon Bedrockの左にあるメニューバーからエージェントを開いて、エージェントを作成します。
4D9302D5-ED5C-4CCD-957D-E75AE783F720.jpeg

エージェントの名前をweather-agentにして、説明文を入れて作成します。

8D28812D-DF5E-4685-8B1F-47C9E6E248E6_4_5005_c.jpeg

作成されたら、あらかじめ有効化にされたモデルを選びます、その他の設定は一旦デフォルトのままにしましょう。

C0FEB239-4A64-476E-81E8-6CA46F07961E.jpeg

次、アクショングループを作成します。

C11DEAE1-A046-46CB-BD93-FF00E31DFB87_4_5005_c.jpeg

追加ボタンをクリックすればアクションを追加画面が開きます。

8DC3AC0B-8AF9-4C9F-8238-35A7E92A1C34.jpeg

  • アクショングループ名を入力します: action-group-get-weather
  • 説明を入力します: get weather action group
  • アクショングループタイプ: APIスキーマで定義を選択します
  • アクショングループの呼び出し: 新しい Lambda 関数をすばやく作成する - 推奨にチェックを入れます
  • アクショングループスキーマは: インラインスキーマエディタで定義を選びます

インラインオープン API スキーマは下記のように定義します。

openapi: 3.0.0
info:
  title: GetWeather
  version: 1.0.0
paths:
  /weather:
    get:
      summary: Search
      description: Retrieve current weather information for a specified city
      operationId: searchGetWeatherInfo
      parameters:
        - name: cityName
          in: path
          description: Name of the city to get weather information for API
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: object
                properties:
                  body:
                    type: string      

最後作成をクリックします、しばらくしたらエージェントビルダーのメイン画面に戻されます。

9E255E1B-132C-42DB-AF93-B085D4A03CBE_4_5005_c.jpeg

そしたら、アクショングループから先ほど作られたアクションを確認できます。

AF04C9DF-B1BC-48F0-89B3-5CECB5B43235_4_5005_c.jpeg

アクションの名前をクリックして、編集画面に入ります。
その画面のLambda 関数を選択から表示ボタンをクリックしてください。
284110C3-B84A-407F-A851-B93FC8F25F2C.jpeg

別タグからLambda関数の編集画面が表示されると思います。

エージェントビルダー画面から新しいLambdaを作成する場合、現在Python製になる一択です。

Lambdaコードを下記のように修正して、Deployしてください。
OpenWeatherMapのAPIKeyは一旦ベタ書きします。

dummy_lambda.py
import json
import urllib.request
import urllib.parse
from datetime import datetime

def lambda_handler(event, context):
    api_key = "" # ご自身のキーを入れてください。
    get_parameters = event.get("parameters", [])
    city_name = get_parameters[0].get("value", "New York City")
    print("city_name:", city_name)
    
    base_url = "http://api.openweathermap.org/data/2.5/weather"
    query_params = {
        "q": city_name,
        "appid": api_key,
        "lang": "ja",
        "units": "metric"
    }
    url = f"{base_url}?{urllib.parse.urlencode(query_params)}"
    
    try:
        with urllib.request.urlopen(url) as response:
            if response.status != 200:
                raise Exception(f"HTTP Error: {response.status}")
            
            data = json.loads(response.read().decode("utf-8"))
        
        weather_description = data["weather"][0]["description"]
        temperature = data["main"]["temp"]
        feels_like = data["main"]["feels_like"]
        humidity = data["main"]["humidity"]
        wind_speed = data["wind"]["speed"]
        
        sunrise_time = datetime.fromtimestamp(data["sys"]["sunrise"]).strftime('%H:%M')
        sunset_time = datetime.fromtimestamp(data["sys"]["sunset"]).strftime('%H:%M')
        
        contents = {
            "city": city_name,
            "weather": weather_description,
            "temperature": temperature,
            "feels_like": feels_like,
            "humidity": humidity,
            "wind_speed": wind_speed,
            "sunrise": sunrise_time,
            "sunset": sunset_time
        }
        
        message = (f"{city_name}の現在の天気は{weather_description}、気温は{temperature:.1f}℃です。"
                   f"体感温度は{feels_like:.1f}℃、湿度は{humidity}%、風速は{wind_speed}m/sです。"
                   f"日の出は{sunrise_time}、日の入りは{sunset_time}です。")
        
        contents["message"] = message
        
    except Exception as e:
        contents = {"error": f"天気情報の取得中にエラーが発生しました: {str(e)}"}
    
    response_body = {"application/json": {"body": json.dumps(contents)}}
    
    action_response = {
        "actionGroup": event.get("actionGroup", ""),
        "apiPath": event.get("apiPath", ""),
        "httpMethod": event.get("httpMethod", ""),
        "httpStatusCode": 200,
        "responseBody": response_body,
    }
    
    api_response = {"messageVersion": "1.0", "response": action_response}
    return api_response

次、Lambda関数の設定から、アクセス権限を選び、リソースベースのポリシーステートメントからagentsInvokeFunctionをチェック入れて編集します。
D9F62485-1F2B-4371-8D9B-48EC43395C36_4_5005_c.jpeg

ポリシーの編集画面でソース ARNにエージェントのARNを貼り付けて、アクションをlambda:InvokeFunctionを選択します。
AB1D2639-774A-4008-9916-DCD54E887E0F.jpeg

エージェント ARNは該当エージェントのメイン画面から入手できます。
A7903A5E-7753-4B50-B87F-769C590B4987.jpeg
設定完了したら、保存してAmazon Bedrockエージェントの画面に戻ります。

次にエージェント向けの指示を入力します。いわゆるプロンプトです。
今回の目的は、エージェントに天気について質問した際に、アクションを使ってリアルタイムの情報を取得し、それを元に回答してもらうことです。
また、OpenWeatherMap の API は都市名に英語でしか対応していません。そのため、日本語の都市名が入力された場合には、適切に英語に翻訳してから問い合わせてくれると便利です。

名称未設定ファイル.drawio.png

プロンプト

あなたはリアルタイムの天気情報を取得してユーザーに回答するエージェントです。以下の条件に従って行動してください:

1.ユーザーからの一般質問に関して、任意に回答してください。
2.ユーザーから天気情報に関する質問はアクション使って回答してください。
3.ユーザーから日本語で都市名を指定された場合、その都市名を英語に翻訳してから使ってください。

ユーザーが指定しない場合、デフォルトの都市名は「Tokyo」としてください。

B03CE26E-BEDA-4442-B607-4A6DE4E30AFA_4_5005_c.jpeg

入力完了しましたら、保存してから準備をクリックしてください。

81FCABFE-ED72-4283-8AB8-7E7294FBE331_4_5005_c.jpeg

エージェントの右側にテストできるので、軽く試してみます。
81859DC2-93BC-4071-A401-3EF6FC2AAFBF.jpeg

予想通りの結果が返ってきましたね、次はフロントエンドの実装をやっていきます。

チャット画面の実装

最初は Next.js プロジェクトを 0 から構築してすべて解説する予定でしたが、
尺の都合で、こちらのリポジトリをクローンしてご利用ください。
Star:star:いただけると励みになります:relaxed:

クローン後、ルートディレクトリの配下に.envファイルを作ってください。

.env
NEXT_PUBLIC_AWS_REGION=
NEXT_PUBLIC_AWS_ACCESS_KEY_ID=
NEXT_PUBLIC_AWS_SECRET_ACCESS_KEY=
NEXT_PUBLIC_AWS_SESSION_TOKEN=
NEXT_PUBLIC_AWS_AGENTID=
NEXT_PUBLIC_AWS_AGENT_ALIASID=

環境変数それぞれの意味を説明します。

  • NEXT_PUBLIC_AWS_REGION

先作ったBenrock Agentが存在するリージョン、東京リージョンの場合:ap-northeast-1

  • NEXT_PUBLIC_AWS_ACCESS_KEY_ID
  • NEXT_PUBLIC_AWS_SECRET_ACCESS_KEY
  • NEXT_PUBLIC_AWS_SESSION_TOKEN

AWS Identity Centerを利用している方は、アクセスポータルからアクセスキーなどをコピーしてご使用ください。
利用していない方は、Bedrock 用の IAM ユーザーを作成し、AmazonBedrockFullAccess ポリシーを付与した上で、アクセスキーとセキュリティキーをコピーしてご使用ください、IAM ユーザー利用される場合、NEXT_PUBLIC_AWS_SESSION_TOKENは不要です。

  • NEXT_PUBLIC_AWS_AGENTID

エージェントの概要一覧で確認できます。
FE2F5330-34F8-4D17-9769-A6AE0FB37938_4_5005_c.jpeg

  • NEXT_PUBLIC_AWS_AGENT_ALIASID

同じくエージェント概要一覧画面の最下部でエイリアス作成できます、作成されたエイリアンIDを利用しましょう

85D87A2C-0301-45DD-ABF4-49B7E9722125.jpeg

ローカルでの動作確認は下記のコマンドを実行してください。

$ npm i
$ npm run dev

最後に

完成品は下記の図のような感じになります。

372ECD4A-10AC-4FD1-A7BC-2579C400C5EA.jpeg

デプロイやIaCに興味がある方がいらっしゃれば、今度また別の記事でご紹介します:writing_hand_tone1:

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?