🔖

Bedrock(Claude)のトークンquotaを監視する

に公開

かわごえです、タイトルの通りです、

先日Bedrockで「429 Too Many Token」というエラーにでくわしました。
事象はログの通り、AWS側のトークンの使用量が上限に達しているため発生するエラーです。

根本解消には、上限緩和を依頼するか、Exponential backoffのようなものを入れるかなどいくつか解決策はありますが、今回はその前段の「そもそものquotaに抵触しそうかをモニタリングする」方法です。

バーンダウンレートを理解する

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

bedrockの一部モデルには、バーンダウンレートというものが存在します。
これはquotaの計算にのみ使われるもので、以下のモデルでは実際の出力トークンの5倍の値でquotaの計算上は利用されます。

  • Opus 4
  • Sonnet 4
  • 3.7 Sonnet

例えば、
IN: 100 Token
OUT: 500 Token
だった場合、quotaの計算としては、100+500*5=2600という値が使われるという形です。

どのメトリクスをモニタリングするか

一番上の参考ドキュメントにも記載はあるのですが、プロンプトキャッシュを利用する場合には、CacheWriteInputTokensの値も考慮する必要があります。

そのため、quotaの計算に利用されるトークンの計算式は以下のようになります。

InputTokenCount + CacheWriteInputTokens + (OutputTokenCount x burndown rate)

つまり、

  • InputTokenCount
  • CacheWriteInputTokens
  • OutputTokenCount

のメトリクスさえ特定できれば、あとは数式でいい感じにquotaのモニタリングが実現できることになります。

CDKで書くとこう

これらのメトリクスを、いい感じに足し算掛け算して、一発アラームまで流すCDKがこちらです。

import * as cdk from "aws-cdk-lib";
import * as cloudwatch from "aws-cdk-lib/aws-cloudwatch";
import { Construct } from "constructs";

export class BedrockTokenSumStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const period = cdk.Duration.minutes(1); // quotaは1分ごとにリセットされるため、1分間隔で集計
    const region = this.region;
    const account = this.account;
    const modelId = "us.anthropic.claude-sonnet-4-20250514-v1:0"; // 例: 使用するモデルID

    const inputTokens = new cloudwatch.Metric({
      namespace: "AWS/Bedrock",
      metricName: "InputTokenCount",
      dimensionsMap: { ModelId: modelId },
      statistic: "Sum",
      period,
      region,
      account,
    });

    const outputTokens = new cloudwatch.Metric({
      namespace: "AWS/Bedrock",
      metricName: "OutputTokenCount",
      dimensionsMap: { ModelId: modelId },
      statistic: "Sum",
      period,
      region,
      account,
    });

    const cacheWriteTokens = new cloudwatch.Metric({
      namespace: "AWS/Bedrock",
      metricName: "CacheWriteInputTokens",
      dimensionsMap: { ModelId: modelId },
      statistic: "Sum",
      period,
      region,
      account,
    });

    // m1 + m2 で新しい“合計トークン数メトリクス”
    const totalTokens = new cloudwatch.MathExpression({
      expression: "m1 + m2*5 + m3",
      usingMetrics: { m1: inputTokens, m2: outputTokens, m3: cacheWriteTokens },
      label: "TotalTokenCount",
      period,
    });

    // 例: ダッシュボードに表示
    const dashboard = new cloudwatch.Dashboard(this, "BedrockTokensDashboard", {
      dashboardName: "bedrock-token-usage",
    });
    dashboard.addWidgets(
      new cloudwatch.GraphWidget({
        title: "Bedrock Total Tokens (Input + Output + Cache Write)",
        left: [totalTokens],
      })
    );

    // 例: アラーム(しきい値は適宜)
    new cloudwatch.Alarm(this, "HighTotalTokens", {
      metric: totalTokens,
      threshold: 100000,
      evaluationPeriods: 1,
      comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD,
      alarmDescription: "Total tokens exceeded threshold",
    });
  }
}

中身は一般的なCloudWatch AlarmのCDKなので詳細は割愛しますが、
こんな感じでいい感じに足し算できるはずです。

私のプライベート環境ではまだToo Many Tokenを再現できてないので
メトリクスの正確性まで細かく見れていないのですが、
もしquotaの確認に手間取ってる方がいて手助けになれば幸いです。

Discussion