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?

Foundryトレースの保存先を4設定で検証してみた

0
Last updated at Posted at 2026-06-21

本記事記述および実装内容は、多くの部分をAIで処理しており、人間チェックは甘いです

Foundryトレースの保存先を4設定で検証してみた

はじめに

Microsoft Foundry Agent Service の Prompt Agent を動かすと、トレース(プロンプト・ツール呼び出し・トークン・レイテンシ)が OpenTelemetry の GenAI セマンティクスで記録されます。ただし「どの設定をしたら、どのデータが、どこ(どのテーブル / どの画面)に入るのか」は意外と分かりにくいです。

そこで本記事では、関数ツールを1つ持つ Prompt Agent を用意し、トレース設定を 4 通りに変えて、保存先テーブルと Portal 画面の見え方の違いを実機で確認しました。

  • 想定読者: Foundry Agent / Application Insights でエージェントを監視したい Azure エンジニア
  • 読むと分かること: サーバサイド / クライアントサイドのトレースの違い、Application Insights のどのテーブルに入るか、Foundry Portal と Azure Portal「Agents (Preview)」での見え方の差

結論

  • トレースは実質すべて dependencies(=AppDependencies)テーブルに入るrequests / traces はほぼ 0 件。サーバ/クライアントは cloud_RoleNameresponsesapi / unknown_service)で見分ける。
  • サーバサイド(App Insights を Foundry に接続)はコード変更ゼロで有効になり、プロンプト・応答の本文まで既定でキャプチャされる。
  • クライアントサイド(AIProjectInstrumentor)は本文を既定で伏せる(redact)。本文を記録するには環境変数の明示 opt-in が必要。
  • ⚠️ configure_azure_monitor を呼ぶ「だけ」では GenAI span が出ない。エージェント観測 UI(Foundry Traces / Azure Agents (Preview))は gen_ai span に依存するため、ほぼ何も映らない。
  • ⚠️ Foundry Portal に出るかどうかは「App Insights をプロジェクトに接続したか」だけで決まる(クライアント計装とは無関係)。

構成

App Insights を 2 つ用意し、保存先を厳密に切り分けました。

  • appi-server: Foundry プロジェクトに接続(サーバサイドトレース受信)
  • appi-client: 未接続。クライアントが接続文字列で export

検証した4パターン

同じ Prompt Agent に「追跡番号の配送状況を教えて」と尋ね、クライアント側のトレース計装だけを変えて 4 通り実行しました。

パターン クライアント設定
A: 1だけ 計装なし(素の Responses 呼び出し)
B: 2だけ configure_azure_monitor のみ
C: 2+3だけ configure_azure_monitor + GenAI 環境変数 + AIProjectInstrumentor
D: 全部 C を接続済み App Insights に export

それぞれのパターンごとのUI上の出力です
image.png

設定2・3 の実体はこれだけです。

run_scenario.py
import os

# 設定3: GenAI トレースを有効化(instrument より前に必須)
os.environ["AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING"] = "true"
# 任意: クライアント側で本文も記録したい場合のみ opt-in
# os.environ["OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT"] = "true"

# 設定2: Azure Monitor へ export
from azure.monitor.opentelemetry import configure_azure_monitor
configure_azure_monitor(connection_string=conn_str)

# 設定3: GenAI 計装を有効化
from azure.ai.projects.telemetry import AIProjectInstrumentor
AIProjectInstrumentor().instrument()

① パターン別「保存先テーブル」の対応

ここが本記事の主役です。どの設定で、どのテーブルに、どんな span が入るかを実測でまとめました(App Insights は workspace-based)。

パターン 出力先 テーブル(cloud_RoleName) 主な span 本文
A 1だけ server(接続) dependencies(responsesapi) invoke_agent, chat(モデル) 込み(既定ON)
B 2だけ client(未接続) dependencies(unknown_service) 汎用のみ(get_package_status 等 InProc / HTTP)、gen_ai なし
C 2+3だけ client(未接続) dependencies(unknown_service) gen_ai 有invoke_agent, create_conversation)+ 汎用 redact(既定OFF)
D 全部 server(接続) dependencies(responsesapi + unknown_service) server + client が相関 込み

ポイント:

  • どのパターンでも トレースは dependencies に集約requests / traces は実質 0、exceptions は IMDS への無害な接続エラーのみ。
  • サーバ(responsesapi) は chat(モデル呼び出し)span まで出る。クライアント gen_ai は invoke_agent 止まり(モデル内部はサーバ側)。

全部出ているDパターンの場合のログとその由来などです。

target type name 由来 備考
unknown AI chat gpt-4o-mini-2024-07-18 A(サーバトレース設定) Chat本文テキストあり(ツール結果での最終回答)
unknown AI invoke_agent ftrace-v2-agent:1 A(サーバトレース設定) Chat本文テキストあり(ツール結果での最終回答)
invoke_agent ftrace-v2-agent Microsoft.CognitiveServices invoke_agent ftrace-v2-agent C(AIProjectInstrumentor) ツール結果での最終回答
get_package_status InProc <ツール名> B(configure_azure_monitor) ツール呼出
unknown AI chat gpt-4o-mini-2024-07-18 A(サーバトレース設定) Chat本文テキストあり(ツール呼出指示)
unknown AI invoke_agent ftrace-v2-agent:1 A(サーバトレース設定) Chat本文テキストあり(ツール呼出指示)
invoke_agent ftrace-v2-agent Microsoft.CognitiveServices invoke_agent ftrace-v2-agent C(AIProjectInstrumentor) ツール呼出指示
169.254.169.254:None HTTP GET /metadata/identity/oauth2/token B(configure_azure_monitor)
create_conversation Microsoft.CognitiveServices create_conversation C(AIProjectInstrumentor)
agent-tracing-scenario InProc agent-tracing-scenario C(AIProjectInstrumentor)
AIProjectClient.get_openai_client InProc AIProjectClient.get_openai_client B(configure_azure_monitor)

Azure Portal の Logs(リソース スコープ)で、サーバ側 App Insights を見ると responsesapi(server)と unknown_service(client)が同じ dependencies に同居しているのが分かります。

▲ サーバ側 App Insights の dependenciesresponsesapi(=サーバサイド) と unknown_service(=クライアント) が同居。requests / traces は出ていない

テーブル名はスコープで変わる

Azure Portal の「App Insights リソース」スコープでは classic 名dependencies / requests / traces / exceptions)。一方、Log Analytics ワークスペース スコープ(LogsQueryClient など)では *AppDependencies / AppRequests / ...** になります。同じデータの別名で、リソース スコープで Appを使うとFailed to resolve table expression` になります。

② UI での「見え方」の違い

同じデータでも、gen_ai span があるかどうかで UI の見え方が大きく変わります。

Foundry Portal: トレース詳細

接続済み(パターン A / D)では、Foundry Portal の Agent → Traces にトレースが並びます。詳細(Trajectories)を開くと、custom span を根に、クライアント invoke_agent → サーバ invoke_agentchat が入れ子で相関し、関数ツール get_package_status の span も確認できます。

▲ トレース詳細:span が相関表示され、ツール呼び出し get_package_status も見える(10 spans / 2 chat calls)

「User view」に切り替えると、プロンプトとモデル応答の本文がそのまま表示されます。サーバサイドが本文を既定キャプチャしている証拠です(本記事の例は架空のテストデータです)。

▲ User view:プロンプト/応答の本文が表示される(サーバサイドは本文を既定保存)

プライバシー注意:サーバサイドトレース(App Insights 接続)を有効にすると、ユーザーのプロンプトとモデル応答の本文が既定で App Insights に保存されます。Log Analytics 読み取り権限を持つ全員が閲覧可能です。本番では RBAC・リテンション・データ最小化を必ず検討してください。

Foundry Portal に出る/出ないの分かれ目は「接続」だけ

ここは間違えやすいポイントです。Foundry Portal の Traces / Monitor に出るかどうかは、App Insights をプロジェクトに「接続」したか(設定1)だけで決まります。クライアント計装(設定2 / 3)とは無関係です。

  • 接続している(A / D) → サーバサイドトレースが出て Foundry Portal に表示。
  • 接続していない(B / C) → いくらクライアントで configure_azure_monitor / AIProjectInstrumentor しても、Foundry Portal は(クライアントのデータは指定した App Insights 側にだけ入る)。

これは「Foundry+App Insights を4セット用意し、各パターンで接続状態を変えた」独立環境で検証しました。未接続プロジェクトの Traces 画面は次のように「接続を促す案内」と「No runs or traces to display」が出るだけです。

▲ 未接続(パターンB / C)の Traces 画面:「Create or connect an App Insights resource to enable tracing」「No runs or traces to display」で空

よくある誤解:「クライアント側で計装したのに Foundry Portal に出ない」は正常です。Foundry Portal は接続済み App Insights のサーバサイドトレースを見ているため、接続していなければ何も出ません。Foundry Portal で見たいなら、まず App Insights をプロジェクトに接続してください。

Foundry Portal: エージェントの Monitor 画面

Foundry Portal の ビルド → エージェント → (エージェント選択)→ Monitor には、エージェント単位の運用ダッシュボードがあります。Estimated costTotal token usage、Agent runs / token のチャートが並びます(Open in Azure Monitor で Azure 側へ遷移可)。

▲ Monitor → Overview:Estimated cost <$0.01 / Total token usage 2.3K、下部に Agent runs / token メトリクス

Tools サブタブには、エージェントに紐づくツール(今回の get_package_status)が並びます。

▲ Monitor → Tools:関数ツール function(=get_package_status)が登録されている

この Monitor も 接続済み(server側)App Insights のサーバサイドトレースを集計しています(Azure Portal「Agents (Preview)」と同じデータソース)。つまり 接続している A / D でのみ数値が出ます。クライアントのみ(B / C)ではここには出ません。

Azure Portal: Agents (Preview)

Azure Portal の App Insights には「調査 → Agents (Preview)」というエージェント運用ダッシュボードがあります。これも gen_ai span を集計します。

接続済み(A / D)のサーバ側では、エージェント実行回数・トークン消費・モデル別メトリクスがしっかり表示されます。

▲ サーバ側 Agents (Preview):エージェント実行 12 回、生成 AI エラー 0、モデル別メトリクスも表示

一方、クライアント側(パターン C)の App Insights を見ると、エージェント実行は出るがモデル/ツールは空になります。クライアント gen_ai span には chat(モデル)span が無いためです。そして gen_ai span を出さないパターン B は、実行回数にすら現れません

▲ クライアント側 Agents (Preview):実行回数は出るが「モデル:クエリは結果を返しません」。パターン B は出てこない

Agents (Preview) は既定の時間範囲が「過去24時間」です。過去のデータを見るときは範囲を広げてください(本検証は「過去7日」)。

パターンD の注意:クライアント/サーバが入れ子で「重複」する

接続済み App Insights にクライアント export も向けるパターン D では、同じエージェント呼び出しが「サーバ層」と「クライアント層」の2つの span として 1 トレースに入れ子で記録されます(先のトレース詳細 portal-05 と同じ構造)。完全コピーではなく、同一操作を2層から観測したものが traceparent で1トレースに相関しています。

トレース内の span 見分け方
invoke_agent <agent>(親) クライアント 版数サフィックス無し
invoke_agent <agent>:1(子) サーバ :1(版数)付き
 └ chat <model> サーバ モデル呼び出し(サーバのみ)

トークンの二重計上に注意

クライアントの invoke_agent とサーバの chat同じトークン値を持ちます(実測で完全一致)。Dの構成で全 gen_ai span を素朴に SUM すると約2倍になります。集計は cloud_RoleName で絞ってください(例:トークンはサーバ chat のみ)。

重複を避けたい本番では、クライアント側で SDK の自動計装を止めて、自前 span だけ残すのが有効です。

dedupe.py
import os
# サーバ側が記録する invoke_agent / chat の再送を止める(自前 span だけ残る)
os.environ["AZURE_TRACING_GEN_AI_INSTRUMENT_RESPONSES_API"] = "false"

from azure.ai.projects.telemetry import AIProjectInstrumentor
AIProjectInstrumentor().instrument()

(A はサーバのみ、B / C はクライアントが別 App Insights なので、この重複は D だけで起きます。)

おまけ:D の dependencies は A + B + C の全レコードが合流する

D(接続ON + クライアント export を接続済み AI へ)の dependencies には、A(サーバ)+ B(クライアント汎用)+ C(クライアント gen_ai)の全レコードが 1 トレースに同居します。代表列(Name / type / cloud_RoleName / 本文の有無)と、何がトリガで、どの画面に使われるかを実測でまとめました。

Name type / role トリガ 本文/応答/Tool I/O 由来 使われる画面
chat <model> AI / responsesapi Foundry サーバが LLM 呼び出し時に自動記録 含む(system/user 本文+tool_call 引数+tool 結果+usage A(設定1) Traces 詳細・User view、Monitor / Agents(Preview) のモデル・トークン
invoke_agent <agent>:1 AI / responsesapi Foundry サーバがエージェント実行時に自動記録(:1=版数) ✅ 本文/応答あり A(設定1) Traces、Agent runs
invoke_agent <agent> CognitiveServices / unknown_service クライアント計装(AIProjectInstrumentor ⚠️ **本文 redact(空)**+usage 有(二重計上注意) C(設定2+3) Traces(入れ子の親)、Agent runs
create_conversation CognitiveServices / unknown_service クライアント計装 ❌ なし C(設定2+3) Traces
agent-tracing-scenario InProc / unknown_service 自前のカスタム span ❌ 属性のみ B(設定2 / 自前) Traces(ルート)
get_package_status InProc / unknown_service @trace_function 付きローカル関数の実行 引数/戻り値も空 B(設定2) Traces(子 span)
AIProjectClient.get_openai_client InProc / unknown_service SDK のクライアント生成 ❌ なし B(設定2) Traces
GET /metadata/identity/oauth2/token HTTP / unknown_service azure-core の HTTP 自動計装(IMDS 認証) ❌ なし(ノイズ) B(設定2) Traces / 通常ノイズ

ポイント:

  • 実テキスト(プロンプト/応答/Tool 入出力)を持つのはサーバ側 responsesapichat / invoke_agent:1 だけ。例:chatgen_ai.output.messages{"type":"tool_call","name":"get_package_status","arguments":{"tracking_id":"..."}}
  • クライアント gen_ai は redact(構造のみ)クライアント InProc/HTTP は内容ゼロ(ローカルツール実行 get_package_status ですら引数/戻り値は空)。
  • つまり D = A の server span + B の汎用 client span + C の gen_ai client span の合流。由来は「設定1=サーバ / 設定2=汎用 client / 設定2+3=gen_ai client」で切り分けられます。

ハマりポイント

configure_azure_monitor を呼んだのに Agent のトレースが Portal に出ない

configure_azure_monitor(設定2)だけでは、HTTP / InProc の汎用 span しか出ず、invoke_agent などの GenAI span は生成されません。さらに App Insights を接続していなければ Foundry Portal には何も出ません(接続が前提)。

原因: GenAI 計装はプレビューのため明示 opt-in が必要。

解決策: AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING=true を設定したうえで AIProjectInstrumentor().instrument() を呼ぶ(=設定3)。これで初めて invoke_agent / create_conversation などの gen_ai span が出ます。

fix.py
# NG: これだけでは gen_ai span が出ない
configure_azure_monitor(connection_string=conn_str)

# OK: GenAI 計装を opt-in してから instrument
import os
os.environ["AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING"] = "true"
from azure.ai.projects.telemetry import AIProjectInstrumentor
AIProjectInstrumentor().instrument()
本文キャプチャの有無を切り替えるには
  • サーバサイド(接続): 既定で本文込み。
  • クライアントサイド: 既定で redact。本文も記録したい場合のみ OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true を設定(開発環境限定推奨)。

まとめ

観点 サーバサイド(設定1) クライアントサイド(設定2+3)
有効化 App Insights 接続のみ(コード不要) configure_azure_monitor + GenAI env + AIProjectInstrumentor
cloud_RoleName responsesapi unknown_service
粒度 invoke_agent + chat(モデル)まで invoke_agent まで
本文キャプチャ 既定 ON 既定 OFF(redact)
Foundry Portal 表示 される(接続が条件) されない(接続しない限り)
  • トレースの保存先は実質 dependencies の一択。サーバ/クライアントは cloud_RoleName で切り分ける。
  • エージェント観測 UI は gen_ai span 依存。「configure_azure_monitor だけ」では機能しない。
  • Foundry Portal の可視性は「接続(設定1)」だけで決まる。クライアント計装をいくらしても、未接続なら Foundry Portal は空。
  • サーバサイドは本文を既定保存するので、プライバシー設計を忘れずに。

参考リンク

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?