【やってみた】Agents for Amazon BedrockでLambdaとKnowledge baseに振り分ける

# はじめに

こんにちは、もちもちMAXです。  
先日、Agents for Amazon Bedrockを使って色々試す機会があったので、今回はその内容を記事にしていきたいと思います。  

## 作ったもの

今回作ったのは、Agentsを使って雑談とAWSに関する質問とを振り分けるシステムで構成図は下記の通りです。  
\
![AWS_structure.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463753/c176d89e-ba6b-4daf-3811-d3327677c87e.png)
\
現時点では、Agents for Amazon Bedrockはアクションベースとナレッジベースが登録できます。アクションベースはLambda関数を呼び出すことで目的に応じた処理をおこなえます。
今回は、Lambda関数からBedrockの基盤モデルを呼び出して雑談の返答をおこないます。  
ナレッジベースはいわゆるRAGシステムです。今回はAWSに関する知識を読み込ませたナレッジベースを作成しておきます。本記事では、ナレッジベースの作成方法については説明しません。またどこかのタイミングがあれば記事にしようかと思っています。  

## Lambda関数の準備

今回の構成では、エージェントがユーザの入力を雑談と判断した場合、アクションベースに登録したLambda関数を呼び出して基盤モデルとやり取りします。その設定手順を説明していきます。  
\
まずは、Lambda関数を作成します。関数名は任意で結構です。今回はLLMとやり取りするためにランタイムはPython3.12を選びますが、何か使いたいものがあればそれに合わせて変更してください。
![Lambda_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463753/4b3fa44a-b1b5-4441-80c6-7c218fff9dfe.png)
\
次に、Lambda関数のコードを書いていきます。この関数ではユーザから受け取った入力をそのままBedrockのAPIに渡します。内容的にはそれだけですが、APIを正しく呼び出せるようにちょこちょこ設定は追加してあります。コード全文は以下の通りです。  

```python
import boto3
import json
bedrock_runtime = boto3.client('bedrock-runtime')
def lambda_handler(event, context):
    # プロンプトに設定する内容を取得
    prompt = event["inputText"]
    # 各種パラメーターの指定
    modelId = 'anthropic.claude-3-sonnet-20240229-v1:0'
    accept = 'application/json'
    contentType = 'application/json'
    # リクエストの指定
    user_message = {
        "role": "user",
        "content": prompt
    }
    messages = [user_message]
    # リクエストBODYの指定
    body = json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "max_tokens": 1000,
        "messages": messages,
        "system": "フレンドリーに会話してください。"
    })
    # Bedrock APIの呼び出し
    response = bedrock_runtime.invoke_model(
    	modelId=modelId,
    	accept=accept,
    	contentType=contentType,
        body=body
    )
    # APIレスポンスからBODYを取り出す
    response_body = json.loads(response.get('body').read())
    # レスポンスBODYから応答テキストを取り出す
    answer = response_body["content"][0]["text"]
    # agentの形式でreturn
    response_body = {"application/json": {"body": answer }}
    action_response = {
		"actionGroup": event["actionGroup"],
		"apiPath": event["apiPath"],
		"httpMethod": event["httpMethod"],
		"httpStatusCode": 200,
		"responseBody": response_body,
    }
    api_response = {"messageVersion": "1.0", "response": action_response}
    return api_response
```  
\
次に、アクセス権限を設定していきます。アクセス権限は、Lambda関数自身がエージェントに呼び出されることを許可するための権限と、Lambda関数がBedrockのLLMを呼び出すための権限の2種類を設定します。まずは、エージェントからの呼び出し用の権限です。Lambda関数の`設定`>`アクセス権限`から`リソースベースのポリシーステートメント`という設定があるので、`アクセス権限の追加`を選択します。
![access_from_agent.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463753/640f8add-1050-ceab-d87e-4f5566cc16d8.png)
\
下記の項目を2枚目の画像の通り設定します。Principalに`bedrock.amazonaws.com`を、Effectに`Allow`を、Actionに`lambda:InvokeFunction`を設定することでエージェントからの呼び出しが可能となります。ステートメントIDは任意の一意の値としてください。
![access_from_agent_2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463753/1468fb81-05b3-bd64-02e7-99ef74cedd37.png)
![access_from_agent_3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463753/ce86517f-f193-8ef0-4356-4116e33f89e4.png)
\
最後に、Lambda関数からBedrockのLLMを呼び出すための設定をおこないます。`設定`>`アクセス権限`から`ロール名`が書いてある箇所のリンクをクリックします。
![access_to_bedrock.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463753/3ca3aa7c-3368-8a28-66aa-877efc54e5a5.png)
\
遷移した先で、`インラインポリシーを作成`を選択し下記の通りにJSONを設定します。
![access_to_bedrock_2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463753/700f05fc-6cc3-f449-a466-22d1c8df06f7.png)

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "bedrock:*",
            "Resource": "*"
        }
    ]
}
```  
\
作成したポリシーを設定したらLambda関数の準備は完了です。

## エージェントの設定

それでは早速エージェントを作成していきます。Descriptionは自分で見るだけなので適当でも大丈夫です。
![Agent_1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463753/fa11d3af-6f30-9b65-d3cb-1c04be69e227.png)
\
次に、エージェント向けの指示を書いていきます。この指示によってエージェントの振り分け方が決まるのでできるだけ詳しく書きましょう。と言いつつも今回はテスト用なのでざっくりと書いています。  
![Agent_2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463753/4793a531-6129-9c8e-6ffb-b3d070ebb07c.png)
\
振り分け先の一つであるナレッジベースを登録します。どういった時にナレッジベースに振り分けて欲しいかを詳しく書きます。
![Agent_3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463753/14b5712a-aaf9-faf7-d289-1d890d93d108.png)
\
もう一つの振り分け先であるアクショングループを登録します。説明はまた適当で大丈夫です。Action group typeとして`Define with API schemas`を選択します。Lambda関数は既に作成済みのものがあれば`Select an existing Lambda function`から所望のLambda関数を選択します。
![Agent_4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463753/6c7d0145-96f5-5306-adb7-ce1c90a1e215.png)
\
API Schemasを登録しないと動かないので、とりあえず登録します。よく分からなければ添付画像のものを移しても動くと思いますので使ってください。
![Agent_5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463753/b7dcbd0c-4046-718b-9c76-c96d9f0852c9.png)

以上で、エージェントの設定も完了です。  
あとは思うがままにエージェントを試してみてください。設定が間違っていなければ上手く振り分けてくれると思います（ただ、処理時間は結構かかってしまいます。振り分けのためのシステムプロンプト部分がなかなか量が多いようです）

## 最後に

本記事では、Agents for Amazon Bedrockを使った雑談との振り分け方法を解説しました。ここまで書いていてなんですが、記事執筆時はAgentsが利用できない状態でして、実際に動かしながら書けなかったので誤りがあるかも知れません。そこはご勘弁ください。何はともあれマウスポチポチして、指示を入力するだけでエージェントが作れるとは凄いものですね。今後もAWSにはお世話になるでしょうし楽しみです。  
\
[ハンドメイド](https://jp.mercari.com/user/profile/218655300?utm_source=ios&utm_medium=share)、[LINEスタンプ](https://store.line.me/stickershop/product/25451213/ja?utm_source=gnsh_stickerDetail)、[アプリ](https://play.google.com/store/apps/details?id=com.teamdelta.mealmotion)もありますので良かったら見てってください～