2023年12月20日水曜日

Amazon Bedrock Agents APIのリクエストに署名バージョン4の署名を付ける

Oracle APEXのアプリケーションからAWSのREST APIを呼び出すには、リクエストに署名を付加する必要があります。これはAmazon Bedrock Agents APIについても同様です。

AWSからは署名バージョン4のリファレンスとして、以下のページが公開されています。英語ですし内容も難しいので、これを読んで署名処理を実装するのはかなり難しいと思います。

Signing AWS API requestsRequest signature examples
Troubleshoot signed requests for AWS APIs

日本語では、以下の説明がわかりやすかったです。

AWS の API を理解しよう !
中級編 ~ リクエストの署名や CLI/SDK の中身を覗いてみる

いちから署名処理を実装するのは大変なので、Amazon S3にアクセスするために書かれたパッケージより、署名処理の部分を流用することにしました。

plsql-aws-s3

パッケージAWS4_S3_PKGに、Amazon S3を操作するファンクションやプロシージャが実装されています。このパッケージを元に、署名生成に使われているプライベート・ファンクションを残したパッケージAWS4_REST_PKGを作成しました。これらのファンクションでS3に決め打ちになっている部分を、bedrockを呼び出せるように改変しています。

S3を操作するためのファンクションはすべて削除しています。その上で、署名バージョン4を生成し、HTTPのリクエスト・ヘッダーに設定するファンクションset_authorization_headersを新設しています。パッケージAWS4_REST_PKGのパブリックなファンクションはこれだけです。ファンクションset_authorization_headersではREST APIの呼び出しは行わず、apex_web_service.set_request_headersを呼び出して、署名バージョン4による署名を含んだAuthorizationヘッダーおよびその他いくつかの関連したヘッダーの設定だけを行います。

aws4_rest_pkg.set_authorization_headresを呼び出した後に、apex_web_service.make_rest_requestを呼び出すことによって、署名が付いたREST APIを発行します。

パッケージAWS4_REST_PKG本体のコードは記事の末尾に添付します。

パッケージAWS4_REST_PKGをインストールした後に実施した、動作確認の作業を記述します。以下の記事と同じ手順で、AWSのIAMユーザーとしてoracletestuserが作成済みで、アクセスキーシークレットアクセスキーが作成済みとします。

Oracle Database 23c FreeにDBMS_CLOUDパッケージを入れてAmazon S3にアクセスする

AWSコンソールよりBedrockのページを開きます。今回はAgents APIを呼び出すことを想定しています。Agentsが使えるリージョンは限られているようなので、メニューにAgentsが表示されない場合は、リージョンを切り替える必要があります。以下の作業はバージニア北部(us-east-1)で実施しています。

Agentsから使える基盤モデルは、現時点ではAnthropicに限られているようです。


Request model accessをクリックしてみます。

AnthropicClaudeおよびClaude Instantについては、Access statusUse case details requiredとなっています。今回はAgentsから実際に基盤モデルを呼び出すのは(お金もかかるので)やめて、署名バージョン4が正しく生成できていることだけを確認することにします。


Agentsのページを開き、新しくAgentを作成します。Create Agentをクリックします。


Agent nameMyAgentとしました。Agent description - optionalには「My First Bedrock Agent.」と記述しています。それ以外はデフォルトのままです。

今回は署名が付与されたREST APIの認証が通ればよいので、Bedrock Agent自体の設定は最低限にします。BedrockのAgentsの詳細については、他の資料にあたっていただくようお願いします。

Nextをクリックします。


基盤モデルの選択画面に移ります。選択できるモデルはAnthropicのClaude Instant V1またはClaude V2です。2023年12月20日時点では、Claude V2.1はComing Soonです。どちらのモデルを選択しても、Claudeは使用をリクエストしないと呼び出せません。

とりあえずClaude Instant V1を選択し、Instructions for the Agentとして「あなたは日本語を話す親切なエージェントです。丁寧な言葉遣いで回答し差別的な用語は使いません。」と記述して、Nextをクリックします。


Action groupsの追加画面が開きます。OpenAIでのFunction Callingと同等の機能と考えて良いかと思います。OpenAIのFunction Callingとは異なり、AgentはActionとして設定したLambdaファンクションの呼び出しまでを実施するようです。

Action groupsとして何も設定せず、Nextをクリックします。


Knowledge baseの追加画面が開きます。OpenAIでのRetrievalに当たる機能かと思います。Amazon S3に保存してあるドキュメントからベクトル埋め込み(embeddings)を生成しOpenSearchやPineconeに保存して、RAG(Retrieval-Augmented Generation)を実行する機能のようです。

Knowledge baseも何も設定せず、Nextをクリックします。


設定内容を確認し、Create Agentをクリックします。


AgentとしてMyAgentが作成されます。これからポリシーを作成するにあたって、アカウントIDAgent IDを使います。そのため、Agent ARNをコピーしておきます。


Identity and Access Management (IAM)のページのポリシーを開き、ポリシーの作成をクリックします。


ポリシーエディタとしてJSONを選択し、JSONでポリシーを記述します。作成されているAgentを一覧するListAgentsと、Agentを指定して情報を取得するGetAgentの呼び出し、および、Agentを指定してAliasをアップデートするUpdateAgentAliasとAgentに処理を依頼するInvokeAgentを許可します。

[アカウントID]の部分はアカウントIDである12桁の数値に置き換えます。[Agent ID]AgentのIDに置き変えます。Agentとして未デプロイのWorking draftを指定するため、Agent AliasとしてTSTALIASIDを指定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "BedrockConsole",
            "Effect": "Allow",
            "Action": [
                "bedrock:ListAgents",
                "bedrock:GetAgent"
            ],
            "Resource": "*"
        },
        {
            "Sid": "AgentAliasSid",
            "Effect": "Allow",
            "Action": [
                "bedrock:UpdateAgentAlias",
                "bedrock:InvokeAgent"
            ],
            "Resource": [
                "arn:aws:bedrock:us-east-1:[アカウントID]:agent-alias/[Agent ID]/TSTALIASID"
            ]
        }
    ]
}
次へ進みます。


ポリシー名OracleBedrockAgentPolicy_MyAgentと記述します。

ポリシーの作成をクリックすると、Bedrock Agentの呼び出しを許可するポリシーが作成されます。


作成済みのユーザーoracletestuserを開き、許可タブより許可を追加を実行します。


許可を追加の画面でポリシーを直接アタッチするを選択します。アタッチするポリシーとして先ほど作成したポリシーOracleBedrockAgentPolicy_MyAgentを検索し、チェックを入れます。

次へ進みます。


確認画面で許可を追加をクリックします。


Bedrock Agentの作成とアクセスの許可が完了しました。ユーザーoracletestuserのアクセスキーとシークレットアクセスキーは生成済みという前提なので、これでAWS側での準備は完了です。

これからOracle APEXのSQLコマンドからBedrock AgentのREST APIを呼び出してみます。

ListAgentsを呼び出してみます。以下のコードを実行します。


レスポンスとしてagentSummariesが返されました。REST APIに署名が正しく付けられているようです。


GetAgentを呼び出してみます。以下のコードを実行します。



InvokeAgentを呼び出してみます。


dependencyFailedExceptionが返されます。messageは"Access denied when calling Bedrock. Check your request permissions and retry the request."となっています。これはClaude Instance V1へのアクセスをリクエストしていないためだと思われます。

HTTPのステータス・コードは200が返されているため、署名は正しく生成されていると言えます。


印刷されたレスポンスを見ると、一筋縄では行かなそうなフォーマットでレスポンスが返されています。InvokeAgentのリファレンスのResponse SyntaxはJSONになっています。


Amazon Bedrock Agents APIを呼び出すための署名バージョン4の生成について、パッケージの作成とその動作確認については以上になります。

Oracle APEXのアプリケーション作成の参考になれば幸いです。

補足

パッケージDBMS_CLOUDにSEND_REQUESTというファンクション(およびプロシージャ)があります。開発元に確認してはいませんが、credentialScopeがs3に固定されているように見えます。credentialScopeを指定する引数はありませんし、s3以外のサービスを呼び出すとAuthentication Failedが返されます。