TECH PLAY

大規模言語モデル(LLM)

大規模言語モデル(LLM: Large Language Model)は人工知能の一種であり、大量のテキストデータを学習して言語に関する知識を獲得する機械学習モデルです。自然言語処理の分野でとても重要な役割を果たしています。

イベント

マガジン

技術ブログ

こんにちは、クロスイノベーション本部リーディングエッジテクノロジーセンターの山下です。 最近は、gpt-ossやQwen3.5といったローカルLLM(Local Large Language Model)も注目されており、これらを活用したプロジェクトも増えてきています。 今回の記事では、ローカルLLMのベンチマークソフトウェアである GuideLLM について紹介します。LLMの性能には様々な観点がありますが、GuideLLMはLLMサーバ自体の応答速度などを測るためのベンチマークソフトウェアです。 GuideLLMでは、以下のような観点でLLMサーバの性能を評価します。 レイテンシー(応答時間) スループット(処理能力) 同時リクエスト数に対する性能の変化 エラー率や安定性 GuideLLMは、LLMサーバに対して様々な負荷をかけることで、これらの観点で性能を評価します。例えば、同時に複数のリクエストを送ることで、スループットやレイテンシーの変化を測定します。また、長時間の負荷テストを行うことで、安定性やエラー率も評価します。 LLMサーバの評価項目 LLMサーバの評価には、TTFT(Time To First Token)、ITL(Inter Token Latency)やThroughputなどの指標が用いられます。 TTFT(Time To First Token) : LLMが最初のトークンを生成するまでの時間を測定します。これは、ユーザーが応答を受け取るまでの待ち時間を示す重要な指標です。 ITL(Inter Token Latency) : トークン間の生成時間を測定します。これにより、LLMの応答速度や処理能力を評価できます。 Throughput : 一定時間内に処理できるリクエストの数を測定します。これは、LLMサーバの処理能力を示す指標です。 Latency(レイテンシー) : LLMサーバがリクエストに対して応答するまでの時間を測定します。これはトークンごとではなくすべての生成が完了するまでの時間になります。 同時リクエスト数に対する性能の変化 : 同時に複数のリクエストを送ることで、LLMサーバの性能がどのように変化するかを評価します。これにより、サーバのスケーラビリティや負荷耐性を測定できます。 エラー率や安定性 : 長時間の負荷テストを行うことで、LLMサーバの安定性やエラー率を評価します。 通常のWebサーバのベンチマークソフトウェアは、HTTPリクエストの処理能力や応答時間を測定することが一般的です。しかし、LLMサーバは応答を作成するための時間が長く、しかも生成された結果をリアルタイムに返す仕組みになっています。このため、通常のWebサーバの指標に加えてTTFTやITLといったLLM特有の指標が重要になります。特にTTFTはユーザーが最初の応答を受け取るまでの待ち時間を示し、ITLは1つのトークンが生成されてから次のトークンが生成されるまでの時間になります。これらがユーザーエクスペリエンスに直結する重要な指標となります。 ChatGPTなどのサービスを利用している際に、最初の一文字が出るまでの時間が長いと感じることがあるかもしれませんが、これはTTFTが長いことを意味しています。TTFTが短いほど、ユーザーは迅速に応答を受け取ることができ、より快適な体験を提供できます。 GuideLLMは実際にLLMサーバに対して負荷をかけることで、これらの指標を測定し、LLMサーバの性能を評価します。これにより、LLMサーバの性能を定量的に評価し、改善点を特定することができます。 GuideLLMの使用方法 GuideLLMは、Pythonで実装されたベンチマークソフトウェアです。以下のコマンドでインストールできます。 他のインストール方法については、公式の GitHubリポジトリ を参照してください。 pip install guidellm[recommended] インストール後、例えば以下のコマンドでベンチマークを実行できます。 guidellm benchmark run\ --target "http://<LLMサーバのアドレス:ポート>" \ --profile sweep \ --max-seconds 30 \ --data "prompt_tokens=256,output_tokens=128" ここでは --target オプションでLLMサーバのアドレスとポートを指定します。 --profile オプションでは、ベンチマークのプロファイルを指定します。 sweep プロファイルは、様々な負荷条件でベンチマークを実行するためのプロファイルです。 --max-seconds オプションでは、ベンチマークの最大実行時間を指定します。 --data オプションでは、ベンチマークに使用するデータを指定します。ここでは、プロンプトトークン数と出力トークン数を指定しています。 --profile として今回は sweep を指定しています。これの動作は以下のようなものになっています。 まずは1並列でのベンチマークを行い、ベースラインのレイテンシーを測定します。これにより、LLMサーバが単一リクエストに対してどれくらいの応答時間があるかを把握します。 次に並列アクセスを行い(デフォルトでは512並列)LLMサーバの最大スループットを測定します。これにより、LLMサーバがどれくらいのリクエストを同時に処理できるかを把握します。 2つのベンチマークでベースとなる性能と最大スループットがわかりました。次に、ベースラインのレイテンシーと最大スループットの間の設定でベンチマークを試します。これにより、LLMサーバが異なる負荷条件でどのように性能が変化するかを把握します。 --profile には他にも色々なプロファイルが用意されているので、目的に応じて選択することができます。 公式のページ を参考にしてください。 実行例 ここでは、実際にGuideLLMを使用してベンチマークを実行した例を紹介します。今回は、ローカルで動作しているLLMサーバに対してベンチマークを実行しました。 通信するLLMサーバはDGX Sparkで動作しているvLLMサーバでgpt-oss-120b を使用しています。 以下のコマンドでベンチマークを実行しました。 GUIDELLM__MAX_CONCURRENCY は、guidLLMがベンチマークを実行する際の最大並列数です。 今回の接続先がDGX Sparkなのでそこまで多くの接続はしない想定なので128並列を指定してみました。 また、 --processor オプションで、ベンチマークで使用するデータを生成するために使用するプロセッサを指定しています。ここでは、gpt-oss-120bが接続先になるので、 openai/gpt-oss-120b を指定しています。 export GUIDELLM__MAX_CONCURRENCY=128 guidellm benchmark --target "LLMサーバのアドレス:ポート" \ --output-dir ./output-dir/ \ --profile sweep \ --max-seconds 300 \ --data "prompt_tokens=256,output_tokens=128" \ --processor "openai/gpt-oss-120b" ベンチマークの結果は以下のようになりました。 すべての結果を載せると長すぎるので、ベンチマーク結果のサマリの部分を抜粋しています。 サマリを見てみると全体の数字の傾向として、同時リクエスト数が増えるにつれて、レイテンシー(Lat)が増加し、スループット(Tok gen/s)も増加していることがわかります。 また、TTFTやITLも同様に増加しています。つまりリクエスト数が増えると応答速度が遅くなっていることがわかります。 一方でTTFTは最悪でも500ms程度で、ITLも131ms程度なので、同時リクエスト数が増えても応答速度はまだ許容可能な範囲に収まっていることがわかります。 特に throughput@128 の行を見ると、スループットが約5.1 req/sに達していることがわかります。さらに、123.2並列まで問題なく処理できていることがわかります。この場合でも、TTFTは1506.7ms、ITLは177.3msなので、同時リクエスト数が増えても応答速度はまだ許容可能な範囲と言えるのではないでしょうか。 複数ある constant@数字 の結果は、ベースラインのレイテンシーと最大スループットの間の設定でベンチマークを試した結果になります。 @ の右側の数字はリクエストの頻度になります。 これらの結果から、TTFTがどの程度までなら許容できるのかを基準にして許容可能なリクエスト頻度を決めることもできます。例えば、TTFTで900ms以下に応答してほしいという場合であるなら constant@1.49 、 constant@2.09 の結果が参考になるかもしれません。 constant@1.49 ではTTFTが786.1ms、 constant@2.09 ではTTFTが943.2msとなっています。つまり、1.49リクエスト/秒程度であれば、TTFTが900ms以下に収まる可能性があることがわかります。 利用してみて気が付いた点 ベンチマークの出力形式としては、JSONやCSVに加えてHTMLも選択できます。しかし、今回HTML形式で出力したものを確認したところ、うまく表示されませんでした。生成されているHTMLに問題がありそうですが原因は不明です。JSONやCSV形式で出力したものは問題なく利用できたので今回はそちらを使用しました。 まとめ 今回は、ローカルLLMのベンチマークソフトウェアであるGuideLLMについて紹介しました。GuideLLMは、LLMサーバの性能を様々な観点で評価するためのベンチマークソフトウェアです。GuideLLMを使用することで、LLMサーバの性能を定量的に評価し、改善点を特定することができます。 ローカルLLMを活用したプロジェクトを進める際には、LLMサーバの性能を評価して最適な設定を見つけることが重要です。ぜひ、GuideLLMを活用して、ローカルLLMの性能を評価して最適な設定を見つけてください。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @yamashita.tsuyoshi レビュー: @sato.taichi ( Shodo で執筆されました )
はじめに 今回は AgentCore CLI を使ったエージェント開発を本番運用できるかを検討した際に、複数環境のデプロイについて詰まったポイントがあったので、ご紹介させていただきます。 AgentCore CLIは2026年4月17日現在では、GA前段階のため、本記事で紹介する内容が今後変更される可能性があります。 検証に使用したエージェント構成 今回検証のために使用したエージェントの構成を簡単に紹介します。 今回はAgentCore CLIの使い方の説明が主題ではないため、使い方についての詳細は省かせていただきます。 AgentCore CLIの agentcore create コマンドで以下のようなエージェントを作成したという前提で話を進めさせていただきます。 - Project name : MyProject - Agent name : analysis - Type : Create new agent - Language : Python - Build : Direct Code Deploy - Protocol : HTTP - Framework : OpenAI Agents - Advanced : defaults コマンドを実行すると以下のような構成でファイルが生成されます。 主要なものに絞って記載していますが、実際には CDK の設定ファイルや LLM コンテキストファイルなども生成されます。 MyProject/ # プロジェクトルート ├── AGENTS.md # エージェントの概要・設計ドキュメント ├── README.md # プロジェクトのREADME ├── agentcore/ │ ├── agentcore.json # エージェント定義(ランタイム、Gateway、Credential等) │ ├── aws-targets.json # デプロイ先のAWSアカウント・リージョン │ ├── tool-schema.json # Gatewayターゲットのツール定義 │ ├── .env.local # APIキー等のシークレット │ ├── .cli/ │ │ └── deployed-state.json # デプロイ済みリソースの状態 │ └── cdk/ │ ├── bin/cdk.ts # CDKエントリポイント │ └── lib/cdk-stack.ts # CDKスタック定義 └── app/ # エージェントのアプリケーションコード └── analysis/ ├── main.py └── pyproject.toml また、上記構成に含まれていませんが、今回の構成では、AgentCore CLIで作成したエージェントが Gateway 経由で、 lambroll でデプロイした Lambda 関数をツールとして呼び出します。 デプロイの仕組み agentcore deploy を実行すると、内部では以下が行われます: デプロイターゲット( aws-targets.json )の読み込み agentcore.json のバリデーション CDKプロジェクトのビルド Credential(APIキー等)のセットアップ CloudFormationテンプレートの合成(synth) CloudFormationスタックのデプロイ CloudFormationスタックには、ランタイム、Gateway、IAMロール等のリソースがまとめて含まれます。 詰まったポイント 1. --target オプションでデプロイ先が絞り込めない 問題 AgentCore CLIでは、デプロイ先のAWSアカウント・リージョンを aws-targets.json に定義します。 dev/prodを分離するために、以下のように2つのターゲットを定義しました。 // aws-targets.json [ { " name ": " dev ", " account ": " 111111111111 ", " region ": " ap-northeast-1 " } , { " name ": " prod ", " account ": " 999999999999 ", " region ": " ap-northeast-1 " } ] agentcore deploy コマンドには --target オプションがあり、デプロイ先を指定できます。 --target dev を指定すればdev環境のみにデプロイされると期待しましたが、実際には以下のようにprodのCloudFormationスタックもdevアカウントに作成されてしまいました。 # targetをdevに指定してデプロイ AWS_PROFILE=dev-profile agentcore deploy --target dev 実際にはdevアカウントに以下の2つのスタックが作成される - AgentCore-MyProject-dev (意図通り) - AgentCore-MyProject-prod (意図しない) 原因 この問題は、CLIとCDKの間でターゲット情報が連携されていないことが原因のようです。 CLIの --target オプションは、 aws-targets.json からターゲット情報(account, region)を取得してIdentityのセットアップやデプロイ後の状態記録に使われますが、CDKのsynth(CloudFormationテンプレートの合成)やdeploy処理にはターゲット名が伝わりません。 agentcore create で生成される cdk.ts のデフォルトコードでは、 aws-targets.json に定義された 全ターゲット に対してスタックを生成するforループになっています。 // cdk.ts(デフォルト生成コード) for ( const target of targets) { // --target の指定に関係なく、全ターゲット分のスタックが生成される new AgentCoreStack(app, stackName, { ... } ); } CDKのsynthはローカルで実行されるため、アカウントIDが異なっていてもテンプレート生成自体は成功します。その結果、devアカウントのクレデンシャルで実行しているにもかかわらず、prod用のスタック定義もdevアカウントにデプロイされてしまいます。 対策 対策1: cdk.ts を修正して環境変数でフィルタ cdk.ts に環境変数 AGENTCORE_TARGET でターゲットをフィルタするコードを追加しました。 // cdk.ts const app = new App (); // 環境変数でターゲットをフィルタ const targetFilter = process .env.AGENTCORE_TARGET; const filteredTargets = targetFilter ? targets. filter ( t => t. name === targetFilter) : targets; for ( const target of filteredTargets) { // フィルタされたターゲットのみスタックを生成 new AgentCoreStack(app, stackName, { ... } ); } デプロイ時に環境変数を指定して実行します: # dev環境のみデプロイ AGENTCORE_TARGET=dev AWS_PROFILE=dev-profile agentcore deploy --target dev # prod環境のみデプロイ AGENTCORE_TARGET=prod AWS_PROFILE=prod-profile agentcore deploy --target prod 注意点 : agentcore create で新規プロジェクトを作成するたびに cdk.ts が初期状態で生成されるため、毎回この修正を適用する必要があります。 CLIの --target オプションの値はCDKプロセスに自動的に引き渡されないため、環境変数 AGENTCORE_TARGET として別途指定する必要があります。 --target はCLI内部でのターゲット情報取得に、 AGENTCORE_TARGET はCDKのsynthでのスタック絞り込みに使われるため、両方に同じ値を指定する必要があり、冗長になってしまいます。将来のCLIバージョンで改善される可能性はありますが、現時点(v0.8.0)ではこの対応が必要です。 対策2: aws-targets.json を毎回リセットしてプロファイルから自動検出 aws-targets.json を空( [] )にしてからデプロイすると、CLIが AWS_PROFILE からアカウントIDとリージョンを自動検出し、 "default" という名前のターゲットを自動生成します。 # dev環境(aws-targets.json が空の状態で実行) AWS_PROFILE=dev-profile agentcore deploy # prod環境(aws-targets.json をリセットしてから実行) echo '[]' > agentcore/aws-targets.json AWS_PROFILE=prod-profile agentcore deploy 一見シンプルですが、実用上は問題があります。devデプロイ後に aws-targets.json にはdevターゲットが追加された状態になっています。この状態でリセットせずにprodをデプロイすると、 aws-targets.json に2つのターゲットが登録され、対策1で述べたのと同じ問題(全ターゲット分のスタックがsynthされる)が発生してしまいます。 そのため、デプロイのたびに aws-targets.json をリセットする運用が必要になりますが、CI/CDを使い、 echo '[]' > agentcore/aws-targets.json を実行してからデプロイする形にすれば、毎回クリーンなワークスペースから始まるためリセット忘れは防げると思います。 対策1は agentcore create で自動生成される cdk.ts を書き換える必要があり、CLIのバージョンアップで生成内容が変わった際に手動マージが必要になったり、修正漏れで予期せぬ挙動を起こすリスクがあります。そのため、基本的には自動生成ファイルには手を入れず、対策2をCI/CDで運用するのが望ましいと考えています。 2. Lambda ARNのハードコーディング 問題 GatewayにLambda関数をターゲットとして追加するには、以下のようにコマンドを実行します。 agentcore add gateway-target \ --gateway Gateway \ --name DataFetcher \ --type lambda-function-arn \ --lambda-arn arn:aws:lambda:ap-northeast-1:111111111111:function:get-data \ --tool-schema-file ./agentcore/tool-schema.json ./agentcore/tool-schema.json にはLambda関数が提供するツールの定義を記述したJSONファイルを指定します。 Lambda ARNターゲットの場合、Gatewayがどのツールを公開しているか知る手段がないため、このファイルを自分で用意する必要があります。 // tool-schema.json の例 { " tools ": { " get-data ": { " name ": " get-data ", " description ": " 分析用のデータを取得する ", " inputSchema ": { " type ": " object ", " properties ": { " date ": { " type ": " string ", " description ": " 取得対象の日付 " } } , " required ": [ " date " ] } } } } このコマンドを実行すると、 agentcore.json に以下のようなGatewayターゲットが追加されます。 // agentcore.json " agentCoreGateways ": [ { " name ": " Gateway ", " targets ": [ { " name ": " DataFetcher ", " targetType ": " lambdaFunctionArn ", " lambdaFunctionArn ": { " lambdaArn ": " arn:aws:lambda:ap-northeast-1:111111111111:function:get-data ", " toolSchemaFile ": " ./agentcore/tool-schema.json " } } ] } ] ここで問題になるのが lambdaArn の値です。Lambda ARNにはAWSアカウントIDが含まれるため、dev/prodでアカウントが異なる場合、デプロイ前に毎回この値を対象環境のARNに書き換える必要があります。 devにデプロイする場合: arn:aws:lambda:ap-northeast-1:111111111111:function:get-data prodにデプロイする場合: arn:aws:lambda:ap-northeast-1:999999999999:function:get-data agentcore.json はgit管理されるファイルのため、デプロイのたびにARNを書き換えてコミットするのは手間がかかりますし、書き換え忘れにより誤った環境のARNでデプロイしてしまうリスクもあります。 対策 agentcore.json にはdev用のARNを登録しておき、 cdk.ts 側で関数名だけを取り出して、ターゲットのアカウント・リージョンからARNを動的に再構築するようにしました。 // agentcore.json(dev用のARNで登録しておく) { " lambdaArn ": " arn:aws:lambda:ap-northeast-1:111111111111:function:get-data ", " toolSchemaFile ": " ./agentcore/tool-schema.json " } // cdk.ts const resolvedMcpSpec = mcpSpec ? JSON . parse ( JSON . stringify (mcpSpec)) : undefined ; if (resolvedMcpSpec?.agentCoreGateways) { for ( const gw of resolvedMcpSpec.agentCoreGateways) { for ( const t of gw.targets ?? [] ) { if (t.lambdaFunctionArn?.lambdaArn) { // 元のARNから関数名を抽出し、ターゲットのアカウント・リージョンで再構築 const functionName = t.lambdaFunctionArn.lambdaArn. split ( ':' ). pop (); t.lambdaFunctionArn.lambdaArn = `arn:aws:lambda: ${ target. region} : ${ target.account } :function: ${ functionName } ` ; } } } } 注意点 : cdk.ts は agentcore create で新規プロジェクトを作成するたびに初期状態で生成されるため、毎回この修正を適用する必要があります。 また、前述の通り自動生成ファイルを書き換えるのはCLIのバージョンアップ等でバグを生みやすいので、CI/CDのデプロイジョブ内で agentcore.json のARNを対象環境のアカウントIDに置換してからデプロイする方が安全かなと思います。 3. APIキーをdev/prodで分けたい 問題 エージェントが外部API(OpenAI等)を利用する場合、APIキーをCredentialとして登録します。登録されたAPIキーはAgentCore Identityサービスの アウトバウンド認証 (エージェントから外部サービスへの認証情報)として管理されます。 agentcore add credential --name OpenAIApiKey --api-key sk-xxxxx このコマンドを実行すると、以下の2箇所に情報が書き込まれます。 agentcore/agentcore.json — Credentialのメタ情報(名前・タイプ) agentcore/.env.local — APIキーの実際の値 // agentcore.json " credentials ": [ { " authorizerType ": " ApiKeyCredentialProvider ", " name ": " OpenAIApiKey " } ] agentcore/.env.local AGENTCORE_CREDENTIAL_OPENAIAPIKEY=sk-xxxxx 環境変数名は Credential名から AGENTCORE_CREDENTIAL_{NAME} の形式で自動生成されます。デプロイ時にこの値が読み取られ、AWS側の Token Vault (AgentCore Identityサービスのシークレットストア)に登録されます。 dev/prodで同じAPIキーを使う場合は、 .env.local の値をそのまま使えるので問題ありません。しかし、セキュリティや課金管理の観点からdev/prodでAPIキーを分けたい場合、 .env.local は1ファイルしかないため、デプロイのたびに値を書き換える必要があります。 対策 デプロイ時に環境変数でAPIキーを上書きします。環境変数が設定されていれば .env.local の値より優先されます。 # dev環境 AGENTCORE_CREDENTIAL_OPENAIAPIKEY=sk-dev-xxxxx \ AGENTCORE_TARGET=dev \ AWS_PROFILE=dev-profile \ agentcore deploy --target dev # prod環境 AGENTCORE_CREDENTIAL_OPENAIAPIKEY=sk-prod-xxxxx \ AGENTCORE_TARGET=prod \ AWS_PROFILE=prod-profile \ agentcore deploy --target prod ただし、毎回デプロイコマンドにAPIキーを環境変数として渡すのであれば、 .env.local を直接書き換える運用と手間は変わりません。今回はCI/CDを使わずローカルからデプロイする運用のため、デプロイ前に .env.local の値を対象環境のAPIキーに書き換える方法を採用しました。 別のアプローチ:dev/prodでプロジェクトを分ける ここまで紹介した課題は、いずれも 1つのプロジェクトでdev/prodを共有する ことに起因しています。 これらをすべて解消するシンプルなアプローチとして、dev用とprod用でそれぞれ別のAgentCoreプロジェクトを作成する方法があります。 MyAgent-dev/ ├── agentcore/ │ ├── agentcore.json ← dev用のLambda ARN、dev用のAPIキー │ ├── aws-targets.json ← devアカウントのみ │ └── cdk/ └── app/ └── analysis/ MyAgent-prod/ ├── agentcore/ │ ├── agentcore.json ← prod用のLambda ARN、prod用のAPIキー │ ├── aws-targets.json ← prodアカウントのみ │ └── cdk/ └── app/ └── analysis/ この方法なら cdk.ts のカスタマイズは不要で、 aws-targets.json にはターゲットが1つだけなのでsynthの問題も発生せず、 .env.local も環境ごとに独立しています。 ただし、 app/ 配下のエージェントコードが2つのプロジェクトで重複するため、ロジックを変更するたびに両方を更新する必要があります。コードの同期忘れによる環境差異が生まれるリスクもあるため、この方法を積極的に採用することはできないなと思いました。 まとめ AgentCore CLIを使用してみて、実際に本番運用できるのかを検討しました。 CLIで必要なリソースを簡単に素早く作成できるというメリットはありますが、環境を分離するには課題が多いという検証結果になりました。 最後まで読んでいただきありがとうございました!
G-gen の佐々木です。当記事では、ADK で開発した AI エージェントに BigQuery Agent Analytics のプラグインを組み込むことで、エージェントのリクエストやレスポンス、ツール呼び出しなどのイベントを BigQuery に記録し、SQL で分析できるようにしていきます。 構成 当記事で使用するもの Agent Development Kit(ADK) Vertex AI Agent Engine BigQuery BigQuery Agent Analytics について 概要 BigQuery に記録されるイベントについて エージェントの開発 ディレクトリ構成 プロジェクトの準備 エージェントのソースコード(agent.py) Google Cloud 側の準備 BigQuery データセットの作成 Agent Engine サービスアカウントへの IAM 付与 ローカル認証 .env ファイルの作成 ローカルでの動作確認(ADK Web) Agent Engine へのデプロイ デプロイの実施 動作確認 構成 当記事では、 Agent Development Kit(ADK) で定義した AI エージェントを Vertex AI Agent Engine にデプロイし、エージェントの実行中に発生するイベント(LLM への入出力、ツール呼び出し、エージェントのライフサイクルなど)を BigQuery にストリーミング方式で記録できるようにします。 イベントの記録には、ADK が公式に提供する BigQuery Agent Analytics プラグイン ( BigQueryAgentAnalyticsPlugin )を使用します。プラグインをエージェントに登録するだけで、BigQuery の Storage Write API を使用したイベントの記録と、イベント型ごとのビューの自動生成が行われます。 BigQuery に記録されたイベントにクエリを実行することで、トークン使用量の集計、ツール呼び出しの頻度分析、特定セッションのトレースなどを行うことができます。また、 Conversational Analytics 機能を使用した自然言語での分析や、BigQuery ML や Looker / Data Studio(データポータル)による高度な分析、可視化も可能です。 BigQuery Agent Analytics を使用してエージェントのイベントを BigQuery にストリーミングする 当記事で使用するもの Agent Development Kit(ADK) Agent Development Kit(ADK) は、Google Cloud が提供する AI エージェント構築のためのオープンソース フレームワークであり、単純なタスクをこなすエージェントから複数のエージェントが協働する複雑なワークフローまで容易に実装できます。 ADK には、当記事で使用する BigQueryAgentAnalyticsPlugin のような、エージェントの振る舞いを拡張するためのプラグインが用意されており、エージェントのコードを大きく変更することなくロギング、トレーシングなどの機能を追加できます。 参考 : Agent Development Kit の概要 参考 : Plugins Vertex AI Agent Engine Vertex AI Agent Engine(Agent Engine) は AI エージェントの実行基盤を提供するフルマネージドサービスです。 Agent Engine では、エージェントとのマルチターン会話を実現するための組み込みの セッション機能 を利用することができるほか、エージェントの機能拡張に必要な様々な機能が提供されています。また、Agent Engine のコンソールからチャット UI(Playground)で直接エージェントの動作確認を行うことができます。 Agent Engine の詳細については、以下の記事をご一読ください。 blog.g-gen.co.jp BigQuery BigQuery は Google Cloud が提供するフルマネージドなサーバーレス データウェアハウスです。大量のデータを高速に分析できる SQL エンジンを備えており、 Storage Write API を用いたストリーミング インサートによってリアルタイムにデータを書き込むこともできます。 当記事では、エージェントのイベントを格納する先として BigQuery を使用します。BigQuery Agent Analytics プラグインが内部で Storage Write API を利用してイベントを非同期にストリーミングするため、エージェントのパフォーマンスへの影響を抑えつつログを蓄積できます。 BigQuery の詳細については、以下の記事をご一読ください。 blog.g-gen.co.jp 参考 : BigQuery の概要 参考 : BigQuery Storage Write API の概要 BigQuery Agent Analytics について 概要 BigQuery Agent Analytics は、AI エージェントのインタラクション データをキャプチャ・分析・可視化するためのオープンソース ソリューションです。エージェントのリクエスト、レスポンス、ツール呼び出し、エラーなどのイベントを BigQuery テーブルに直接ストリーミングすることで、SQL や BigQuery ML での分析や、ダッシュボードでの可視化を可能にします。 当記事を執筆している2026年4月現在では、以下の2つのフレームワークに対応しています。 Agent Development Kit(ADK) LangGraph(2026年4月現在ではプレビュー) ADK では BigQueryAgentAnalyticsPlugin という プラグイン が提供されており、これをエージェントに登録するだけで BigQuery に対するイベントのログストリーミングを有効化できます。プラグインには以下のような特徴があります。 Storage Write API による高スループット・低遅延の非同期書き込み マルチモーダルのコンテンツ(テキスト / 画像 / 音声 / 動画)を記録可能(コンテンツの種類によっては Cloud Storage にオフロード) OpenTelemetry と統合された分散トレーシングにより trace_id 、 span_id による実行フローの可視化が可能 ツールの呼び出し元( LOCAL / MCP / SUB_AGENT / A2A / TRANSFER_AGENT )を記録 新しいイベント型が追加された際に、既存テーブルに対して自動で列を追加 その他、詳細な仕様については、以下の公式ドキュメントを参照してください。 参考 : BigQuery Agent Analytics plugin for ADK 参考 : BigQuery エージェント分析を使用する BigQuery に記録されるイベントについて BigQuery に記録されるイベントは、大きく以下の5つのカテゴリに分類されます。 カテゴリ イベント型 内容 LLM interactions LLM_REQUEST / LLM_RESPONSE / LLM_ERROR LLM へのプロンプト、モデル出力、エラーに関するイベント トークン使用量、生成にかかった時間なども記録される Tool usage TOOL_STARTING / TOOL_COMPLETED / TOOL_ERROR ツール呼び出しの開始、完了、エラーに関するイベント ツールの呼び出し元( tool_origin )も記録される State Management STATE_DELTA エージェントの内部状態の変更に関するイベント Agent lifecycle & Generic Events INVOCATION_STARTING / INVOCATION_COMPLETED / AGENT_STARTING / AGENT_COMPLETED / USER_MESSAGE_RECEIVED エージェントの起動、実行完了、ユーザー入力の受信などのイベント Human-in-the-Loop (HITL) Events HITL_CREDENTIAL_REQUEST / HITL_CONFIRMATION_REQUEST / HITL_INPUT_REQUEST / 各イベントの _COMPLETED ユーザー認証情報の要求、ユーザーへの確認要求、ユーザーからの入力要求などの割り込みイベント これらのイベントはすべて agent_events という1つのテーブルにまとめて格納されますが、プラグインによって自動で生成されるビュー( v_llm_request 、 v_llm_response 、 v_tool_completed など)を使用することで、イベント型ごとに分析が可能です。 イベントのスキーマや詳細な内容については、以下の公式ドキュメントを参照してください。 参考 : BigQuery Agent Analytics plugin for ADK - Event types and payloads エージェントの開発 ディレクトリ構成 当記事では、コーヒーに関する質問に回答する「コーヒーエージェント」を ADK で構築し、 BigQueryAgentAnalyticsPlugin を組み込みます。ユーザーからの質問は、Google 検索を行うサブエージェントをツールとして持つエージェントが処理します。 最終的なディレクトリ構成は以下の通りになります。 coffee_agent ディレクトリで AI エージェントを実装していきます。 . ├── coffee_agent │ ├── agent.py │ ├── .env │ └── __init__.py ├── pyproject.toml # 自動で作成 └── uv.lock # 自動で作成 プロジェクトの準備 エージェント開発用のディレクトリでプロジェクトを初期化します。 BigQueryAgentAnalyticsPlugin は google-adk をインストールするだけで併せて利用できます。 # uv プロジェクト初期化 $ uv init --no-readme # パッケージの追加 $ uv add " google-adk>=1.29.0 " エージェント用のパッケージディレクトリ( coffee_agent )を作成し、ADK がエージェントのパッケージとして認識できるように __init__.py を配置します。 # エージェントのパッケージディレクトリを作成 $ mkdir coffee_agent # __init__.py を作成 $ cat <<EOF > coffee_agent/__init__.py from . import agent EOF エージェントのソースコード(agent.py) エージェントのソースコードでは、以下のように BigQueryAgentAnalyticsPlugin を組み込んだエージェントを実装します。 BigQueryAgentAnalyticsPlugin のインスタンスを作成し、ログの記録先となる BigQuery プロジェクト・データセット・ロケーションを指定 root_agent をラップする App オブジェクトを作成し、 plugins 引数にプラグインを登録 ポイントとして、このエージェントを adk deploy コマンドで Agent Engine にデプロイする際に、 root_agent ではなく App オブジェクト( app )をデプロイ対象として指定する必要があります(後述)。この App オブジェクトに plugins を登録しておくことで、デプロイ後のエージェントでプラグインが有効化されます。 import os from google.adk.agents import Agent from google.adk.apps import App from google.adk.plugins.bigquery_agent_analytics_plugin import ( BigQueryAgentAnalyticsPlugin, BigQueryLoggerConfig, ) from google.adk.tools import google_search from google.adk.tools.agent_tool import AgentTool PROJECT_ID = os.environ[ "GOOGLE_CLOUD_PROJECT" ] DATASET_ID = os.environ.get( "BQ_DATASET" , "agent_analytics" ) BQ_LOCATION = os.environ.get( "BQ_LOCATION" , "asia-northeast1" ) # BigQuery Agent Analytics プラグイン bq_analytics_plugin = BigQueryAgentAnalyticsPlugin( project_id=PROJECT_ID, dataset_id=DATASET_ID, location=BQ_LOCATION, config=BigQueryLoggerConfig( batch_size= 1 , batch_flush_interval= 0.5 , log_session_metadata= True , ), ) # Web 検索用サブエージェント search_agent = Agent( name= "search_agent" , model= "gemini-2.5-flash" , description= "Google検索でコーヒーに関する情報を調べるエージェント" , instruction= "ユーザーの質問に対してGoogle検索を使って情報を収集し、日本語で回答してください。" , tools=[google_search], ) # ルートエージェント root_agent = Agent( name= "coffee_agent" , model= "gemini-2.5-flash" , description= "コーヒーに関する情報を収集するエージェント" , instruction= """あなたはコーヒーの専門家アシスタントです。 ユーザーからの質問に対して、search_agentを活用しながらコーヒーに関する正確で有益な情報を提供してください。 対応できるトピックの例: - コーヒー豆の産地・品種・特徴 - 抽出方法(ドリップ、エスプレッソ、フレンチプレスなど) - 焙煎度合いと味わいの違い - カフェやコーヒーショップの情報 - コーヒーの健康効果や歴史 - ラテアートやバリスタの技術 回答は日本語で、わかりやすく丁寧に行ってください。""" , tools=[AgentTool(agent=search_agent)], ) # Agent Engine デプロイ用 App (プラグインを登録) app = App( name= "coffee_agent" , root_agent=root_agent, plugins=[bq_analytics_plugin], ) また、 BigQueryLoggerConfig では動作確認をしやすくするために、 batch_size=1 / batch_flush_interval=0.5 を指定してイベントが即座に BigQuery へ書き込まれるようにしています。 BigQueryLoggerConfig では、このほかにもイベントの記録挙動を細かく制御できます。代表的なものを以下に挙げます。 パラメータ デフォルト 説明 table_id "agent_events" イベントを格納する BigQuery テーブル ID event_allowlist / event_denylist None 記録する / 除外するイベント型のリスト content_formatter None イベントの記録前にフォーマットを行うために使用する関数( 参考 ) gcs_bucket_name None マルチモーダル コンテンツをオフロードする Cloud Storage バケット create_views True イベント型ごとのビューを作成するか view_prefix "v" 自動生成するビュー名のプレフィックス 参考 : BigQuery Agent Analytics plugin for ADK - Configuration options Google Cloud 側の準備 BigQuery データセットの作成 プラグインがイベント記録用のテーブル( agent_events )とビュー( v_llm_request など)を自動で作成するため、あらかじめ格納先のデータセットのみ用意します。データセットのリージョンは、後述する Agent Engine の稼働リージョンと一致させます。 # データセット ID とロケーションを環境変数にセット $ PROJECT_ID = < プロジェクトID > $ DATASET_ID =agent_analytics $ BQ_LOCATION =asia-northeast1 # データセットの作成 $ bq --location = $BQ_LOCATION mk \ --dataset \ --description =" BigQuery Agent Analytics for ADK " \ $PROJECT_ID : $DATASET_ID Agent Engine サービスアカウントへの IAM 付与 Agent Engine にデプロイしたエージェントから BigQuery に書き込みを行うために、Agent Engine のサービスアカウント( service-<プロジェクト番号>@gcp-sa-aiplatform-re.iam.gserviceaccount.com )に対して以下のロールを付与します。 ロール スコープ 用途 BigQuery ジョブユーザー ( roles/bigquery.jobUser ) プロジェクト BigQuery ジョブ(クエリ・書き込み)の実行 BigQuery データ編集者 ( roles/bigquery.dataEditor ) データセット テーブル・ビューの作成、データの書き込み 最小権限の原則に従い、 roles/bigquery.dataEditor はエージェント分析用のデータセットに対してのみ付与します。データセット単位の IAM は SQL の GRANT 文を使って付与します。 # プロジェクト番号の取得 $ PROJECT_NUMBER = $( gcloud projects describe $PROJECT_ID --format =' value(projectNumber) ' ) # Agent Engine 実行サービスアカウント $ RE_SA = " service- ${PROJECT_NUMBER} @gcp-sa-aiplatform-re.iam.gserviceaccount.com " # bigquery.jobUser はプロジェクトレベルで付与 $ gcloud projects add-iam-policy-binding $PROJECT_ID \ --member =" serviceAccount: ${RE_SA} " \ --role =" roles/bigquery.jobUser " # bigquery.dataEditor はデータセットレベルで付与 $ bq query --use_legacy_sql =false \ " GRANT \` roles/bigquery.dataEditor \` ON SCHEMA \` ${PROJECT_ID} \` . ${DATASET_ID} TO 'serviceAccount: ${RE_SA} ' " 当記事では実施しませんが、マルチモーダル コンテンツを Cloud Storage にオフロードする場合は、対象バケットに対して Storage オブジェクト作成者 ( roles/storage.objectCreator )および Storage オブジェクト閲覧者 ( roles/storage.objectViewer )も付与します。 参考 : BigQuery Agent Analytics plugin for ADK - Prerequisites ローカル認証 ローカルから adk web や adk deploy を実行する際の Google Cloud CLI の認証を行っておきます。 # 認証 $ gcloud auth login $ gcloud auth application-default login # プロジェクトの設定 $ gcloud config set project $PROJECT_ID .env ファイルの作成 エージェントの実行時に Vertex AI を利用するための環境変数を、 coffee_agent ディレクトリ配下の .env ファイルに設定します。ADK は adk web や adk deploy の実行時にこのファイルを自動で読み込みます。 # coffee_agent/.env を作成 $ cat <<EOF > coffee_agent/.env GOOGLE_GENAI_USE_VERTEXAI=1 GOOGLE_CLOUD_PROJECT= $PROJECT_ID GOOGLE_CLOUD_LOCATION=asia-northeast1 EOF GOOGLE_GENAI_USE_VERTEXAI : 1 を指定することで、Gemini API ではなく Vertex AI 経由で Gemini モデルを利用します GOOGLE_CLOUD_PROJECT : エージェントをデプロイする Google Cloud プロジェクト ID。 agent.py で BigQuery 出力先プロジェクトとしても参照されます GOOGLE_CLOUD_LOCATION : Agent Engine およびモデルを利用するリージョン ローカルでの動作確認(ADK Web) Agent Engine へのデプロイ前に、ローカルで ADK Web UI を起動してエージェントの動作と BigQuery へのログ記録を確認します。 agent.py に app = App(...) を定義しておくと、 root_agent ではなく app が自動検出され、 plugins で指定されているプラグインを有効化した状態でエージェントが起動します。 # ADK Web UI の起動 $ uv run adk web ブラウザで http://localhost:8000 を開き、チャット UI からエージェントに質問を送ってみます。 ADK Web UI からエージェントにメッセージを送信する BigQuery コンソールで、 agent_events テーブルが自動作成され、イベントが記録されていることを確認します。 SELECT timestamp , event_type, agent, content FROM `<プロジェクトID>.agent_analytics.agent_events` ORDER BY timestamp DESC LIMIT 20 ; エージェントの各種イベントが BigQuery テーブルに記録されている USER_MESSAGE_RECEIVED 、 LLM_REQUEST 、 LLM_RESPONSE 、 AGENT_COMPLETED といったイベントが時系列で記録されていれば、プラグインが正しく動作しています。 また、 agent_events テーブルとあわせて、イベント型ごとのビュー( v_llm_request 、 v_llm_response 、 v_tool_completed など)も自動で作成されており、こちらもデータセット内で確認できます。 イベント型ごとのビューが自動作成されている 参考 : ADK CLI documentation - web Agent Engine へのデプロイ デプロイの実施 Agent Engine にエージェントをデプロイします。プラグインを含めてデプロイするには、 --adk_app_object オプションで App オブジェクトの変数名(ここでは app )を指定する必要があります。このオプションを指定しない場合、デフォルトでは root_agent がデプロイ対象となり、プラグインが適用されません。 # Agent Engine にエージェントをデプロイ $ uv run adk deploy agent_engine \ --project = $PROJECT_ID \ --region = asia-northeast1 \ --display_name =" Coffee Agent with BQ Analytics " \ --adk_app_object = app \ coffee_agent 参考 : ADK CLI documentation - deploy 動作確認 デプロイが完了したら、Agent Engine のコンソール画面( https://console.cloud.google.com/vertex-ai/agents/agent-engines )でデプロイしたエージェントを選択し、チャット UI(Playground)で動作確認を行います。 コンソールのチャット UI で、コーヒーに関する質問を送信してみます。 Agent Engine のコンソールからエージェントにメッセージを送信する ローカル実行時と同様に、BigQuery の agent_events テーブルにイベントが記録されていることを確認します。 Agent Engine にデプロイしたエージェントのイベントが記録されている 自動作成された v_llm_response ビューを使用して、LLM のトークン使用量を集計してみます。以下は全体の平均トークン数を確認するクエリです。 SELECT AVG (usage_total_tokens) AS avg_tokens, AVG (usage_prompt_tokens) AS avg_prompt, AVG (usage_completion_tokens) AS avg_completion FROM `<プロジェクトID>.agent_analytics.v_llm_response`; v_llm_response ビューから平均トークン数を集計する 公式ドキュメントにいくつかのクエリサンプルが紹介されているので、こちらも参照してください。 参考 : BigQuery Agent Analytics plugin for ADK - Advanced analysis queries 佐々木 駿太 (記事一覧) G-gen 最北端、北海道在住のクラウドソリューション部エンジニア 2022年6月に G-gen にジョイン。Google Cloud Partner Top Engineer に選出(2024 / 2025 Fellow / 2026)。好きな Google Cloud プロダクトは Cloud Run。 趣味はコーヒー、小説(SF、ミステリ)、カラオケなど。 Follow @sasashun0805

動画

書籍