見出し画像

Agents for Amazon Bedrockでサンプルアプリを作ってみた


Agents for Amazon Bedrock について

Agents for Amazon BedrockAWS re:Invent 2023で発表されたBedrockの新機能となります。
本機能を利用することでにより、独自データやビジネスロジックの組み込み、システム連携がおこなえる自社独自生成AIアプリケーションを実装できます。

Agents for Amazon Bedrockの主な機能

生成AIアプリのふるまいを定義

生成AIアプリケーションのふるまいを定義し、特定用途に特化したアプリケーションを作成することができます。

具体的には以下の様な事が実施可能です。

  • 役割の定義

    • AIアプリケーションが担う役割を定義できます。

      • 「カスタマーオペレーター」や「製品説明員」等

  • 実施タスクや手順の定義

    • AIアプリケーションが実施するタスク内容や手順、タスクに必要な情報を定義できます

      • 「指定された商品名、商品個数から商品を購入する」「商品名から商品数を検索する」等

自社独自データの活用

Bedrock ナレッジベースを組み込んだ形でアプリケーションが実装できます。これにより、基盤モデルが学習していない独自データを利用したアプリケーションが実装できます。

また、ナレッジベースの利用はユーザ側の入力をエージェントが解釈、事前定義された「AIアプリのふるまい」に応じて適切なナレッジベースを利用してくれます。

独自処理の実装

アクショングループ という機能によるLambdaを呼び出せます。
Lambdaを実行できることにより生成AIだけでは実施が難しいビジネスロジック実装、AIアプリに組み込むことができます。
具体的には以下の様な事が可能です。

  • 社内DBへの問い合わせ

    • DB検索結果をもとにした回答の生成が可能となる等

  • システム連携処理

    • API連携により他システムから情報取得(CRMから顧客情報取得・返却 等)

    • API連携により他システムに処理実行要求(ECとの連携で商品購入処理の実行等)

  • bedrock以外のAWSサービスと連携した処理

    • プロンプトを通じてEC2の起動・停止処理の実装 等

  • 外部APIからの情報取得

    • 公開されている外部APIの情報を利用した回答の生成

Agents for Amazon Bedrockの俯瞰イメージ

Agents for Amazon Bedrockを俯瞰したサービスイメージは以下の様な内容となっています

Agents for Amazon Bedrockの俯瞰イメージ

検証シナリオ

実現すること

今回「商品検索、購入用AIアプリ」のサンプルアプリを作成したいと思います。要件は、以下とします。

  • ユーザの問い合わせ内容に応じて最適な製品を紹介する

    • 紹介製品は製品情報ドキュメントのデータを利用する

  • 製品の在庫状況を問い合わせることができる

    • 製品名を問い合わせると在庫数を返す

  • 製品の購入処理ができる

    • 製品名と購入数を指示すると購入処理が実行される

    • 購入成否を返す

実装方針

  • 全体的なエージェントのふるまいについて

    • 実現したいことを文章化した内容を「エージェント向けの指示」として登録

  • ユーザの問い合わせ内容に応じて最適な製品を紹介する

    • 商品紹介用のナレッジベースを作成

    • S3に商品一覧と商品概要資料を記載した資料を設置

  • 在庫状況の問い合わせ

    • アクショングループとして在庫状況問い合わせ用のLambdaを紐づけ

    • 本検証ではLambdaがランダムで生成した数値データだけ返す形とする

  • 商品の購入

    • アクショングループとして商品購入用のLambdaを紐づけ

    • 本検証ではLambdaがランダムで購入成否を判断し、その結果を返す形とする。

実装内容(ナレッジベース)

ナレッジベースの作成

商品紹介用のナレッジベースを作成します。
ナレッジベースの作成手順については、以下記事に記載しているので、本記事では詳細を割愛します。

尚、ナレッジベースに設置するで商品データは Claude 3 Sonnetに生成してもらった以下の様な架空の製品情報を利用しました。

1. 商品名: マジカル・シェイプシフター
‐ 商品概要: この革新的な製品は、あなたの夢を形に変える能力を持っています。単なるおもちゃではなく、想像力を具現化するツールです。好きな形に変形させ、創造性を解き放ちましょう。
- おすすめするユーザ: 子供から大人まで、創造性に富んだ人々にぴったりです。

2. 商品名: ネオ・トランスレーター
‐ 商品概要: 言語の壁を完全に打ち破る究極の翻訳デバイスです。あらゆる言語をリアルタイムで翻訳し、コミュニケーションの障壁を取り除きます。ビジネスや旅行での必需品です。
- おすすめするユーザ: 国際的に活躍するビジネスパーソン、冒険家、旅行者向けです。

3. 商品名: エコ・リバイバル・キット
‐ 商品概要: 環境保護に熱心な人のための必需品です。この製品は、枯れた植物を復活させ、自然を蘇らせる力を秘めています。使い方は簡単で、あなたの庭を緑に染め上げます。
- おすすめするユーザ: 園芸愛好家、自然愛好家、環境意識の高い人におすすめです。

(全10製品。他は割愛)

実装内容(エージェントの作成)

エージェントの作成に関しては、マネジメントコンソールのBedrock の画面から実施しました

  • Bedrock画面 → エージェント → エージェントの新規作成

エージェントの詳細設定

「エージェントの詳細を入力」画面では以下の設定項目を設定します。

  • エージェント名

    • 任意の名称で登録

  • エージェントの説明 - オプション

    • 任意の説明を登録

  • ユーザ入力

    • アクションするための入力情報が不足している場合に、ユーザに対して追加情報を求めるか

    • 今回は「はい」を選択

  • IAM許可

    • エージェントに紐づけるIAMRoleの設定

    • 既存、新規が選択可能であるが、今回は新規を選択

  • KMS キーセレクション

    • オプション。カスタマーマネージドキーを利用する場合のみ利用

    • 今回は指定なし

  • アイドルセッションタイムアウト

    • ユーザが未入力状態が続いた際のセッションタイムアウト時間の定義

    • 今回は30分で設定

  • タグ

    • 今回は設定なし

モデルを選択
利用するモデルを選択する。2024/3/14現在ではAnthropicClaude(V1, V2.1 , V2)のみが選択可能でした。
今回はClaude V2.1を選択しました。

モデル選択画面では利用モデル以外に「エージェント向けの指示」の設定を実施します。この「エージェント向けの指示」が生成AIアプリのふるまいを定義する設定となります。

今回は以下の様に設定しました。

あなたは商品説明員です。ユーザが希望する商品を提案してください。
その商品に関して現在の商品数を確認して購入可能であるか回答してください。 
ユーザが商品の購入を求めた場合には購入処理を実施してください。
モデル選択画面

アクショングループを追加 - オプション

エージェントの初期設定でアクショングループの設定も実施できますが、アクショングループの設定に関しては後述するので、初期設定では設定しない形とします。

ナレッジベースを追加 - オプション

事前に作成しておいた「商品紹介用のナレッジベース」を選択します。
また、「エージェント向けのナレッジベースの指示」の設定がありますが、こちらは設定したナレッジベースがどの様なデータが入っていて、どの様な用途で利用するのかを記載します。

この内容に応じてエージェントはナレッジベースへの問い合わせの判断をしている様です。

今回は以下の様に設定しました。

商品名と商品説明が登録されています。
商品検索する際にこのナレッジベースを利用してください。
ナレッジベース設定

確認画面

確認画面を経てエージェントの初期設定は完了です。
これでアクショングループ以外設定は完了となります。

実装内容(Lambdaの実装)

事前にアクショングループに紐づけるLambdaを作成します。
今回は以下2つのLambdaを作成しました。

  • 在庫数検索用Lambda

  • 商品購入用Lambda

Lambdaの登録

Lambdaに設定に関しては基本的には初期設定で問題なく、IAMRoleもCloudWatachLohgsへのアクセス等、最低限の設定だけで問題ありませんでした。

一点だけリソースベースポリシーはBedrock agent から実行できる様に設定する必要がありました。
以下は今回設定したリソースベースポリシーです。

{
  "Version": "2012-10-17",
  "Id": "default",
  "Statement": [
    {
      "Sid": "id-01",
      "Effect": "Allow",
      "Principal": {
        "Service": "bedrock.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "LambdaのARN",
      "Condition": {
        "ArnLike": {
          "AWS:SourceArn": "Bedrock agent の ARN"
        }
      }
    }
  ]
}

Lambda用コードの実装(制約条件)

エージェント用のLambdaですが、まず入力として以下のフォーマットのデータが渡されて実行されます。

{
    "messageVersion": "1.0",
    "agent": {
        "name": "string",
        "id": "string",
        "alias": "string",
        "version": "string"
    },
    "inputText": "string",
    "sessionId": "string",
    "actionGroup": "string",
    "apiPath": "string",
    "httpMethod": "string",
    "parameters": [
        {
            "name": "string",
            "type": "string",
            "value": "string"
        },
    ...
    ],
    "requestBody": {
        "content": {
            "<content_type>": {
                "properties": [
                   {
                       "name": "string",
                       "type": "string",
                       "value": "string"
                    },
                            ...
                ]
            }
        }
    },
    "sessionAttributes": {
        "string": "string",
    },
    "promptSessionAttributes": {
        "string": "string"
    }
}

各値に関する詳細に関しては、以下の公式ページに詳細が記載されているので、こちらを参照してください。

https://docs.aws.amazon.com/ja_jp/bedrock/latest/userguide/agents-lambda.html#agents-lambda-input

この中で重要になるのは、parametersかと思います。こちらにアクショングルグループを実行するにあたり必要なパラメータが入っていますので、Lambdaではこの値を取り出して実行することになります。
parametersの値はユーザが入力した値が入ってきます。parametersの設定は後述するOpenAPIスキーマの設定で定義します。

Lambdaのレスポンスに関しては、以下のフォーマットで返す必要があります。

{
    "messageVersion": "1.0",
    "response": {
        "actionGroup": "string",
        "apiPath": "string",
        "httpMethod": "string",
        "httpStatusCode": number,
        "responseBody": {
            "<contentType>": {
                "body": "JSON-formatted string" 
            }
        },
        "sessionAttributes": {
            "string": "string",
        },
        "promptSessionAttributes": {
            "string": "string"
        }
    }
}

各値に関する詳細に関しては、以下の公式ページに詳細が記載されているので、こちらを参照してください。

https://docs.aws.amazon.com/ja_jp/bedrock/latest/userguide/agents-lambda.html#agents-lambda-response

この中でポイントになるのが、以下です。

  • responseBody に生成AIに返したい値を入れる

  • httpStatusCodeに処理結果に対するステータスコードを入れる

    • 200, 400 等

    • ステータスコードの定義も後述するOpenAPIスキーマの設定と合わせる

Lambda用コードの実装(実装コード)

上記制約のもと、今回は以下の様に実装しました。

  • 在庫数検索用Lambda

    • 製品数をランダム値で返却するだけのLambda

    • 製品数はresponse_body内のbody値として返却

import random

def lambda_handler(event, context):
    
    print(event)
    
    item_num = [0,1,2]

    response_body = {
        'application/json': {
            'body': random.choice(item_num)
        }
    }

    action_response = {
        'actionGroup': event['actionGroup'],
        'apiPath': event['apiPath'],
        'httpMethod': event['httpMethod'],
        'httpStatusCode': 200,
        'responseBody': response_body
    }

    session_attributes = event['sessionAttributes']
    prompt_session_attributes = event['promptSessionAttributes']

    api_response = {
        'messageVersion': '1.0', 
        'response': action_response,
        'sessionAttributes': session_attributes,
        'promptSessionAttributes': prompt_session_attributes
    }

    print(api_response)
    
    return api_response
  • 製品購入用Lambda

    • ランダム値で「購入完了」、「購入失敗」を判定

    • 購入結果はresponse_body内のbody値として返却

    • 購入完了の場合にはステータスコード 200 で返却

    • 購入失敗の場合にはステータスコード 400 で返却

import random

def lambda_handler(event, context):
    
    print(event)
    
    Result = ["購入完了","購入失敗"]

    response_body = {
        'application/json': {
            'body': random.choice(Result)
        }
    }

    if response_body['application/json']['body'] == "購入完了":
        action_response = {
            'actionGroup': event['actionGroup'],
            'apiPath': event['apiPath'],
            'httpMethod': event['httpMethod'],
            'httpStatusCode': 200,
            'responseBody': response_body
        }
    elif response_body['application/json']['body'] == "購入失敗":
        action_response = {
            'actionGroup': event['actionGroup'],
            'apiPath': event['apiPath'],
            'httpMethod': event['httpMethod'],
            'httpStatusCode': 400,
            'responseBody': response_body
        }

    session_attributes = event['sessionAttributes']
    prompt_session_attributes = event['promptSessionAttributes']
    
    api_response = {
        'messageVersion': '1.0', 
        'response': action_response,
        'sessionAttributes': session_attributes,
        'promptSessionAttributes': prompt_session_attributes
    }

    print(api_response)
    
    return api_response
    

実装内容(アクショングループの設定)

アクショングループの設定

今回のアクショングループは以下2種類のアクショングループを設定しました。

  • 在庫数検索用アクショングループ

    • 在庫数検索用Lambdaと紐づけるアクショングループ

  • 製品購入用アクショングループ

    • 製品購入用Lambdaと紐づけるアクショングループ

アクショングループの設定は マネジメントコンソールで実施しました。
設定する内容は以下の通りです。

  • アクショングループ名

    • 任意の名称

  • 説明 - オプション

    • 任意

  • Lambda関数

    • アクショングループと紐づけるLambdaを選択

  • APIスキーマ

    • S3に設置のものとOpenAPI スキーマエディターによる定義が可能

    • 設定内容は後述

アクショングループ設定

API スキーマの設定について

APIスキーマではアクショングループの用途や、アクショングループ実施時の必要パラメータ定義、レスポンス設定を実施します。

設定については、以下の様なOpenAPIスキーマで定義します。

{
    "openapi": "3.0.0",
    "paths": {
        "/path": {
            "method": {
                "description": "string",
                "operationId": "string",
                "parameters": [ ... ],
                "requestBody": { ... },
                "responses": { ... }
           }
       }
    }
}

詳細は以下をご参照下さい。

具体例は今回の検証内容で設定した内容にしたがい説明します。

API スキーマの設定について(今回の設定値)

在庫数検索用アクショングループのAPIスキーマは以下の様の設定しました。

openapi: 3.0.0
info:
  title: 商品数検索API
  version: 1.0.0
  description: 入力された商品名から商品数を返却するAPI
paths:
  /search:
    get:
      summary: Item number search
      description: 入力された商品名から商品数を返却します
      operationId: search
      parameters: 
        - name: ItemName
          in: "path"
          description: 商品名
          required: true
          schema: 
            type: "string"
      responses:
        "200":
          description: 商品数を返却します
          content:
            application/json:
              schema:
                type: object
                properties:
                  body:
                    type: string

ポイントとなるのは、descriptionとなります。
エージェントでは本内容でユーザ要求に対して実行するアクショングループを判断している模様です。
その次にparametersでアクショングループ実行に必要なパラメータを定義しているので、ユーザ要求で本アクショングループ実行を指定する様な要求であってもパラメータに沿った要求がそろわない限り実行されません。
最後にresponsesですが、こちらでステータスコードの定義とアクショングループ実行に返す値の定義をします。本設定がLambdaで実装したコードと併せる形になると思います。

上記の例では、商品名をInputとしてLambda実行で返された商品在庫数を返却する設定となります。

製品購入用アクショングループのAPIスキーマは以下の様の設定しました。

openapi: 3.0.0
info:
  title: 商品数購入API
  version: 1.0.0
  description: 指定された商品名、個数で商品購入処理をするAPI
paths:
  /buy:
    post:
      summary: Item number search
      description: 指定された商品名、個数で商品購入処理を実施して購入結果を返却します。
      operationId: buty
      parameters: 
        - name: ItemName
          in: "path"
          description: 商品名
          required: true
          schema: 
            type: "string"
        - name: ItemNum
          in: "path"
          description: 商品個数
          required: true
          schema: 
            type: integer
      responses:
        "200":
          description: 購入完了しました。
          content:
            application/json:
              schema:
                type: object
                properties:
                  body:
                    type: string
        "400":
          description: 購入失敗しました。
          content:
            application/json:
              schema:
                type: object
                properties:
                  body:
                    type: string

上記例では「商品名」と「購入個数」をパラメータとして、商品成功時には200、商品失敗の際には 400 として返答する設定としています。

実装したアプリの動作について

テスト方法

エージェントの動作確認はマネジメントコンソールで実施することができます。
尚、今回は詳細は割愛しますが、エイリアスを作成してバージョン管理を行うことも可能な様です。

エージェントのテスト

また、テスト実施時にはトレース結果が確認が可能です。これによりプロンプトをどの様に解釈し、その結果に応じたナレッジベースへの問い合わせやアクショングループの実行結果が確認することが可能です。

トレース画面について

サンプルアプリのテスト結果

以下の様な期待する結果となりました。
「AIの実施内容」部は前述したエージェントのテストのトレース部を要約した内容となっています。

  • (質問)

    • 冒険家におすすめの商品はありますか?

  • (回答)

    • ネオ・トランスレーターが冒険家や旅行者におすすめの商品です。[1]

  • (AIの実施内容)

    • 商品説明を求めらていると解釈

    • ナレッジベースへの検索と在庫状況確認のために在庫数検索用アクショングループの実行を判断

    • ナレッジベースへの問い合わせ結果をもとに回答を生成

  • (質問)

    •  ネオ・トランスレーターについて説明してください。

  • (回答)

    • ネオ・トランスレーターは、あらゆる言語をリアルタイムで翻訳し、コミュニケーションの障壁を取り除く究極の翻訳デバイスです。冒険家や旅行者にとって非常に便利なアイテムです。

  • (AIの実施内容)

    • 商品詳細を求める質問と解釈

    • ナレッジベースへの問い合わせ結果をもとに回答を生成

  • (質問)

    • ネオ・トランスレーターは在庫はありますか?

  • (回答)

    • はい、ネオ・トランスレーターは現在2個在庫があります。

  • (AIの実施内容)

    • 在庫数の問い合わせであると解釈

    • 在庫数検索用アクショングループを実行

    • 実行結果をもとに返答を生成

  • (質問)

    • ネオ・トランスレーターを購入したいです。

  • (回答)

    • はい、ネオ・トランスレーターは現在1個在庫があります。ご購入希望でしょうか? 購入処理を実施いたしますので、ご希望でしたら「はい」とお答えください。

  • (AIの実施内容)

    • 在庫数を確認して要望があれば購入手続きが必要と判断

    • 在庫数検索用アクショングループを実行

    • 在庫数検索用アクショングループの実行結果から在庫があったため、購入確認のプロンプトを返答

  • (質問)

    • はい

  • (回答)

    • ネオ・トランスレーターの購入処理を実施しました。購入完了となりました。

  • (AIの実施内容)

    • 製品購入用アクショングループ を実行

    • 製品購入用アクショングループの返答結果から購入完了を判断し、返答


テスト画面

ただし、上記のテスト結果を得られるまでに、想定通りに返答しないこともあったのも事実でした。そちらは「エージェント向けの指示」やナレッジベース、アクショングループへの指示内容の精度が低かったものと考えています。
そのため、本番利用する際には制度の高い指定方法を検証して見つけていくこともポイントになると感じました。

まとめ

Agents for Amazon Bedrockを今回試してみましたが、こちらは生成AIの独自アプリ実装時の大きな助けになる機能であると感じました。
今後、生成AIを利用した独自アプリ実装時にはぜひご利用を検討してみてはいかがでしょうか。

この記事が気に入ったらサポートをしてみませんか?