AWS Chalice を使って、Amazon Bedrock Slack Appを作成してみた

2023.09.29

AWS事業本部の梶原@福岡オフィスです。

先日作成したSlack Appに対して、Amazon Bedrockの検証の為に、応答部分を変更してAmazon Bedrock Slack Appを作成してみます。

ということで、以前作成したSlack Appをベースに

Amazon BedrockのAPIを呼び出して、回答を作成し、返信する Slack Appを作成してみます

はじめに

以下の技術、サービスを使っています。詳しくは参考情報や、リンクなどをご参照ください

前提条件

  • AWS アカウントまた以下サービスへの権限が必要です
    • Amazon Bedrock
    • AWS IAM
    • AWS Lambda
    • Amazon API Gateway
    • Amazon S3
  • Slack
    • アプリケーションがインストール可能なこと

事前準備

Amazon Bedrock

AWS コンソールにて、Amazon Bedrock の使用可能なモデルの確認を行って下さい。必要応じてBedrockで使用するモデルへのアクセスをリクエストしてください。

今回は、AL21 Labs の Jurassic-2 Mid を使用しますので、該当の項目が[Access granted]になっていることを確認してください

Amazon Bedrock > Model access リージョン:us-east-1

https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/modelaccess

AWS 環境設定

Chaliceでデプロイをおこなうので、事前にCredential等を設定してください

Bedrock の使用可能なリージョン us-east-1 を指定します

$ aws configure
AWS Access Key ID [None]: xxxxx
AWS Secret Access Key [None]: xxxxx
Default region name [ap-northeast-1]: us-east-1
Default output format [None]:

Pythonの環境設定

Python 3.10 の環境設定をします。

以降の処理はPython3.10 のvenv環境での実行を想定しています

$ python3.10 -m venv .venv310
$ source .venv310/bin/activate
$ python --version
Python 3.10.12
$ pip --version
pip 22.0.2 from .venv310/lib/python3.10/site-packages/pip (python 3.10)

各種pipパッケージのインストール

Slack, Chalice, Boto3, のパッケージをインストールしておきます。

※ Boto3 SDK はAmazon Bedrock の対応が含まれる 1.28.57 以上を指定してください

requirements.txt

slack_bolt
chalice
boto3 >= 1.28.57

尚、requirements.txt に記載したファイルはAWS Lambdaにデプロイされる際にLambda Layerに一緒にパッケージングされます。便利!

$ pip install -r requirements.txt

Chalice、Slackについて

このアプリケーションの元となる、Chalice, Slackの部分はこちらのエントリーでご案内していますのでご参考ください。

やってみた

Slack Bolt for Pythonのclone

実際は、Chalice の部分だけで良いのですが、まとめて取得します。

$ git clone https://github.com/slackapi/bolt-python.git

Chalice

Slack Bolt for Python にChaliceのサンプルがあるので流用します。

$ cd bolt-python/examples/aws_chalice/

メンションの応答の実装部分に、AWS Bedrock APIの処理を追加して、メンションされた内容に対して、AWS Titan モデルで回答を作成して返すようにしてみます

なお、Amazon Bedrockのコードは公開されているAWS サンプルのBedrock のワークショップのコードや、API リファレンスを参考にしています。

環境変数設定

.chalice フォルダにある Chalice(AWS Lambda)の環境変数を設定します。

Bedrockの呼び出しの権限などは、以下で設定するLambdaのロールに対して行いますので、特にここでAPIキーなどの設定は必要ありません。

現在はLambdaに含まれているboto3のバージョンが古いため、automatic_layer でboto3を含んだレイヤーを自動作成してLambaで使用します。

config.json

{
  "version": "2.0",
  "app_name": "bolt-chalice-bedrock",
  "stages": {
    "dev": {
      "api_gateway_stage": "api",
      "environment_variables": {
        "SLACK_BOT_TOKEN": "xoxb-xxxxx",
        "SLACK_SIGNING_SECRET": "xxxxxx"
      },
      "autogen_policy": false,
      "automatic_layer": true
    }
  }
}

Amazon Bedrock を呼び出す際に必要なポリシーをpolicy-dev.jsonに設定します。

以下で、bedrockの呼び出しをすべて許可状態にしています。必要に応じて、権限を絞る等の対応を実施してください

    {
        "Effect": "Allow",
        "Action": [
            "bedrock:*"
        ],
        "Resource": "*"
    }

policy-dev.json

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "lambda:InvokeFunction"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "bedrock:*"
            ],
            "Resource": "*"
        }
    ]
}

実装部分

既存の処理はSlackアプリに対して、メンションされた場合(”app_mention”)に、say()でメッセージを返していますので、この部分に変更を行います

元のコード

@bolt_app.event("app_mention")
def handle_app_mentions(body, say, logger):
    logger.info(body)
    say("What's up? I'm a Chalice app :wave:")

Bedrockを使用してメンションの内容から返信を作成するコードに置き換えます

  1. メンションでAppが受け取ったメッセージからメンション部分を削除
  2. Bedrock で AL21 Labs の Jurassic-2 Mid モデルを使用して応答を生成
  3. スレッドに返信する
<br />import boto3
import botocore
logging.info(f"boto3={boto3.__version__}, botocore={botocore.__version__}")


@bolt_app.event("app_mention")
def handle_app_mentions(body, say, logger):
    logger.info(body)

    event = body["event"]
    channel = event["channel"]
    ts = event["ts"]

    # Slackでメンションを受け取ったらメッセージからメンションを取り除く
    mention_text = re.sub(r'<@.*?> ', "", event["text"])

    # 応答を生成
     # Bedrock Clientの作成
    bedrock_client = boto3.client('bedrock-runtime')

    titanInputText = f"{mention_text}\n"

    bedrock_body = {
        "prompt": titanInputText,
        "maxTokens": 200,
        "temperature": 0.7,
        "topP": 1,
    }

    body_bytes = json.dumps(bedrock_body).encode('utf-8')

    response = bedrock_client.invoke_model(
                    accept="*/*",
                    body=body_bytes,
                    contentType="application/json",
                    modelId="ai21.j2-mid-v1",
                )

    resp_body = response["body"].read()
    resp_body_json = json.loads(resp_body.decode('utf-8'))
    logging.info(resp_body_json["completions"][0]["data"]["text"])

    text_prompts = resp_body_json["completions"][0]["data"]["text"]

    # スレッドに返信
    say(f"{text_prompts}", thread_ts = ts)

デプロイ

新しいBoto3を含んだLambdaのLayerも自動で作成して、更新デプロイしてくれるのでとても助かります。

$ chalice deploy
...
Creating Rest API
Resources deployed:
  - Lambda Layer ARN: arn:aws:lambda:us-east-1:123456789012:layer:bolt-chalice-bedrock-dev-managed-layer:1
  - Lambda ARN: arn:aws:lambda:us-east-1:123456789012:function:bolt-chalice-bedrock-dev
  - Rest API URL: https://hoge.execute-api.ap-northeast-1.amazonaws.com/api/

動作確認

インストールが正常にいけば、任意の部屋に追加したSlack Appを追加して、メンションしてください。

以下のようにBedrock API からの答えが生成されており、スレッドに返信されていれば成功です

リソース削除

以下コマンドでAWS上のリソースはきれいに削除できます

$ chalice delete

まとめ

以前作ったSlack App を流用して、さくっとBedrock API 使ってSlack App を作成してみました。 Bedrock ではほぼ同じ、APIのインターフェースで様々なモデルがよべるようになるので、いろいろなバリエーションができるかと思います。

プロンプト検証は、Jypter Notebook(SageMaker)などで、行うことが多いと思いますが、デモや共有して検証して貰う際などに流用できるかと思います。

参考情報

Chalice

https://github.com/aws/chalice