Microsoft Foundry Agent Tracing 検証
1. 概要
Microsoft Foundry の Agent Tracing 機能を包括的に検証した。4つのトレーシングオプションを同一条件で実行し、セットアップの容易さ・取得データ・パフォーマンス・ユースケース適合性を比較分析した。
| 項目 | 内容 |
|---|---|
| 検証日 | 2026-04-27 |
| リージョン | East US |
| モデル | gpt-4.1-nano (GlobalStandard, 50K TPM) |
| SDK バージョン | azure-ai-projects 2.1.0, opentelemetry 1.40.0 |
| IaC | Bicep (API version 2025-06-01) |
使用 Python パッケージ
| パッケージ | バージョン | 用途 |
|---|---|---|
azure-ai-projects |
2.1.0 | Foundry Project クライアント |
azure-ai-agents |
1.1.0 | Agent 操作 |
azure-identity |
1.25.3 | Azure 認証 (DefaultAzureCredential) |
azure-core |
1.39.0 | Azure SDK 共通基盤 |
azure-core-tracing-opentelemetry |
1.0.0b12 | Azure SDK ↔ OTel ブリッジ |
azure-monitor-opentelemetry |
1.8.7 | Azure Monitor エクスポーター (Option A) |
azure-monitor-opentelemetry-exporter |
1.0.0b51 | App Insights テレメトリ送信 |
opentelemetry-api |
1.40.0 | OTel API |
opentelemetry-sdk |
1.40.0 | OTel SDK (TracerProvider, SpanProcessor) |
opentelemetry-semantic-conventions |
0.61b0 | GenAI セマンティック属性定義 |
opentelemetry-exporter-otlp-proto-http |
1.40.0 | OTLP HTTP エクスポーター (Option D) |
opentelemetry-resource-detector-azure |
0.1.5 | Azure リソース検出 |
python-dotenv |
1.2.2 | .env ファイル読込 |
2. インフラストラクチャ構成
2.1 Bicep で作成したリソース
┌─────────────────────────────────────────────────┐
│ Resource Group: rg-foundry-tracing-verify │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ AI Services (S0) │ │
│ │ └─ Project: proj-tracing-verify │ │
│ │ └─ Model: gpt-4.1-nano (GlobalStandard) │ │
│ ├─────────────────────────────────────────────┤ │
│ │ Log Analytics Workspace │ │
│ ├─────────────────────────────────────────────┤ │
│ │ Application Insights │ │
│ │ (linked to Log Analytics) │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
2.2 IaC の留意点
| 課題 | 詳細 |
|---|---|
| API バージョン |
2025-06-01 が必須。2024-10-01 では accounts/projects リソースタイプが未対応 |
| Project 作成 | REST API 経由では "identity": {"type": "SystemAssigned"} が必須(省略すると InternalServerError) |
| allowProjectManagement | AI Services アカウントに allowProjectManagement: true が必要 |
3. トレーシングオプション比較
3.1 検証した4オプション
| Option | エクスポーター | 送信先 | 主なユースケース |
|---|---|---|---|
| A: Azure Monitor | configure_azure_monitor() |
Application Insights | 本番運用・長期モニタリング |
| B: Console | ConsoleSpanExporter |
標準出力 (stdout) | 開発・デバッグ |
| C: Custom Attributes | Console + SpanProcessor
|
標準出力 + カスタムメタデータ | A/Bテスト・実験管理 |
| D: OTLP | OTLPSpanExporter |
OpenTelemetry Collector | 既存OTelインフラ統合 |
3.2 セットアップ比較
セットアップ難易度(低い = 簡単)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Option A ██░░░░░░░░ 低 (configure_azure_monitor 1行)
Option B ███░░░░░░░ 低 (TracerProvider + Exporter設定)
Option C █████░░░░░ 中 (SpanProcessor自作が必要)
Option D ████████░░ 高 (外部Collector構築が前提)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
3.3 必要なパッケージ
| Option | 追加パッケージ |
|---|---|
| A | azure-monitor-opentelemetry |
| B |
opentelemetry-sdk (azure-ai-projects に付属) |
| C |
opentelemetry-sdk (同上) |
| D |
opentelemetry-exporter-otlp + 外部 Collector |
3.4 コア設定コード
共通(全オプション必須):
import os
os.environ["AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING"] = "true"
# ↑ GenAI セマンティック属性のキャプチャに必須
Option A – Azure Monitor:
from azure.monitor.opentelemetry import configure_azure_monitor
conn_str = project_client.telemetry.get_application_insights_connection_string()
configure_azure_monitor(connection_string=conn_str)
Option B – Console:
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor, ConsoleSpanExporter
from azure.ai.projects.telemetry import AIProjectInstrumentor
from azure.ai.inference.tracing import AIInferenceInstrumentor
provider = TracerProvider()
provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
trace.set_tracer_provider(provider)
AIProjectInstrumentor().instrument()
AIInferenceInstrumentor().instrument()
Option C – Custom Attributes:
class CustomAttributeSpanProcessor(SpanProcessor):
def __init__(self, attributes: dict):
self.attributes = attributes
def on_start(self, span, parent_context=None):
for k, v in self.attributes.items():
span.set_attribute(k, v)
provider.add_span_processor(CustomAttributeSpanProcessor({
"custom.experiment_name": "tracing-comparison",
"custom.option": "C",
"custom.environment": "verification",
}))
4. パフォーマンス比較
4.1 レイテンシ測定結果
同一の3プロンプトを各オプションで実行(gpt-4.1-nano, 同一 Agent 設定):
| プロンプト | Option A (Azure Monitor) | Option B (Console) | Option C (Custom Attrs) | Option D (OTLP)* |
|---|---|---|---|---|
| 日本の首都は? | 2.86s | 1.78s | 2.82s | 9.61s |
| Pythonソート方法 | 1.92s | 1.60s | 1.58s | 10.59s |
| 吾輩は猫である著者 | 1.90s | 1.42s | 1.44s | 9.36s |
| 平均 | 2.23s | 1.60s | 1.95s | 9.85s |
*Option D はローカルに OTLP Collector が不在のためエクスポートリトライが発生し、大幅に遅延。Collector が正常稼働していれば Option B と同等のレイテンシが期待される。
平均レイテンシ (秒) — 低いほど高速
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Option A ██████░░░░░░░░░░░░░░░░░░ 2.23s
Option B ████░░░░░░░░░░░░░░░░░░░░ 1.60s ← 最速
Option C █████░░░░░░░░░░░░░░░░░░░ 1.95s
Option D ████████████████████████ 9.85s ← Collector不在による遅延
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
注意: 初回リクエストはコールドスタートの影響で遅い傾向(全オプション共通)。2回目以降はほぼ同等。Azure Monitor の若干のオーバーヘッドは、テレメトリのバッファリング・エクスポート処理に起因する。Option D の遅延はエクスポーターのリトライタイムアウトに起因し、Collector 正常稼働時には発生しない。
4.2 コンテンツ記録の影響
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT 環境変数の ON/OFF での比較:
| 設定 | Prompt 1 | Prompt 2 | Prompt 3 | 平均 |
|---|---|---|---|---|
| OFF (デフォルト) | 1.78s | 1.60s | 1.42s | 1.60s |
| ON | 2.83s | 1.62s | 1.48s | 1.98s |
→ コンテンツ記録 ON でもレイテンシへの影響は軽微(初回のみやや遅い)。
5. 取得データ比較
5.1 キャプチャされるスパン
全オプション共通で 11スパン が生成された(3プロンプト実行時):
| スパン名 | 種別 | 説明 |
|---|---|---|
option_X_tracing |
Root | 実行全体の親スパン |
AIProjectClient.get_openai_client |
Internal | OpenAI クライアント取得 |
create_agent TracingTestAgent-X |
Internal | Agent 作成 |
create_conversation |
Internal | 会話作成 |
invoke_agent TracingTestAgent-X (×3) |
Internal | Agent 呼出(プロンプトごと) |
AgentsOperations.delete_version |
Internal | Agent 削除 |
GET / POST / DELETE
|
HTTP | 実際の HTTP リクエスト |
5.2 GenAI セマンティック属性
invoke_agent スパンにキャプチャされる OTel GenAI 属性:
| 属性 | 説明 | Content OFF | Content ON |
|---|---|---|---|
gen_ai.operation.name |
操作名 | ✅ | ✅ |
gen_ai.agent.id |
Agent ID | ✅ | ✅ |
gen_ai.agent.name |
Agent 名 | ✅ | ✅ |
gen_ai.agent.type |
Agent タイプ (prompt) | ✅ | ✅ |
gen_ai.agent.version |
Agent バージョン | ✅ | ✅ |
gen_ai.conversation.id |
会話 ID | ✅ | ✅ |
gen_ai.provider.name |
プロバイダー名 | ✅ | ✅ |
gen_ai.request.model |
リクエストモデル | ✅ | ✅ |
gen_ai.response.model |
レスポンスモデル | ✅ | ✅ |
gen_ai.response.id |
レスポンス ID | ✅ | ✅ |
gen_ai.usage.input_tokens |
入力トークン数 | ✅ | ✅ |
gen_ai.usage.output_tokens |
出力トークン数 | ✅ | ✅ |
gen_ai.system_instructions |
システム指示内容 | ❌ | ✅ |
gen_ai.input.messages |
入力メッセージ内容 | 構造のみ* | ✅ 全文 |
gen_ai.output.messages |
出力メッセージ内容 | 構造のみ* | ✅ 全文 |
server.address |
サーバーアドレス | ✅ | ✅ |
az.namespace |
Azure namespace | ✅ | ✅ |
az.client_request_id |
クライアントリクエストID | ✅ | ✅ |
*「構造のみ」=
{"role": "user", "parts": [{"type": "text"}]}のようにロール・タイプのみ、内容テキストは空
5.3 コンテンツ記録 ON/OFF の出力差異
Content OFF (デフォルト — プライバシー保護):
{
"gen_ai.input.messages": "[{\"role\": \"user\", \"parts\": [{\"type\": \"text\"}]}]",
"gen_ai.output.messages": "[{\"role\": \"assistant\", \"parts\": [{\"type\": \"text\"}], \"finish_reason\": \"completed\"}]"
}
Content ON (OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true):
{
"gen_ai.system_instructions": "[{\"type\": \"text\", \"content\": \"あなたは日本語で簡潔に答えるアシスタントです。\"}]",
"gen_ai.input.messages": "[{\"role\": \"user\", \"parts\": [{\"type\": \"text\", \"content\": \"日本の首都はどこですか?\"}]}]",
"gen_ai.output.messages": "[{\"role\": \"assistant\", \"parts\": [{\"type\": \"text\", \"content\": \"東京です。\"}], \"finish_reason\": \"completed\"}]"
}
5.4 Option C: カスタム属性
Option C では、全スパンに以下のカスタム属性が自動付与された:
{
"custom.experiment_name": "tracing-comparison",
"custom.option": "C",
"custom.environment": "verification"
}
これにより、A/Bテスト・実験管理・マルチ環境でのトレース分類が可能。
6. Option D: OTLP エクスポーター
6.1 構成
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
exporter = OTLPSpanExporter(endpoint="http://localhost:4318/v1/traces")
6.2 検証結果
Agent 呼出自体は成功(3プロンプトとも正常応答)。ただし、ローカルに OTLP Collector が稼働していないため、エクスポーターがリトライを繰り返し、以下の影響が確認された:
| 項目 | 結果 |
|---|---|
| Agent 呼出 | ✅ 成功(3/3 プロンプト正常応答) |
| トレースエクスポート | ❌ 失敗(Connection refused on localhost:4318) |
| 平均レイテンシ | 9.85s(Collector 不在によるリトライタイムアウト込み) |
| エラーメッセージ | Failed to export span batch due to timeout, max retries or shutdown |
重要な発見: OTLP エクスポーターの接続失敗はアプリケーション全体をブロックしない(Agent 呼出は正常完了)。ただし、リトライ処理がバックグラウンドで走り続けるため、レイテンシに大きな影響を与える。本番環境では Collector のヘルスチェックが重要。
6.3 OTLP が適するケース
- Jaeger / Zipkin / Grafana Tempo など既存の分散トレーシング基盤がある場合
- マルチクラウド・マルチサービスで統一的にトレースを収集する場合
- Azure Monitor 以外のバックエンドにトレースを送信したい場合
6.4 OTLP 構築時の推奨
# OpenTelemetry Collector を Docker で起動する例
docker run -p 4318:4318 otel/opentelemetry-collector-contrib:latest
7. Application Insights でのトレース確認
7.1 収集されたデータ概要
Option A (Azure Monitor) で送信されたトレースを App Insights から KQL で確認した:
| テレメトリタイプ | 件数 |
|---|---|
| dependency | 29 |
7.2 invoke_agent スパンの詳細(App Insights customDimensions)
App Insights の dependencies テーブルには GenAI 属性が customDimensions として格納される:
┌───────────────────────────────────────────────────────────────────────┐
│ invoke_agent TracingTestAgent-A (duration: 2861ms) │
├───────────────────────────────────────────────────────────────────────┤
│ az.namespace : Microsoft.CognitiveServices │
│ gen_ai.operation.name : invoke_agent │
│ gen_ai.agent.id : TracingTestAgent-A:1 │
│ gen_ai.agent.name : TracingTestAgent-A │
│ gen_ai.conversation.id : conv_dadec4c95b0c760a00dCmappe... │
│ gen_ai.provider.name : microsoft.foundry │
│ gen_ai.response.model : gpt-41-nano │
│ gen_ai.usage.input_tokens : 44 │
│ gen_ai.usage.output_tokens: 4 │
│ gen_ai.input.messages : [{"role":"user","parts":[{"type":"text"}]}]│
│ gen_ai.output.messages : [{"role":"assistant",...}] │
│ gen_ai.response.id : resp_dadec4c95b0c760a... │
└───────────────────────────────────────────────────────────────────────┘
7.3 App Insights での分析用 KQL サンプル
// Agent 呼出のレイテンシ分布
dependencies
| where name startswith "invoke_agent"
| summarize avg(duration), percentile(duration, 50), percentile(duration, 95) by name
// トークン使用量の集計
dependencies
| where name startswith "invoke_agent"
| extend input_tokens = toint(customDimensions["gen_ai.usage.input_tokens"]),
output_tokens = toint(customDimensions["gen_ai.usage.output_tokens"])
| summarize sum(input_tokens), sum(output_tokens), count() by bin(timestamp, 1h)
// エラー率の監視
dependencies
| where customDimensions["az.namespace"] == "Microsoft.CognitiveServices"
| summarize total = count(), failures = countif(success == false) by bin(timestamp, 1h)
| extend error_rate = round(100.0 * failures / total, 2)
// Agent 別のパフォーマンス比較
dependencies
| where name startswith "invoke_agent"
| extend agent_name = tostring(customDimensions["gen_ai.agent.name"])
| summarize avg(duration), count() by agent_name
8. 総合比較表
| 評価項目 | Option A (Azure Monitor) | Option B (Console) | Option C (Custom Attrs) | Option D (OTLP) |
|---|---|---|---|---|
| セットアップ難易度 | ⭐ 最も簡単 | ⭐⭐ 簡単 | ⭐⭐⭐ やや複雑 | ⭐⭐⭐⭐ 複雑 |
| 外部依存 | App Insights | なし | なし | OTel Collector |
| 追加パッケージ | azure-monitor-opentelemetry | なし (組込み) | なし (組込み) | opentelemetry-exporter-otlp |
| 平均レイテンシ | 2.23s | 1.60s | 1.95s | 9.85s* |
| オーバーヘッド | 軽微(バッチ送信) | 最小 | 最小 | Collector依存* |
| データ永続化 | ✅ App Insights | ❌ 揮発性 | ❌ 揮発性 | ✅ 外部バックエンド |
| KQL クエリ | ✅ 対応 | ❌ | ❌ | バックエンド依存 |
| カスタムメタデータ | SpanProcessor追加で可 | SpanProcessor追加で可 | ✅ 標準対応 | SpanProcessor追加で可 |
| GenAI 属性数 | 18 | 18 | 18 + カスタム | 18 |
| 本番適合性 | ⭐⭐⭐⭐⭐ | ⭐ | ⭐⭐ | ⭐⭐⭐⭐ |
*Option D のレイテンシは Collector 不在時の値。Collector 正常稼働時は Option B と同等が期待される。
9. 環境変数リファレンス
| 環境変数 | 必須 | 説明 |
|---|---|---|
AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING |
✅ |
true に設定すると GenAI セマンティック属性がキャプチャされる |
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT |
true でメッセージ内容を完全記録(プライバシー注意) |
|
AZURE_IDENTITY_DISABLE_MANAGED_IDENTITY |
WSL 等 IMDS なし環境で true に設定(タイムアウト回避) |
10. 推奨ガイドライン
用途別の推奨オプション
ユースケース → 推奨オプション
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
本番運用・長期モニタリング → Option A (Azure Monitor)
ローカル開発・デバッグ → Option B (Console)
A/Bテスト・実験管理 → Option C (Custom Attributes)
既存OTelインフラ統合 → Option D (OTLP)
本番 + カスタムメタデータ → Option A + C (組合せ)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
10.1 本番環境
推奨: Option A (Azure Monitor) + Option C のカスタム属性
# 本番推奨構成
configure_azure_monitor(connection_string=conn_str)
# カスタム属性も追加
provider = trace.get_tracer_provider()
provider.add_span_processor(CustomAttributeSpanProcessor({
"custom.environment": "production",
"custom.version": "1.0.0",
}))
- App Insights でのダッシュボード・アラート設定が可能
- KQL でトレースを詳細分析
- カスタム属性でデプロイメント・バージョン追跡
10.2 開発環境
推奨: Option B (Console)
- 追加インフラ不要、即座にスパン情報を確認
-
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=trueを設定して入出力内容もデバッグ
10.3 コンテンツ記録の判断
| 環境 | 推奨設定 | 理由 |
|---|---|---|
| 開発・検証 | CAPTURE_MESSAGE_CONTENT=true |
デバッグに入出力内容が必要 |
| 本番(社内データ) | 要件に応じて判断 | トレースに機密データが含まれる可能性 |
| 本番(顧客データ) | CAPTURE_MESSAGE_CONTENT=false |
PII/プライバシー保護が最優先 |
11. IaC コード
Bicep テンプレート: iac/main.bicep
デプロイコマンド:
az group create --name rg-foundry-tracing-verify --location eastus \
--tags SecurityControl=Ignore
az deployment group create \
--resource-group rg-foundry-tracing-verify \
--template-file iac/main.bicep
12. 検証で発見した課題と対策
| 課題 | 影響 | 対策 |
|---|---|---|
| Bicep Project 作成の制限 |
accounts/projects が InternalServerError |
REST API で identity.type=SystemAssigned 指定で回避 |
| OTLP Collector 必須 | ローカル環境で Option D 実行不可 | Docker で Collector を事前構築、または Azure Monitor に統一 |
| コンテンツ記録のデフォルト OFF | 開発時にメッセージ内容が見えない | 開発環境で明示的に CAPTURE_MESSAGE_CONTENT=true 設定 |
13. 結論
Microsoft Foundry の Agent Tracing は、OpenTelemetry 標準に準拠した柔軟なトレーシング基盤を提供する。
- 最小構成でも18のGenAI属性が自動キャプチャされ、トークン使用量・レイテンシ・Agent メタデータの可視化が可能
- Azure Monitor (Option A) は本番環境に最適。1行の設定で App Insights への永続化・KQL 分析・アラートが実現
- Console (Option B) は開発時の即座のフィードバックに最適。追加インフラ不要
- Custom Attributes (Option C) は実験管理・A/Bテストに有効。SpanProcessor の自作は容易
- コンテンツ記録オプションは強力だが、本番ではプライバシーポリシーに従って慎重に設定すべき
- オプションは組合せ可能 — 例えば Azure Monitor + Custom Attributes で本番運用しつつ実験メタデータも記録できる