LoginSignup
3
1

Agents for Amazon Bedrockを使ってBacklogの課題とWikiを検索する

Last updated at Posted at 2024-02-18

はじめに

前回の記事「Bedrockを使って、S3に置いた独自データに応答してくれるチャットボットを作ってみた。」では、Knowledge Bases for Amazon BedrockとAgents for Amazon Bedrock、Pineconeを使用してS3バケット配置したオブジェクトを対象としたRAGを構築しました。

本記事では、Agents for Amazon BedrockのAction groupsを使用し、自然言語でBacklogの課題やWikiを検索するチャットボットを作成します。

今回は、AgentsがBacklog APIを使用して課題やWikiをキーワード検索し、その結果をもとにAgentsが回答を組み立てます。RAGではないので、キーワードに対して類似度の高いものを検索するようなことはできません。検索の精度や結果はBacklog APIに異存します。そのため、Backlogの検索にAgents for Amazon Bedrockが向いているかはさておき、Action groupsの構築方法や運用の理解を深めることに重点を置きました。

デモ画面

契約について検索してくださいというメンションに対して、契約というキーワードでBacklogの課題とWikiを検索し、その結果をSlackに返しています。Backlogの課題はプロジェクトをまたいで検索できますが、Wikiはプロジェクトキーを指定して検索する必要があります。そのため、チャットボットはプロジェクトキーを問う返信を行います。検索結果には、課題の検索結果が10件とWikiの検索結果が3件表示されています。この画面は、最も期待どおりに動作した例です。毎回、課題とWikiの検索結果が得られるわけではありませんでした。
また、このデモ画面内には福島という名称が含まれていますが、Wikiに記述している名称は別のものです。同様に、鈴木建設鈴木様池田様もWikiに書かれている内容とは異なります。Agentsが回答を作成する際に勝手に情報を書き換えたようです。この点はプロンプトで制御できるのかもしれません。

デモ画面

構成図

構成図

参考情報

環境構築

  • 以下のリソースを作成・削除・変更できる権限をもつAWSユーザーを利用すること
    • AWS IAM
    • AWS Lambda
    • AWS CloudFormation
    • AWS Secrets Manager
    • Amazon API Gateway
    • Amazon S3
    • Amazon CloudWatch Logs
    • Amazon Bedrock
  • 使用するAWSリージョンは、us-east-1
  • Slack Appを作成するためのアカウントや権限を持っている

開発環境構築

作業環境のOSバージョン

Windows 11上のWSLでUbuntu 23.04を動かしています。

$ cat /etc/os-release | grep PRETTY_NAME
PRETTY_NAME="Ubuntu 23.04"

Python環境

$ python3 --version
Python 3.12.0
$ python3 -m venv .venv
source .venv/bin/activate
$ pip3 install --upgrade pip
$ pip3 --version
pip 24 from /home/xxx/.venv/lib/python3.12/site-packages/pip (python 3.12)

AWS環境構築

aws configureコマンドでデフォルトのリージョンやクレデンシャルを設定するか、もしくは~/.aws/configや~/.aws/credentialsを用意します。

AWS SAM CLIインストール

AWS上でサーバーレスアプリケーションを構築、実行するAWS SAMを使用します。

Installing the AWS SAM CLI の手順に従い、AWS SAM CLIをインストールします。今回はx86_64環境でLinux OSを使用するため、x86_64 - command line installerの手順を実行します。

$ sam --version
SAM CLI, version 1.108.0

version 1.104.0 ~ 1.106.0ではビルド時に不必要なWarningメッセージが出力されるため修正パッチが適用された1.107.0以降を使用します。
この件は以下のissueで解決しています。

Slack Appの作成

Slac APIを開き、From scratchからSlack Appを作成します。ここでは、App Nameをaws-sam-bedrock-action-groupとします。

Basic Information画面のApp Credentialsに表示されているSigning SecretはSlackSigningSecretとして次のSecret Managerのシークレット登録に使用します。

App Credentials

OAuth & Permissions画面のOAuth Tokens for Your WorkspaceにあるBot User OAuth Tokenは、SlackBotTokenとして次のSecret Managerのシークレット登録に使用します。

OAuth Tokens for Your Workspace

OAuth & Permissions画面のBot Token Scopesにapp_mentions:readchat:writeを追加します。

Bot Token Scopes

Slackシークレット情報をSecret Managerに登録

あらたにシークレットを作成し、ここまでの手順で作成した以下のシークレット情報を登録します。シークレット名は、Bedrock-sam-secrets-action-groupとします。このシークレット名は後述のtemplate.yaml内のSECRET_NAMEに定義しているため、異なるシークレット名を使用する場合はtemplate.yaml内のSECRET_NAMEも変更します。

シークレットキー
SlackSigningSecret 前項のSlackのSigning Secret
SlackBotToken 前項のSlackのBot User OAuth Token

シークレット作成

アプリケーションの構築

ディレクトリ構造は以下のとおりです。

.
├── README.md
├── assets
│   ├── backlogSearch.json
│   └── backlogSearch.yml
├── backlogSearch
│   ├── __init__.py
│   └── app.py
├── bedrock_action_group_slack_app
│   ├── __init__.py
│   ├── app.py
│   └── requirements.txt
├── samconfig.toml
└── template.yaml

上記のソースコード類はGithubリポジトリにアップロードしています。

assets/backlogSearch.yml, assets/backlogSearch.jsonの構成

assets/backlogSearch.ymlもしくはassets/backlogSearch.jsonは、Backlogの課題やWikiを検索するためのOpenAPIスキーマです。これらを任意のS3バケットに配置します。後述のAction groupsの設定で使用します。
OpenAPIスキーマは、Backlog API とはで公開されているAPI仕様をもとに作成しました。ほぼ、GitHub Copilotが生成してくれたものを使用しています。

__init__.pyは空のファイルです。
bedrock_action_group_slack_app/requirements.txtは以下のとおりです。boto3やrequestsも必要ですが、それらはLambdaレイヤーで追加するようtemplate.yamlに記述します。

slack-bolt
slack-sdk

template.yamlの構成

AWS SAM テンプレートファイル(template.yaml)に、作成するAWSリソースを定義します。
ここでは、ふたつのLambda関数を作成します。ひとつはSlack Event Subscriptionsを受け取り、もうひとつはBacklogの課題やWikiを検索するための関数です。それぞれ、Lambda関数用ロールやポリシー、Lambdaの環境変数などを記述します。その他に、以下のレイヤーやリソースベースポリシーが含まれます。

  • Lambda関数からSecrets ManagerにアクセスするためのAWS-Parameters-and-Secrets-Lambda-Extensionレイヤー
  • Lambda関数内からimportするためのboto3やrequestsをパッケージにしたレイヤー
  • BedrockkからLambda関数を扱うためのリソースベースポリシー

AWS-Parameters-and-Secrets-Lambda-ExtensionレイヤーのARNはUsing Parameter Store parameters in AWS Lambda functionsのドキュメントにリージョンやアーキテクチャ毎に掲載されています。
boto3やrequestsのレイヤーは、keithrozario/KlayersのリポジトリにあるList of ARNsに、Pythonバージョンとアーキテクチャ毎に掲載されています。今回は、Python 3.12, arm64を使用するので、Layers for Python 3.12-arm64の一覧からus-east-1用のARNを使用します。

Lambdaレイヤーは以下のようにtemplate.yamlに記述しています。

      Layers:
        # Layer for AWS Parameter Store and Secrets Manager
        - arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:11
        # Layer for requests and boto3
        - arn:aws:lambda:us-east-1:770693421928:layer:Klayers-p312-arm64-requests:1
        - arn:aws:lambda:us-east-1:770693421928:layer:Klayers-p312-arm64-boto3:1

適用すると、Lambda関数のLayersに以下のように表示されます。

Lambdaレイヤー

リソースベースポリシーは、以下のようにtemplate.yamlに記述しています。

  BacklogSearchFunction:
    Type: AWS::Serverless::Function
    Properties:

(途中省略)

  # Resouse based policy for lambda.
  PermissionForBacklogSearchToInvokeLambda:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !GetAtt BacklogSearchFunction.Arn
      Action: lambda:InvokeFunction
      Principal: bedrock.amazonaws.com

適用すると、Lambda関数の設定のResource-based policy statementsに以下のように表示されます。

リソースベースのポリシー

template.yaml内のEnvironmentにあるSECRET_NAMEREGION_NAMEには、それぞれ先ほど作成したSecrets Managerのシークレットの名前とリージョンを設定します。

Lambda関数の実行ロール内のポリシーではResource: "*"としていますが、本番環境などでは許可するリソースを特定したほうがよいでしょう。例えば、AgentsのResourceを特定する場合は以下のように指定します。

Resource: "arn:aws:bedrock:{Region}:{AWS Account ID}:agent-alias/{Agents ID}/{Agents Alias}"

samconfig.tomlの構成

SAM CLIの実行設定ファイル(samconfig.toml)に、SAM CLIを実行する際の設定を定義します。AWS SAMのチュートリアル: Hello World アプリケーションのデプロイを実行した際に作成されるsamconfig.tomlをもとにしています。今回の例では、以下の点を変更しています。

  • [default.global.parameters]セクションのstack_nameを"sam-app"から"bedrock-slack-rag-appt"に変更
  • [default.deploy.parameters]セクションにregion指定を追加
  • [default.deploy.parameters]セクションのcapabilitiesを"CAPABILITY_IAM"から"CAPABILITY_NAMED_IAM"に変更

bedrock_action_group_slack_app/app.pyの構成

bedrock_action_group_slack_app/app.pyは、Slack Event Subscriptionsを受け取り、Slackのメンションイベントに応答するための関数です。boto3クライアントを使用してAgentsのinvoke_agentメソッドを呼び出し、Agentsにメッセージを送信します。そして、レスポンスをSlackに返します。

    client = boto3.client(
        service_name='bedrock-agent-runtime',
        region_name="us-east-1",
        config=Config(
            read_timeout=180,
        )
    )

    response = client.invoke_agent(
        inputText=prompt,
        agentId=agent_id,
        agentAliasId=agent_alias_id,
        sessionId=session_id,
        enableTrace=enable_trace,
    )

backlogSearch/app.pyの構成

backlogSearch/app.pyは、Agentsからイベントデータを受け取り、Backlogの課題やWikiを検索するための関数です。
event["apiPath"]が'/issues'の場合は課題を検索し、'/wikis'の場合はWikiを検索します。このapiPathは、AgentsのAction groupsの設定で読み込むOpenAPIスキーマのpathsに記述されています。それぞれの関数の結果をAgentsの形式に合わせて返します。

    if api_path == "/issues":
        body = issue_search(parameters)

    elif api_path == "/wikis":
        body = wiki_search(parameters)

    response_body = {"application/json": {"body": json.dumps(body)}}

    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

課題検索を行うissue_search関数では、レスポンスボディの中から課題キー、課題の件名、課題の状態、担当者、期限日を返します。全ての情報を返そうとすると検索結果の件数や課題本文のサイズなどでLambda response exceeds maximum size 25KBのエラーが発生するため返す情報を絞っています。

Wiki検索を行うWiki_serach関数では、レスポンスボディの中からWiki名と本文の先頭100文字を返します。これも同様にエラーを回避するために情報を絞っています。

ビルド

template.yamlがあるディレクトリで、ビルドコマンドを実行します。

sam build

ビルドに成功すると、以下のようなメッセージが表示されます。

Starting Build use cache
Building codeuri: /home/xxx/aws-sam-bedrock-action-group-slack-app/backlogSearch runtime: python3.12
metadata: {} architecture: arm64 functions: BacklogSearchFunction
Manifest is not changed for (BedrockAssitantFunction), running incremental build
Building codeuri: /home/xxx/aws-sam-bedrock-action-group-slack-app/bedrock_action_group_slack_app
runtime: python3.12 metadata: {} architecture: arm64 functions: BedrockAssitantFunction
requirements.txt file not found. Continuing the build without dependencies.
 Running PythonPipBuilder:CopySource
 Running PythonPipBuilder:CopySource
 Running PythonPipBuilder:CopySource

Build Succeeded

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

Commands you can use next
=========================
[*] Validate SAM template: sam validate
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {{stack-name}} --watch
[*] Deploy: sam deploy --guided

デプロイ

ビルドでエラーがなければsam deployコマンドを実行し、デプロイを行います。

sam deploy

デプロイが成功すると、CloudFormationがチェンジセットを実行する様子とともに以下のような情報がコンソールに出力されます。

CloudFormation outputs from deployed stack
----------------------------------------------------------------------------------------------------------------------------------
Outputs
----------------------------------------------------------------------------------------------------------------------------------
Key                 BacklogSearchFunction
Description         Backlog Search Lambda Function ARN
Value               arn:aws:lambda:us-east-1:xxxxxxxxxxxx:function:bedrock-action-group-slack-a-BacklogSearchFunction-xxxxxxxxxxxx

Key                 BedrockAssitantApi
Description         The URL of Slack Event Subscriptions
Value               https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/Prod/slack/events

Key                 BedrockAssitantFunction
Description         Bedrock Assistant Lambda Function ARN
Value               arn:aws:lambda:us-east-1:xxxxxxxxxxxx:function:bedrock-action-group-slack-BedrockAssitantFunction-xxxxxxxxxxxx

Key                 BedrockAssitantFunctionIamRole
Description         Implicit IAM Role created for Bedrock Assistant function
Value               arn:aws:iam::xxxxxxxxxxxx:role/bedrock-action-group-slack-app-lambda-role
----------------------------------------------------------------------------------------------------------------------------------

Slack Appの設定

メンションイベントに応答するために、Event Subscriptions画面のSubscribe to bot eventsにapp_mentionを追加します。

Event Subscriptions

Event Subscriptions画面のEnable EventsをOnにし、Request URLにデプロイ時に出力されたURL https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/Prod/slack/events を入力します。
Verified ✓ と表示されれば、正しいURLが入力されています。レスポンスが得られるようになるまで時間がかかる場合があります。正しいURLを入力しているにもかかわらずVerifiedとならない場合は、時間をおいて再試行します。

Enable_events.png

設定を追加後、画面最下部にあるSave Changesをクリックし内容を保存します。

Slack Workspaseにアプリをインストール

Install App画面のInstall to Workspaceをクリックし、Slack AppをWorkspaceにインストールします。
インストールに成功すると、Thank you!画面が表示されます。Slackアプリをインストールしている場合はclick hereのリンク、Webブラウザを使用している場合は、this linkをクリックしてSlackを開きます。

Bedrock環境構築

Agentsの設定

Agentsを開き、Agentを作成します。

入力/選択項目 内容
Agent name 任意のAgents名
Agent description Agentsの説明文
User Input Yes
IAM Permissins 新規にロールを作成する場合は、Create and use a new service role。既存のロールを利用する場合は Use an existing service role
Idle session timeout 30 Minutes

Agent作成

"User Input" は、Agentsが回答するための十分な情報がない場合に、ユーザーに追加の情報を求めることができるかを選択します。Yes,Noのどちらを選択しても良いのですが、Yesのほうが会話らしくなると思います。
"Idle session timeout"は、入力が何もない状態でセッションを維持する時間。セッションが有効な間であれば、以前の会話履歴を引き継いで会話を続けることができます。

Agentsが使用する言語モデルを選択します。記事執筆時点では、Anthropic社の"Claude instant V1","Claude instant V2", "Claude instant V2.1"のみが選択可能です。

Agentsの言語モデルを選択

Instructions for the Agentには、エージェントが実行するタスクについて明確かつ具体的な指示を入力します。

ここでのポイントは、Agentsがタスクを実行する順番や実行するLambda関数の理解を深めるために具体的な指示を与えることです。例えば、 Agentsは実行するLambda関数に個々のクエリパラメータを処理する実装を見つけられない場合に"依頼内容を実現する実装がない"と判断し処理を中断することがありました。そのため、 それを防ぐ指示を含めます。また、依頼内容に対してOpenAPIスキーマのどのパスを使用するかを指示することで、Agentsが適切な処理を行う助けになるようです。ただし、この指示は40~1,200文字以内という制限があります。

上記のポイントや指示を踏まえて、以下のような指示を入力します。
指示内にあるGET::backlogSearch::getIssueListやGET::backlogSearch::getWikiListのbacklogSearchは、Action groupsの設定名です。getIssueListgetWikiListは、OpenAPIスキーマのpathsに記述されているoperationIdです。

上記のポイントや以下の指示は、Agentsの反応を試す中で経験的に得たものです。おおよそ期待した結果が得られたので、おそらく考え方は合っていると思います。

あなたはBacklogの課題やWikiを検索するするプロフェッショナルです。
以下の手順でデータを検索してください。一度にすべてを行ってはいけません。user::askuser を通じて1つずつ実行してください。

1. 私の依頼内容を正しく理解してください。例えば、私が"点検に関する課題を10件探し、件名の昇順で一覧にしてください。"と依頼した場合、検索キーワード=点検, 課題を取得する件数=10, 並び替えに使用する属性=件名, 並び順=昇順 のように依頼内容を適切に分解してください。
2. あなたは依頼内容に基づいてfunctionを実行します。functionのコードを参照してfunctionが依頼内容を処理可能か否かを推論する場合、コードの内のコメントも参照しコードの仕様を理解する必要があります。例えば、コード内に個々のクエリパラメータを処理する実装がない場合でも短絡的に"依頼内容を実現する実装がない"と判断してはいけません。クエリパラメータを辞書形式のリストで受け取って値を処理している可能性があります。functionがクエリパラメータをどのように処理しているか仕様がコメントに書かれているので、コメントも参照しfunctionの仕様を理解してください。
3. 与えられたAPIスキーマを正しく理解してください。そのうえで、分解した依頼内容をAPIスキーマをもとにパラメータに当てはめます。例えば、「1. 私の依頼内容の理解」で与えられた依頼内容の例の場合は、GET::backlogSearch::getIssueListに対してはkeyword=点検, count=10, sort=件名(summary), order=asc のようにパラメータに値を当てはめます。GET::backlogSearch::getWikiListに対しては、keyword=点検を当てはめます。
4. 私の依頼に対して、はじめに GET::backlogSearch::getIssueListを実行し続けてGET::backlogSearch::getWikiList実行します。それぞれの結果を提示してください。GET::backlogSearch::getIssueListの結果は、`課題キー`, `課題名`, `課題のステータス`, `担当者`, `期日`のみ提示してください。課題の期日が未設定の場合は、'なし'と回答します。GET::backlogSearch::getWikiListの結果は、Wiki名とWikiの内容を提示してください。

出力例:

    ```
検索結果
{課題キー}, {課題名}, {課題のステータス}, {担当者}. {期日}

Wikiの検索結果
{Wiki名}, {Wikiの内容}
    ```

続いて、Action groupsの設定を行います。ここで先ほどデプロイしたLambda関数や、OpenAPIスキーマを設定します。
assets/backlogSearch.jsonもしくはassets/backlogSearch.yamlを任意のS3バケットにアップロードし、そのオブジェクトパスをS3 Urlに設定します。

入力/選択項目 内容
Action group name 任意のAction groups名。先ほどの指示内容に合わせてbacklogSearchとします。
Description Action groupsの説明文
Select Lambda function 先ほどデプロイしたLambda関数のうち、名前にBacklogSearchFunctionが含まれる関数を選択。
S3 Url S3バケット内にあるbacklogSearch.yamlかbacklogSearch.jsonのオブジェクトパス

Action groupsの設定

今回はknowledge baseは使用しないので、何も入力せず次に進みます。

knowledge baseの設定はスキップ

Agentsの設定が完了すると、概要がこのように表示されます。APIからAgentsを呼び出す際にIDを使用します。 AgentsのIDは後述のSecret Managerのシークレット登録に使用します。
右上のEditからAgentsの設定を変更することができます。

Agentsの設定概要

Agents エイリアスの作成

AgentsをAPIから呼び出す際は、Agents本体ではなくエイリアスを使用します。そこで、Agentsに対するエイリアスを作成します。
右上のCreateから新規作成画面に進みます。

Agents エイリアスの作

エイリアスの情報を入力します。

入力/選択項目 内容
Alias name 任意のエイリアス名
Description エイリアスの説明文
Create a new version and associate it to this alias. / Use an existing version to associate this alias. エイリアスを新しいバージョンと既存バージョンのどちらに紐付けるか

エイリアスの情報

エイリアスを作成すると、バージョンとともに以下のようにリストが表示されます。APIからAgentsを呼び出す際にAlias IDを使用します。 Alias IDは後述のSecret Managerのシークレット登録に使用します。

エイリアス一覧

Agentsの設定変更はのWorking draftの項目から行えます。なかでもAdvanced promptsでは、言語モデルに対して前処理や後処理の詳細な指示テンプレートを上書き/拡張できます。
設定を変更した際はplaygroundで動作確認が行ったあと、エイリアスを作成します。

Agentsのドラフト

Working draft内にあるAdvanced promptsの項目で、Editをクリック。
Advanced promptsg

プロンプトや、Temperature、出力の長さなどがカスタマイズできます。
Advanced promptsの設定 g

Agentsのシークレット情報をSecret Managerに登録

AgentsのIDとAlias IDをSecret Managerに登録します。登録先のシークレットは、SlackのSlackSigningSecretやSlackBotTokenを登録したものです。
あわせて、BacklogのAPIキーと自身のBacklogのURLを登録します。BacklogのURLは、https://[スペースID].backlog.com/ もしくはhttps://[スペースID].backlog.jp/ です。

Secret Manager

動作確認

任意のチャンネンルに、@aws-sam-bedrock-action-group (Slack Appの作成時に設定した名前)を招待し、メンション形式で依頼をポストします。動作しない場合のログやOpenAI APIが返すレスポンスは CloudWatch Logs に出力されているログが参考になります。

作成したリソースの削除

最後に、作成したアプリケーションを削除する手順です。リソースを削除するには sam delete コマンドを実行します。

sam delete

まとめ

Agents for Amazon BedrockとAction groupsを使用することで、SlackアプリとBacklogのAPIを組み合わせて自然言語での問い合わせに対してBacklog課題やWikiを検索することができました。Backlog公式のOpenAPIスキーマがないため自分で作成する必要がありましたが、その作成もGitHub Copilotの助けを借りてスムーズに進めることができました。

このアプリケーションは、RAGと異なり検索の精度や結果はBacklog APIに異存するため、検索キーワードと類似性が高い課題やWikiを抽出するといったことができません。Knowledge Bases for Amazon Bedrockで構築したRAGと組み合わせ、相互の結果をもとにAgentsに回答を求めることで、より高度な問い合わせに対応することができるかもしれません。

前回の記事に引き続きAWS SAMを使用してアプリケーションを構築しましたが、今回はLambdaレイヤーやリソースベースポリシーを使用することで、Lambda関数の設定をより細かく行う設定を知ることができました。

3
1
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
3
1