[プレビュー] Amazon Bedrock のモデル呼び出しのログ記録設定を試してみた

2023.10.02

Amazon Bedrock にはプレビュー中ですが、モデル呼び出しのログを記録する設定があります。モデルの呼び出し API のリクエストと応答を収集でき、出力先には S3 と CloudWatch Logs を指定できます。今回は、S3 と CloudWatch Logs の両方に出力する設定を試してみました。

ログを記録する Model invocation logging 機能は現在プレビューです。リリース時には機能が変更される可能性があります。

Amazon Bedrock のログ記録設定

Bedrock のログ記録は「Settings」メニューから設定できます。プレビュー中である旨の注意文が表示されています。

ログ記録設定は次のユーザーガイドに詳細の記載があります。アカウントで実行されたすべてのInvokeModelまたはInvokeModelWithResponseStreamのリクエストと応答を記録できます。

Settings - Amazon Bedrock


ログの出力先には S3 と CloudWatch Logs を指定できます。今回は両方設定してみます。

次の流れで設定します。

  • 事前作業
    • Amazon S3 バケット作成、バケットポリシーを設定
    • Amazon CloudWatch Logs のロググループを作成
  • Amazon Bedrock の設定

なお、以降の内容は全てのリソースを「バージニア北部リージョン」で作成しています


事前作業 - Amazon S3

ログを格納する S3 バケットを作成します。テスト目的のためリージョンの指定以外はデフォルト設定で作成しています。

次に、バケットポリシーを作成します。

バケットポリシーの例はユーザーガイドで紹介されているため、変数部分とオプション部分を変更して設定します。

Settings - Amazon Bedrock


バケットを選択して「アクセス許可」→「バケットポリシー」から次のポリシーを設定します。アカウント ID は例示の値に変更しています。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "bedrock.amazonaws.com"
      },
      "Action": [
        "s3:PutObject"
      ],
      "Resource": [
        "arn:aws:s3:::bedrock-log-20231002/AWSLogs/111122223333/BedrockModelInvocationLogs/*"
      ],
      "Condition": {
        "StringEquals": {
          "aws:SourceAccount": "111122223333"
        },
        "ArnLike": {
           "aws:SourceArn": "arn:aws:bedrock:us-east-1:111122223333:*"
        }
      }
    }
  ]
}

任意の設定となりますが、ログの保管期間を 1 年とするためにライフサイクルルールを設定します。

バケットを選択して「管理」→「ライフサイクルルール」から設定します。365 日後に現行バージョンではなくなり、非現行バージョンを 1 日後に削除するルールとしています。

以上で Amazon S3 の事前作業は完了です。

もし、SSE-KMS で暗号化する場合は、KSM キーのキーポリシーも変更が必要となります。キーポリシーの例はユーザーガイドに記載されています。

Settings - Amazon Bedrock


事前作業 - Amazon CloudWatch Logs

CloudWatch Logs において、事前に Bedrock のログを格納するロググループを作成します。

今回は次の設定で作成します。ログ保管期間は 365 日としており、KMS キーによる暗号化は設定していません。

Bedrock から CloudWatch Logs にログを転送するための IAM ロールも必要となりますが、Bedrock でログ記録を設定する際に一緒に作成することもできるため、今回は IAM ロールを事前に作成せずに進めます。

もし、事前に IAM ロールを作成する場合は次のポリシーを割り当てます。下記の例は Bedrock が自動生成するポリシーと同様の内容を記載しています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AmazonBedrockModelInvocationCWDeliveryRole",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:us-east-1:111122223333:log-group:bedrock-log:log-stream:aws/bedrock/modelinvocations"
        }
    ]
}

IAM ロールの信頼ポリシーは次の通りです。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "bedrock.amazonaws.com"
            },
            "Action": "sts:AssumeRole",
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": "111122223333"
                },
                "ArnLike": {
                    "aws:SourceArn": "arn:aws:bedrock:us-east-1:111122223333:*"
                }
            }
        }
    ]
}

以上で Amazon CloudWatch Logs の事前設定は終わります


Amazon Bedrock 設定

ログ記録は「Settings」メニューから設定します。

ログ記録はデータタイプ(Text, Image, Embedding)毎に設定できます。今回は全てのタイプを選択しています。

ログの出力先は事前準備した通り、S3 と CloudWatch Logs 両方を指定して設定します。

CloudWatch Logs への出力設定ではロググループへの書き込みを許可する IAM ロールを新規に作成する設定にしています。また、注意書きもあるオプション設定として、100 KB を超えるデータは CloudWatch Logs に出力されないことから、それらのデータの出力用 S3 バケット指定があります。この S3 バケットは上段の通常ログのバケットを分けたほうがよいかは現時点では分からなかったため、今回は同じバケットを指定することにしました。

以上で Amazon Bedrock のモデル呼び出しログの記録設定は終わりです。

Amazon Bedrock のログ確認

始めに、適当にチャットを試してログを確認してみたいと思います。

CloudWatch Logs のロググループを確認したところ、期待通りモデル呼び出しのログが記録されていました。プロンプトの内容を確認することもできます。

{
    "schemaType": "ModelInvocationLog",
    "schemaVersion": "1.0",
    "timestamp": "2023-10-01T15:29:33Z",
    "accountId": "111122223333",
    "region": "us-east-1",
    "requestId": "bbef99a2-5af9-4e5c-b8b8-c5593a385818",
    "operation": "InvokeModel",
    "modelId": "ai21.j2-mid-v1",
    "input": {
        "inputContentType": "application/json",
        "inputBodyJson": {
            "prompt": "\nHow are you?",
            "maxTokens": 200,
            "temperature": 0.7,
            "topP": 1,
            "stopSequences": [],
            "countPenalty": {
                "scale": 0
            },
            "presencePenalty": {
                "scale": 0
            },
            "frequencyPenalty": {
                "scale": 0
            }
        },
        "inputTokenCount": 3
    },
    "output": {
        "outputContentType": "application/json",
        "outputBodyJson": {
            "id": 1234,
            "prompt": {
                "text": "\nHow are you?",
                "tokens": [
                    {
                        "generatedToken": {
                            "token": "<|newline|>",
                            "logprob": -3.060060977935791,
                            "raw_logprob": -3.060060977935791
                        },
                        "textRange": {
                            "start": 0,
                            "end": 1
                        }
                    },
                    {
                        "generatedToken": {
                            "token": "▁How▁are▁you",
                            "logprob": -12.454113006591797,
                            "raw_logprob": -12.454113006591797
                        },
                        "textRange": {
                            "start": 1,
                            "end": 12
                        }
                    },
                    {
                        "generatedToken": {
                            "token": "?",
                            "logprob": -1.7818526029586792,
                            "raw_logprob": -1.7818526029586792
                        },
                        "textRange": {
                            "start": 12,
                            "end": 13
                        }
                    }
                ]
            },
            "completions": [
                {
                    "data": {
                        "text": "\nI'm good, how are you?",
                        "tokens": [
                            {
                                "generatedToken": {
                                    "token": "<|newline|>",
                                    "logprob": -1.124518632888794,
                                    "raw_logprob": -1.1202852725982666
                                },
                                "textRange": {
                                    "start": 0,
                                    "end": 1
                                }
                            },
                            {
                                "generatedToken": {
                                    "token": "▁I'm",
                                    "logprob": -2.805628776550293,
                                    "raw_logprob": -2.3979036808013916
                                },
                                "textRange": {
                                    "start": 1,
                                    "end": 4
                                }
                            },
                            {
                                "generatedToken": {
                                    "token": "▁good",
                                    "logprob": -0.5043708682060242,
                                    "raw_logprob": -0.5925372838973999
                                },
                                "textRange": {
                                    "start": 4,
                                    "end": 9
                                }
                            },
                            {
                                "generatedToken": {
                                    "token": ",",
                                    "logprob": -0.0672428235411644,
                                    "raw_logprob": -0.1584426611661911
                                },
                                "textRange": {
                                    "start": 9,
                                    "end": 10
                                }
                            },
                            {
                                "generatedToken": {
                                    "token": "▁how▁are▁you",
                                    "logprob": -4.9182281494140625,
                                    "raw_logprob": -3.6858272552490234
                                },
                                "textRange": {
                                    "start": 10,
                                    "end": 22
                                }
                            },
                            {
                                "generatedToken": {
                                    "token": "?",
                                    "logprob": -0.000011444026313256472,
                                    "raw_logprob": -0.0004674295778386295
                                },
                                "textRange": {
                                    "start": 22,
                                    "end": 23
                                }
                            },
                            {
                                "generatedToken": {
                                    "token": "<|endoftext|>",
                                    "logprob": -0.0031190102454274893,
                                    "raw_logprob": -0.026162028312683105
                                },
                                "textRange": {
                                    "start": 23,
                                    "end": 23
                                }
                            }
                        ]
                    },
                    "finishReason": {
                        "reason": "endoftext"
                    }
                }
            ]
        },
        "outputTokenCount": 7
    }
}

次に、画像生成も試してみます。

こちらも期待通り CloudWatch Logs に出力されました。出力画像のデータは S3 バケットに保管されており、CloudWatch Logs にはそのパスが記載されていました。

{
    "schemaType": "ModelInvocationLog",
    "schemaVersion": "1.0",
    "timestamp": "2023-10-01T15:40:22Z",
    "accountId": "111122223333",
    "region": "us-east-1",
    "requestId": "c1a78c43-70d5-4b0c-b200-9a01cdbb8059",
    "operation": "InvokeModel",
    "modelId": "stability.stable-diffusion-xl-v0",
    "input": {
        "inputContentType": "application/json",
        "inputBodyJson": {
            "text_prompts": [
                {
                    "text": "tree"
                }
            ],
            "cfg_scale": 10,
            "seed": 0,
            "steps": 50
        },
        "inputTokenCount": 0
    },
    "output": {
        "outputContentType": "application/json",
        "outputBodyS3Path": "s3://bedrock-log-20231002/AWSLogs/111122223333/BedrockModelInvocationLogs/us-east-1/2023/10/01/15/data/111122223333_BedrockModelInvocationLogs_us-east-1_20231001T154057075Z_c1a78c43-70d5-4b0c-b200-9a01cdbb8059_output.json.gz",
        "outputTokenCount": 0,
        "outputImageWidth": 512,
        "outputImageHeight": 512
    }
}

以上で Amazon Bedrock のログ確認は終わりです。

さいごに

まだプレビュー中ですが、Amazon Bedrock においてモデルの呼び出し API のログを記録する設定を試してみました。生成 AI がどのように利用されたかをログから確認したいこともあると思われるため、是非設定しておきたい内容と思いました。今回は同じリージョンの S3 バケットに出力しましたが、他のリージョンのバケット出力できるか等、気になる点はまだあります。

以上、このブログがどなたかのご参考になれば幸いです。