0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

BedrockのTokenomicsを実践してみた requestMetadataとModel Invocation Loggingを使ってリクエスト単位で可視化

0
Last updated at Posted at 2026-10-04

はじめに

内容は執筆時点の情報です。
記事はClaudeと一緒に作りましたが、最終調整・確認は人間がしてます。

生成AIアプリケーションを運用していくうえで、
「誰が・何に・どれだけ利用しているのか」を把握することは、コスト管理の第一歩です。

Amazon BedrockではIAM Principal単位で利用主体を追跡できます。
ただし、複数ユーザーが同じLambdaなどを経由してBedrockを利用する構成では、
Bedrockから見える実行主体は同じIAMロールになります。

つまり問題は「IAM Principalが取れない」ことではなく、

IAM Principal
≠
実際のApplication User

であることです。
社内で複数人・複数用途(要約、FAQ、分類…)が同じAPIを共有していると、
IAM Principal単位の情報だけでは内訳が見えなくなります。

2026年9月、AWSは「AWS Tokenomics Strategy」というブログで、
生成AI利用のコスト管理を次の4ステップに整理しました。

See  → Visibility & Attribution(可視化・帰属)
Save → Optimization(最適化)
Run  → Governance(ガバナンス)
Plan → Value / ROI(価値・投資対効果)

このうち最初のステップであるSeeでは、

  • IAM Principal Allocation(CUR 2.0でBedrockのモデル推論コストをIAM Principal単位に帰属)
  • Application Inference Profiles / Bedrock Projects / Bedrock Workspacesでのタグ付け
  • Model Invocation Logging(プロンプト、レスポンス、Token数、モデル、アカウント、IAMロールを記録)

が紹介されています。
IAM Principal AllocationやApplication Inference Profilesなどを使えば、
IAM Principal・チーム・アプリケーション・プロジェクト単位でコストを帰属できます。
また、Model Invocation Loggingでは推論リクエスト単位でToken数やモデル、
IAM Principalなどを自動的に記録できます。

一方、複数のエンドユーザーや複数用途が同じLambda / IAMロールを共有している場合、
そのリクエストが「どのエンドユーザーによるものか」「どの業務用途なのか」といった
アプリケーション固有の情報までは自動的には付与されません。

本記事では、このギャップをrequestMetadataで補えるかを検証しました。

Amazon Bedrock公式ドキュメントによれば、
requestMetadataはTokenomicsの記事自体では明示的に取り上げられていないものの、
team / application / environment / experimentのようにリクエストごとに変化する
属性をModel Invocation Logsへ付与するための仕組みとして、
Converse / ConverseStream /InvokeModel / InvokeModelWithResponseStreamの
4操作で利用できます(1リクエストあたり最大16個、キー・値それぞれ最大256文字)

つまり、

誰が・どの用途で・何Token使ったか

を本当に追跡できるのか、実際に実装して検証しました。

検証したいこと

誰が?
↓
どの用途で?
↓
どのモデルを使い?
↓
Input Token / Output Tokenを何Token消費した?

最終的に、以下のような粒度で利用状況を見られることをゴールにしました。

user_id use_case model input_tokens output_tokens
user-001 summary Claude Haiku 4.5 172 103
user-002 faq Claude Haiku 4.5 69 374
user-001 classification Claude Haiku 4.5 94 8

アーキテクチャ

簡易な構成図としては以下のようになり、

image.png

  • API Gateway + Lambda: サーバー管理不要な最小構成
  • Bedrock Converse API: 今回はモデル差異を吸収しやすく、レスポンスからToken Usageも取得しやすいためConverse APIを採用(requestMetadata自体はInvokeModel系APIでもヘッダ経由で利用可能)
  • Model Invocation Logging: Bedrock呼び出し単位の詳細ログをCloudWatch Logsに出力する機能

IaCはAWS CDKで管理しています。

計測する3つの情報とその取得元

項目 取得元
誰が? IAM Principal(Lambda実行ロール、固定) + requestMetadata.user_id(アプリケーション側のエンドユーザー識別子)
どの用途で? requestMetadata.use_case(summary / faq / classification)
何Token? Bedrock Converse APIレスポンスのusage、およびModel Invocation Loggingに記録されるToken数

鍵になるのがrequestMetadataです。LambdaからConverseを呼ぶときに、以下のように
アプリケーション側のコンテキストを埋め込みます。

bedrock_response = bedrock_runtime.converse(
    modelId=BEDROCK_MODEL_ID,
    system=[{"text": system_prompt}],
    messages=[{"role": "user", "content": [{"text": text}]}],
    requestMetadata={
        "user_id": user_id,
        "use_case": use_case,
        "application": APPLICATION_NAME,
        "environment": ENVIRONMENT_NAME,
    },
)

これだけで、Model Invocation Loggingの出力にrequestMetadataがそのまま載ってきます。

IAM PrincipalとApplication Userの違い

AWS IAMの観点では、Bedrockを呼び出しているPrincipal(実行主体)は常に1つです。

user-001 がAPIを呼んでも
user-002 がAPIを呼んでも
IAM上は同じ "InvokeFunctionRole"(Lambda実行ロール)

API GatewayとLambdaを共有する構成では、CloudTrailやIAMのアクセス履歴を見ても
「user-001が呼んだ」という情報は一切出てきません。IAMが記録するのは
「InvokeFunctionRoleというロールがBedrockを呼んだ」という事実だけです。

実際にModel Invocation Loggingのログを見ると、これがそのまま確認できます
(アカウントIDとロール名の一部は伏字にしています)。

{
  "requestMetadata": {
    "use_case": "summary",
    "user_id": "user-001",
    "application": "tokenomics-poc",
    "environment": "poc"
  },
  "identity": {
    "arn": "arn:aws:sts::123456789012:assumed-role/TokenomicsPocStack-***-InvokeFunctionServiceRole***/TokenomicsPocStack-***-InvokeFunctionC***"
  },
  "input": { "inputTokenCount": 172 },
  "output": { "outputTokenCount": 103 },
  "inferenceRegion": "us-east-2"
}

user_idがuser-001 user-002どちらでも、
identity.arn(IAM Principal)は完全に同一でした。

つまり、

Infrastructure Principal(IAM Principal)
→ Lambda実行ロール。AWSリソースへのアクセス制御・認可の単位

Application User
→ requestMetadata.user_id。アプリケーションが「誰のリクエストか」を表現するための識別子

という2つの「誰」は、仕組みとしてはっきり分かれています。

requestMetadata.user_idはLambdaコード内で自由に設定できる値で、
IAMによる認証・検証を経たものではありません。

本番環境では、Cognito・OIDC・社内IdP・JWTなど認証済みのIdentityから
取得したuser_idのみ
をrequestMetadataに渡すべきです。
なお、requestMetadata はModel Invocation Logsに保存されるため、
本番では氏名やメールアドレスなどの個人情報を直接格納せず、
分析用の内部IDなどを利用するのが安全です。
https://docs.aws.amazon.com/en_en/bedrock/latest/userguide/cost-mgmt-request-metadata.html

今回場合はAPI Gatewayに認証を設けておらず、user_idもリクエストボディから
直接受け取る検証用の簡易実装です。

検証結果

実際にログから、
user_id / use_caseごとのToken使用量を抜き出しました。

LambdaExecutionRole(IAM上は常に同一)
│
├ user-001
│   ├ summary          → input: 172 / output: 103
│   ├ faq              → input: 66  / output: 360
│   └ classification   → input: 94  / output: 8
│
└ user-002
    ├ summary          → input: 80  / output: 85
    └ faq              → input: 69  / output: 374

IAM上はidentity.arnが常に同一のLambda実行ロールであるのに対し、
requestMetadata経由ではユーザー・用途単位の内訳がきれいに取れています。

Tokenomicsの「See」が上手く実現できていますね。

CloudWatch Logs Insightsで集計する

1件ずつログを目視確認するだけでなく、CloudWatch Logs Insightsを使えば、
user_id × use_case単位でToken使用量を集計できます。

本検証で実際に出力されたログのフィールド構造
(requestMetadata.user_id、input.inputTokenCount等)に
合わせたクエリは以下の通りです。

fields requestMetadata.user_id, requestMetadata.use_case,
       input.inputTokenCount, output.outputTokenCount
| stats count(*) as requests,
        sum(input.inputTokenCount) as inputTokens,
        sum(output.outputTokenCount) as outputTokens
  by requestMetadata.user_id, requestMetadata.use_case
| sort inputTokens desc

※対象ロググループは/aws/bedrock/tokenomics-poc(Model Invocation Loggingの送信先)

実際にaws logs start-query / get-query-resultsで実行したところ、
以下のようにuser_id × use_case単位で集計された結果が返ってきました。

user_id use_case requests inputTokens outputTokens
user-001 summary 2 172 103
user-001 classification 2 94 8
user-001 faq 1 66 360
user-002 summary 1 80 85
user-002 faq 2 69 374
(なし) (なし) 3 17 59

最後の行(user_id/use_caseが空)は、
動作確認の過程でBedrockコンソールのPlaygroundから直接呼び出した分です。
Playground経由のリクエストだけrequestMetadataが空になったことで、
メタデータを付与することの意味も実データ上で確認できました。
公式ドキュメントにも「requestMetadataはBedrockによって強制されるものではなく、
付与しなくてもリクエストは成功する」と明記されており、今回の実測結果と一致します。
組織全体でカバレッジを保証したい場合は、共有クライアントやLLMゲートウェイ側で
付与を強制する設計が公式にも推奨されています。

1件ずつのログ確認だけでなく、ユーザー・用途単位での集計まで同じログソースから行えることが確認できます。

まとめ

Amazon BedrockのrequestMetadataとModel Invocation Loggingを組み合わせれば、
「誰が・どの用途で・どれだけ使ったか」をアプリ側で簡単に可視化できました。

今回はコスト計算そのものまでは踏み込みませんでした。
requestMetadataは、あくまでModel Invocation Loggingによるリクエスト単位の
分析のための仕組みです。これに対して、AWS Tokenomics Strategyが紹介する、

IAM Principal Allocation(CUR 2.0)や
Application InferenceProfiles / Bedrock Projects / Bedrock Workspaces

でのタグ付けは、請求・コスト帰属のレイヤーで役割が異なります。
今回取得したuser_id / use_caseを分析軸として使い、これらのコスト帰属機能と
組み合わせることで、「IAM Principal・タグ単位」では届かなかった、
エンドユーザー単位まで含めた用途別コスト管理へ発展させられるはずです。

見えた先に何をするか

Tokenomics StrategyはSee(可視化・帰属)の先に、
Save(最適化)・Run(ガバナンス)・Plan(価値・ROI)と続きます。
今回Seeで取れたデータは、実はそのまま次のステップの入力になります。

See  → FAQ用途では他用途と比べてOutput Tokenが多い傾向が見える
Save → FAQの回答長を制御する / プロンプトを改善する /
       より安価なモデルを検討する、といった最適化対象が見えてくる
Run  → AWS BudgetsやSCPなどで過剰利用を防ぐ
Plan → FAQにかかるコストに対して、問い合わせ対応時間削減などの
       業務価値を評価する

つまり、Seeで「誰が・どの用途で・何Token使ったか」を集計し、
Save/Run/Planを行っていく、SeeはTokenomicsのスタート地点になります。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?