[アップデート] Amazon Bedrockで、最初のトークンを受信するまでの時間と1分あたりのクォータ消費量をAmazon CloudWatchメトリクスとして取得できるようになりました

[アップデート] Amazon Bedrockで、最初のトークンを受信するまでの時間と1分あたりのクォータ消費量をAmazon CloudWatchメトリクスとして取得できるようになりました

Amazon BedrockのAmazon CloudWatch(以下、CloudWatch)メトリクスとして、リクエストを送信してから最初のトークンを受信するまでの時間であるTimeToFirstTokenと、1分あたりのクォータ消費量であるEstimatedTPMQuotaUsageが、新しく追加されました。
2026.03.11

はじめに

おのやんです。

今回のAWSアップデートにより、Amazon Bedrock(以下、Bedrock)のAmazon CloudWatch(以下、CloudWatch)メトリクスが2つ追加されました。

https://aws.amazon.com/jp/about-aws/whats-new/2026/03/amazon-bedrock-observability-ttft-quota/

追加されたのはTimeToFirstTokenEstimatedTPMQuotaUsageの2つです。

TimeToFirstTokenは、リクエストを送信してから最初のトークンを受信するまでの時間(TTFT: Time To First Token)です。特にAIチャットのようなアプリを監視するときに、回答が始まるまでの待ち時間を監視したいようなケースでは、こちらのメトリクスを使います。

EstimatedTPMQuotaUsageは、1分あたりのトークン(TPM: Tokens Per Minute)から算出されるクォータ消費量です。トークン消費数ではありません。

Bedrockには以前からInputTokenCountOutputTokenCountなどのトークン数を表すメトリクスはありましたが、クォータ消費量のメトリクスはありませんでした。クォータ消費量の計算式は次のとおりです。

InputTokenCount + CacheWriteInputTokens + (OutputTokenCount x burndown rate)

特にClaudeの3.7以降のモデルでは、このburndown rate(バーンダウン率)は5倍なので、出力トークン1つに対してクォータを5消費します(他のモデルはバーンダウン率1倍)。この計算を自分でやらないとクォータ消費量がわからなかったのが、EstimatedTPMQuotaUsageメトリクスでそのまま見えるようになっています。

https://docs.aws.amazon.com/ja_jp/bedrock/latest/userguide/quotas-token-burndown.html#quotas-token-burndown-management

CloudWatchメトリクスの名前空間はAWS/Bedrockです。またディメンションはModelIdです。こちらのアップデートは全リージョンで対応していて、クロスリージョン推論プロファイル・リージョン内推論の両方で取得できます。

やってみた

ということで、CloudWatchアラームとダッシュボードを作成し、BedrockでClaude Sonnet 4.6を呼び出してデータが記録されることを確認します。また、CloudWatchアラームのアクションとしてAmazon SNS(以下、SNS)トピックを指定して、メール通知も一緒にやってみます。

といっても、やり方は通常のCloudWatchアラームの設定方法と同じです。上記で書いたとおり、名前空間はAWS/Bedrock、ディメンションとしてClaude Sonnet 4.6のモデルIDを指定して、メトリクスはそれぞれTimeToFirstTokenEstimatedTPMQuotaUsageを指定します。

検証で使ったAWS CloudFormationテンプレートをこちらに記載しておきます。

検証で使ったAWS CloudFormationテンプレート
AWSTemplateFormatVersion: "2010-09-09"
Description: >
  Amazon Bedrock observability - CloudWatch alarms and dashboard
  for TimeToFirstToken and EstimatedTPMQuotaUsage metrics

Parameters:
  ModelId:
    Type: String
    Default: "global.anthropic.claude-sonnet-4-6"
    Description: >
      Bedrock model ID to monitor (cross-region inference profile or in-region model ID)

  AlertEmail:
    Type: String
    Description: Email address to receive CloudWatch alarm notifications

  TTFTAlarmThresholdMs:
    Type: Number
    Default: 1000
    Description: >
      Threshold in milliseconds for TimeToFirstToken p99 alarm.
      An alarm is triggered when p99 TTFT exceeds this value.

  TPMQuotaAlarmThreshold:
    Type: Number
    Default: 3
    Description: >
      Threshold in tokens per minute for EstimatedTPMQuotaUsage alarm.
      Set this to approximately 80% of your actual TPM quota limit for the target model.

Resources:
  # SNS Topic for alarm notifications
  AlarmTopic:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: aws-test-topic-bedrock-observability
      Subscription:
        - Protocol: email
          Endpoint: !Ref AlertEmail

  # CloudWatch Alarm: TimeToFirstToken p99
  TTFTAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: aws-test-alarm-ttft-bedrock-observability
      AlarmDescription: !Sub >
        TimeToFirstToken p99 exceeded ${TTFTAlarmThresholdMs}ms for model ${ModelId}.
        This may indicate latency degradation in the Bedrock model.
      Namespace: AWS/Bedrock
      MetricName: TimeToFirstToken
      Dimensions:
        - Name: ModelId
          Value: !Ref ModelId
      ExtendedStatistic: p99
      Period: 60
      EvaluationPeriods: 3
      DatapointsToAlarm: 2
      Threshold: !Ref TTFTAlarmThresholdMs
      ComparisonOperator: GreaterThanThreshold
      TreatMissingData: notBreaching
      AlarmActions:
        - !Ref AlarmTopic
      OKActions:
        - !Ref AlarmTopic

  # CloudWatch Alarm: EstimatedTPMQuotaUsage
  TPMQuotaAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: aws-test-alarm-tpm-quota-bedrock-observability
      AlarmDescription: !Sub >
        EstimatedTPMQuotaUsage exceeded ${TPMQuotaAlarmThreshold} tokens/min for model ${ModelId}.
        Consider requesting a quota increase before rate limiting occurs.
      Namespace: AWS/Bedrock
      MetricName: EstimatedTPMQuotaUsage
      Dimensions:
        - Name: ModelId
          Value: !Ref ModelId
      Statistic: Sum
      Period: 60
      EvaluationPeriods: 3
      DatapointsToAlarm: 2
      Threshold: !Ref TPMQuotaAlarmThreshold
      ComparisonOperator: GreaterThanThreshold
      TreatMissingData: notBreaching
      AlarmActions:
        - !Ref AlarmTopic
      OKActions:
        - !Ref AlarmTopic

  # CloudWatch Dashboard for both metrics
  ObservabilityDashboard:
    Type: AWS::CloudWatch::Dashboard
    Properties:
      DashboardName: BedrockObservabilityDashboard
      DashboardBody: !Sub |
        {
          "widgets": [
            {
              "type": "metric",
              "x": 0,
              "y": 0,
              "width": 12,
              "height": 6,
              "properties": {
                "title": "TimeToFirstToken (p50 / p90 / p99)",
                "view": "timeSeries",
                "stacked": false,
                "metrics": [
                  [ "AWS/Bedrock", "TimeToFirstToken", "ModelId", "${ModelId}", { "stat": "p50", "period": 60, "label": "p50" } ],
                  [ "AWS/Bedrock", "TimeToFirstToken", "ModelId", "${ModelId}", { "stat": "p90", "period": 60, "label": "p90" } ],
                  [ "AWS/Bedrock", "TimeToFirstToken", "ModelId", "${ModelId}", { "stat": "p99", "period": 60, "label": "p99" } ]
                ],
                "region": "${AWS::Region}",
                "period": 60,
                "yAxis": {
                  "left": {
                    "label": "Milliseconds",
                    "min": 0
                  }
                },
                "annotations": {
                  "horizontal": [
                    {
                      "label": "TTFT alarm threshold",
                      "value": ${TTFTAlarmThresholdMs},
                      "color": "#d62728"
                    }
                  ]
                }
              }
            },
            {
              "type": "metric",
              "x": 12,
              "y": 0,
              "width": 12,
              "height": 6,
              "properties": {
                "title": "EstimatedTPMQuotaUsage (tokens/min)",
                "view": "timeSeries",
                "stacked": false,
                "metrics": [
                  [ "AWS/Bedrock", "EstimatedTPMQuotaUsage", "ModelId", "${ModelId}", { "stat": "Sum", "period": 60, "label": "Sum" } ]
                ],
                "region": "${AWS::Region}",
                "period": 60,
                "yAxis": {
                  "left": {
                    "label": "Tokens",
                    "min": 0
                  }
                },
                "annotations": {
                  "horizontal": [
                    {
                      "label": "Quota alarm threshold",
                      "value": ${TPMQuotaAlarmThreshold},
                      "color": "#d62728"
                    }
                  ]
                }
              }
            },
            {
              "type": "alarm",
              "x": 0,
              "y": 6,
              "width": 24,
              "height": 3,
              "properties": {
                "title": "Alarm Status",
                "alarms": [
                  "arn:aws:cloudwatch:${AWS::Region}:${AWS::AccountId}:alarm:aws-test-alarm-ttft-bedrock-observability",
                  "arn:aws:cloudwatch:${AWS::Region}:${AWS::AccountId}:alarm:aws-test-alarm-tpm-quota-bedrock-observability"
                ]
              }
            }
          ]
        }

Outputs:
  AlarmTopicArn:
    Description: SNS Topic ARN for alarm notifications
    Value: !Ref AlarmTopic

  TTFTAlarmArn:
    Description: CloudWatch Alarm ARN for TimeToFirstToken
    Value: !GetAtt TTFTAlarm.Arn

  TPMQuotaAlarmArn:
    Description: CloudWatch Alarm ARN for EstimatedTPMQuotaUsage
    Value: !GetAtt TPMQuotaAlarm.Arn

  DashboardName:
    Description: CloudWatch Dashboard name
    Value: BedrockObservabilityDashboard

Claude Sonnet 4.6は、Boto3経由で実行します。

import boto3
import time

client = boto3.client("bedrock-runtime", region_name="ap-northeast-1")
model_id = "global.anthropic.claude-sonnet-4-6"

for i in range(5):
    response = client.converse_stream(
        modelId=model_id,
        messages=[
            {
                "role": "user",
                "content": [{"text": f"じゅげむを全文出力してください({i+1}回目)"}],
            }
        ],
    )
    # ストリームを最後まで消費する
    for event in response["stream"]:
        pass
    print(f"{i+1}回目完了")
    time.sleep(2)

CloudWatchアラームやSNSの設定が終わった上で、上記のPythonファイルを実行して、アラームが発火するか確認してみます。

Pythonファイルを3回実行し、TimeToFirstTokenのCloudWatchアラームが発火した状態がこちらです。今回は、検証用途でしきい値を低く設定しています。また、事前の検証で取れているデータやOK / Alarmステータスも表示されています。

TimeToFirstTokenのCloudWatchアラーム画面

SNSのメール通知も、このように受信しました。

TimeToFirstTokenのメール通知

同様に、EstimatedTPMQuotaUsageのCloudWatchアラームが発火した状態がこちらです。

EstimatedTPMQuotaUsageのCloudWatchアラーム画面

SNSのメール通知も、このように受信しました。

EstimatedTPMQuotaUsageのメール通知

まとめ

Amazon BedrockのCloudWatchメトリクスが新たに2つ追加され、TimeToFirstTokenEstimatedTPMQuotaUsageが監視できるようになりました。これにより、リクエストを送信してから最初のトークンを受信するまでの時間と、1分あたりのクォータ消費量を追跡できます。

特に、クォータ消費量はクォータ制限やレート制限に直接関わってくるので、追跡したいケースも多いのではないでしょうか?

みなさんもBedrockの監視メトリクスは見直してみてください。では!

この記事をシェアする

FacebookHatena blogX

関連記事