デプロイされたエージェントとモデルの相互作用を評価する

Important

この記事で "(プレビュー)" と付記されている項目は、現在、パブリック プレビュー段階です。 このプレビューはサービス レベル アグリーメントなしで提供されており、運用環境ではお勧めしません。 特定の機能がサポートされていないか、機能が制限されている可能性があります。 詳細については、「 Microsoft Azure プレビューの追加使用条件」を参照してください。

元の要求を再生せずに、デプロイされたエージェントとモデルから格納された応答または OpenTelemetry トレースを評価します。

前提条件

  • クラウド評価の前提条件とクライアントのセットアップを完了します。
  • 応答評価用に格納された応答 ID、またはトレース評価のために Foundry プロジェクトに接続されている Application Insights リソース。
  • トレースを評価するときにトレース データの要件を満たす OpenTelemetry スパン。

この例では、「SDK クライアントのセットアップ」で構成された SDK クライアントを使用します

応答 ID で対話を評価する

azure_ai_responses データ ソースの種類を使用して、応答 ID によって Foundry エージェントの応答を取得および評価します。 このシナリオを使用して、特定のエージェントの相互作用が発生した後で評価します。

ヒント

開始する前に、 クライアントのセットアップを完了します。

応答 ID は、Foundry エージェントが応答を生成するたびに返される一意の識別子です。 応答 API を使用して、またはアプリケーションのトレース ログから、エージェントの対話から応答 ID を収集できます。 ファイル コンテンツとして ID をインラインで指定します。

Important

エージェント応答評価 (azure_ai_responses) では、応答 ID を提供するための file_content のみがサポートされます。 file_idソースの種類はサポートされておらず、400 Bad Request エラーが返されます。

応答 ID を収集する

Responses API を呼び出すたびに、一意の id フィールドを持つ応答オブジェクトが返されます。 アプリケーションの対話からこれらの ID を収集するか、直接生成します。

# Generate response IDs by calling a model through the Responses API
response = openai_client.responses.create(
    model=model_deployment_name,
    input="What is machine learning?",
)
print(response.id)  # Example: resp_abc123

また、アプリケーションのトレース ログまたは監視パイプラインのエージェント操作から応答 ID を収集することもできます。 各応答 ID は、評価サービスが取得できる格納された応答を一意に識別します。

評価を作成して実行する

from azure.ai.projects.models import TestingCriterionAzureAIEvaluator

data_source_config = {"type": "azure_ai_source", "scenario": "responses"}

testing_criteria = [
    TestingCriterionAzureAIEvaluator(
        type="azure_ai_evaluator",
        name="coherence",
        evaluator_name="builtin.coherence",
        initialization_parameters={"model": model_deployment_name},
    ),
    TestingCriterionAzureAIEvaluator(
        type="azure_ai_evaluator",
        name="violence",
        evaluator_name="builtin.violence",
    ),
]

eval_object = openai_client.evals.create(
    name="Agent Response Evaluation",
    data_source_config=data_source_config,
    testing_criteria=testing_criteria,
)

data_source = {
    "type": "azure_ai_responses",
    "item_generation_params": {
        "type": "response_retrieval",
        "data_mapping": {"response_id": "{{item.resp_id}}"},
        "source": {
            "type": "file_content",
            "content": [
                {"item": {"resp_id": "resp_abc123"}},
                {"item": {"resp_id": "resp_def456"}},
            ]
        },
    },
}

eval_run = openai_client.evals.runs.create(
    eval_id=eval_object.id,
    name="agent-response-evaluation",
    data_source=data_source,
)

実行可能な完全な例については、GitHubの sample_agent_response_evaluation.py を参照してください。 完了するまでポーリングして結果を解釈するには、「クラウド評価結果を取得する」を参照してください。

トレースの評価 (プレビュー)

Application Insights によって既にキャプチャされたエージェントの相互作用を評価します。 azure_ai_traces データ ソースの種類を使用します。 このシナリオは、実稼働トラフィックのデプロイ後の評価に役立ちます。 監視パイプラインからトレースを選択し、リクエストを再生することなく、それらに対して評価を実行できます。

Important

トレース評価は、LangChain やカスタム フレームワークなど、Microsoft Foundry Agent Service でビルドされていないagent を評価する場合に推奨されるアプローチです。 エージェントが、GenAI のセマンティック規約に従う OpenTelemetry スパンを Application Insights に送信している限り、トレース評価では、Foundry エージェントで利用できるものと同じ評価器を使用して、そのやり取りを評価できます。

トレース評価では、次の 2 つのモードがサポートされます。

  • トレース ID による - Application Insights から operation_Id 値を指定して、特定のエージェントの相互作用を評価します。
  • エージェント フィルターによる - トレース ID を手動で収集することなく、特定のエージェントの最近のトレースを自動的に検出して評価します。

ヒント

開始する前に、 クライアントのセットアップを完了します。 このシナリオでは、 Foundry プロジェクトに接続されている Application Insights リソースも必要です。

インテリジェント サンプリング

トレース評価では、インテリジェント サンプリングがサポートされています。これは、キャプチャされたすべてのトレースを評価する代わりに、評価のためにトレースの代表的なサブセットを選択します。 トレース評価の実行を構成するときに、Foundry ポータルで インテリジェント サンプリング トグルをオンにします。 インテリジェント サンプリングを使用すると、トレースの多様性を維持しながら評価コストを削減できます。これにより、エッジ ケース、エラー パス、および多様な会話パターンが評価セットに確実に含まれます。

インテリジェント サンプリングのしくみ

サンプリング アルゴリズムでは、複数のステージで実行される MinHash の最も遠い最初の多様性アプローチが使用されます。

  1. 正確な重複除去 - 重複するトレースをプールから削除します。
  2. ハード フィルター - 破損したセッション、切り捨てられたトレース、および評価に適さない形式のツール呼び出しを削除します。
  3. 集計 - トレース レベルのシグナルを統合された表現に結合します。
  4. MinHash の最も遠い最初の選択 - ユーザー テキストの局所性に依存するハッシュ (MinHash シグネチャ) を計算してトレース間の類似性を推定し、残りのプールから最も類似していないトレースを繰り返し選択します。 次に選択される各トレースは、それまでに選択されたすべてのトレースからの距離が最大になるように選ばれます。

このアプローチでは、ランダム サンプリングと比較して、字句の多様性が大幅に高くなり、ボキャブラリカバレッジが広がります。つまり、評価されたセットは、ランダム サンプリングが見逃されがちなまれなケース、ハードケース、新しいケースなど、エージェントの相互作用の全範囲をより適切に表します。

インテリジェント サンプリングは、次の場合に特に有効です。

  • 評価とベンチマーク - 入力分布のカバレッジを最大化し、評価スコアが実際の多様性を反映します。
  • ルーブリック生成 - 多様な会話パターンを公開することで、より集中して実用的なルーブリックを生成します。
  • データセットキュレーションの微調整 - モデルの学習効率を高めるのに役立つトレースを選択します。

このアルゴリズムは、追加の API 呼び出しなしでローカル コンピューティング上で完全に実行されるため、評価自体を超える追加のモデル推論コストは発生しません。

インテリジェント サンプリングの例

# Eval group for trace-based evaluations
data_source_config = {
    "type": "azure_ai_source",
    "scenario": "traces",
}

print("Creating trace-based evaluation group")
eval_object = client.evals.create(
    name="Trace Evaluation (Agent Smart Filter)",
    data_source_config=data_source_config,  # type: ignore
    testing_criteria=testing_criteria,
)
print(f"Evaluation created (id: {eval_object.id})")

# Compute time window in unix seconds
# Pad end_time by +600s (10 min) to avoid ingestion-delay edge exclusion
now_unix = int(time.time())
end_time = now_unix + 600
start_time = now_unix - (args.lookback_hours * 3600)

# Build trace_source based on mode
trace_source: dict = {
    "type": "agent_filter",
    "start_time": start_time,
    "end_time": end_time,
    "max_traces": args.max_traces,
    "filter_strategy": "smart_filtering"
}

# Add agent name/version or agent id
trace_source["agent_name"] = agent_name
trace_source["agent_version"] = agent_version
## trace_source["agent_id"] = args.agent_id

data_source = {
    "type": "azure_ai_trace_data_source_preview",
    "trace_source": trace_source,
}

eval_run = client.evals.runs.create(
    eval_id=eval_object.id,
    name="trace-evaluation-agent-smart-filter-run",
    data_source=data_source,  # type: ignore
)

トレース データの要件

トレース評価では、エージェントが 生成 AI の OpenTelemetry セマンティック規則に従うスパンを出力する必要があります。 具体的には、評価サービスは Application Insights から invoke_agent スパン を読み取り、その属性から会話データを抽出します。

次のスパン属性が使用されます。

Attribute 必須 Description
gen_ai.operation.name Yes "invoke_agent"と等しい必要があります。 サービスは、他のすべてのスパンを無視します。
gen_ai.agent.id エージェント フィルター モードの場合 一意のエージェント識別子 (形式: agent-name:version)。
gen_ai.agent.name エージェント フィルター モードの場合 人間が読みやすいエージェント名。
gen_ai.input.messages エバリュエーターのクエリ入力の場合 GenAI セマンティック規則メッセージ形式に従った入力メッセージの JSON 配列。 ロール user または system を持つメッセージは、 queryにマップされます。 ロール assistant または tool を持つメッセージは、 responseにマップされます。
gen_ai.output.messages エバリュエーターのクエリ入力の場合 モデルによって生成された出力メッセージの JSON 配列。 すべての出力メッセージが responseにマップされます。 出力に type: tool_call または type: tool_resultも含まれている場合は、 tool_callsにマップされます。
gen_ai.tool.definitions オプション エージェントで使用できるツール スキーマの JSON 配列。 存在しない場合、サービスはツール呼び出しメッセージからツール定義を推論しようとしますが、推論されたスキーマが不完全である可能性があります。
gen_ai.conversation.id オプション 相関関係のために評価結果に渡される会話識別子。

Note

gen_ai.input.messagesgen_ai.output.messagesが空または不足している場合、品質エバリュエーター (コヒーレンス、流暢さ、関連性、意図の解決) はscore=Noneを返します。 安全評価者 (暴力、自傷行為、性的、嫌悪、不公平) は、部分的なデータでスコアを生成できますが、意味のある結果が得られない可能性があります。

Azure AI Agent Server SDK を使用して構築されたPythonエージェントの場合は、[tracing] を追加して、自動スパンエミッションを有効にします。

pip install "azure-ai-agentserver-core[tracing]"

トレース評価の前提条件

トレースの評価には、一般的な 前提条件に加えて、次のものが必要です。

  • Foundry プロジェクトに接続されている Application Insights リソース 。 「Microsoft Foundry でトレースを設定する」を参照してください。
  • プロジェクトのマネージド ID には、Application Insights リソースとそのリンクされた Log Analytics ワークスペースの両方で、Log Analytics 閲覧者 ロールが必要です。 トレースを格納するテーブルが 保護されている 場合 (保護レベルが Protected に設定されている場合)、サービスが 保護されたトレース テーブルを読み取ることができるように、同じスコープで 特権監視データ閲覧者 ロールも割り当てます。
  • azure-monitor-query Python パッケージ (トレース ID を手動で収集する場合にのみ必要)。
pip install "azure-ai-projects>=2.2.0" azure-monitor-query

次の環境変数を設定します。

  • APPINSIGHTS_RESOURCE_ID — Application Insights リソース ID (例: /subscriptions/<subscription_id>/resourceGroups/<rg_name>/providers/Microsoft.Insights/components/<resource_name>)。
  • AGENT_ID — トレースのフィルター処理に使用されるトレース統合 (gen_ai.agent.id 属性) によって出力されるエージェント識別子。 形式: agent-name:version
  • TRACE_LOOKBACK_HOURS — (省略可能) トレースのクエリを実行するときに振り返る時間数。 既定値は 1 です。

オプション A: エージェント フィルターによる評価

最も簡単な方法は、サービスが特定のエージェントの最近のトレースを自動的に検出して評価できるようにすることです。 トレース ID を手動で収集する必要はありません。

import os

agent_id = os.environ["AGENT_ID"]  # e.g., "my-weather-agent:1"
trace_lookback_hours = int(os.environ.get("TRACE_LOOKBACK_HOURS", "1"))

# Create the evaluation
data_source_config = {
    "type": "azure_ai_source",
    "scenario": "traces",
}

eval_object = openai_client.evals.create(
    name="Agent Trace Evaluation (by agent)",
    data_source_config=data_source_config,
    testing_criteria=testing_criteria,  # See "Set up evaluators" below
)

# Create a run — the service queries App Insights for matching traces
data_source = {
    "type": "azure_ai_traces",
    "agent_id": agent_id,
    "max_traces": 50,           # Maximum number of traces to evaluate
    "lookback_hours": trace_lookback_hours,
}

eval_run = openai_client.evals.runs.create(
    eval_id=eval_object.id,
    name="agent-trace-eval-run",
    data_source=data_source,
)

print(f"Evaluation run started: {eval_run.id}")

サービスはinvoke_agentgen_ai.agent.id属性でスパンをフィルター処理し、最大max_traces一意のトレース ID をサンプリングし、それらのトレースからのすべてのスパンを評価します。

オプション B: トレース ID による評価

より詳細な制御を行う場合は、Application Insights から特定のトレース ID を収集して評価します。 この方法は、アラートによってフラグ付けされたトレースや品質レビュー用にサンプリングされたトレースなど、精選された一連の対話を評価する場合に便利です。

Application Insights からトレース ID を収集する

Application Insights にクエリを実行して、エージェントのトレースから operation_Id 値を取得します。 各 operation_Id は、完全なエージェント操作を表します。

import os
from datetime import datetime, timedelta, timezone
from azure.identity import DefaultAzureCredential
from azure.monitor.query import LogsQueryClient, LogsQueryStatus

appinsights_resource_id = os.environ["APPINSIGHTS_RESOURCE_ID"]
agent_id = os.environ["AGENT_ID"]
trace_query_hours = int(os.environ.get("TRACE_LOOKBACK_HOURS", "1"))

end_time = datetime.now(timezone.utc)
start_time = end_time - timedelta(hours=trace_query_hours)

query = f"""dependencies
| where timestamp between (datetime({start_time.isoformat()}) .. datetime({end_time.isoformat()}))
| extend agent_id = tostring(customDimensions["gen_ai.agent.id"])
| where agent_id == "{agent_id}"
| distinct operation_Id"""

credential = DefaultAzureCredential()
logs_client = LogsQueryClient(credential)
response = logs_client.query_resource(
    appinsights_resource_id,
    query=query,
    timespan=None,  # Time range is specified in the query itself
)

trace_ids = []
if response.status == LogsQueryStatus.SUCCESS:
    for table in response.tables:
        for row in table.rows:
            trace_ids.append(row[0])

print(f"Found {len(trace_ids)} trace IDs")

評価を作成し、トレース ID を使用して実行する

# Create the evaluation
data_source_config = {
    "type": "azure_ai_source",
    "scenario": "traces",
}

eval_object = openai_client.evals.create(
    name="Agent Trace Evaluation (by trace IDs)",
    data_source_config=data_source_config,
    testing_criteria=testing_criteria,  # See "Set up evaluators" below
)

# Create a run using the collected trace IDs
data_source = {
    "type": "azure_ai_traces",
    "trace_ids": trace_ids,
    "lookback_hours": trace_query_hours,
}

eval_run = openai_client.evals.runs.create(
    eval_id=eval_object.id,
    name="agent-trace-eval-run",
    metadata={
        "agent_id": agent_id,
        "start_time": start_time.isoformat(),
        "end_time": end_time.isoformat(),
    },
    data_source=data_source,
)

print(f"Evaluation run started: {eval_run.id}")

エバリュエーターとデータ マッピングを設定する

トレースを評価すると、サービスは OpenTelemetry スパン属性から会話データを自動的に抽出します。 これらのフィールド名は、 data_mapping で直接使用します (他のシナリオで使用される item. または sample. プレフィックスは使用しません)。

変数 ソース属性 Description
{{item.query}} gen_ai.input.messages (ユーザー/システム ロール) トレースから抽出されたユーザー クエリ。
{{item.response}} gen_ai.input.messages (アシスタント/ツールロール) + gen_ai.output.messages トレースから抽出されたエージェントの応答。
{{item.tool_definitions}} gen_ai.tool.definitions エージェントで使用できるツール スキーマ。 ツール関連のエバリュエーターにのみ必要です。
{{item.tool_calls}} 内のアシスタント メッセージから抽出 gen_ai.input.messages / gen_ai.output.messages 対話中にエージェントによって行われたツール呼び出し。 ツール エバリュエーターによって使用されます。 ツール関連のエバリュエーターにのみ必要です。
from azure.ai.projects.models import TestingCriterionAzureAIEvaluator

testing_criteria = [
    # Quality evaluators — require query and response from trace data
    TestingCriterionAzureAIEvaluator(
        type="azure_ai_evaluator",
        name="intent_resolution",
        evaluator_name="builtin.intent_resolution",
        data_mapping={
            "query": "{{item.query}}",
            "response": "{{item.response}}",
            "tool_definitions": "{{item.tool_definitions}}",
        },
        initialization_parameters={"model": model_deployment_name},
    ),
    # Tool evaluators — assess tool usage quality
    TestingCriterionAzureAIEvaluator(
        type="azure_ai_evaluator",
        name="tool_call_accuracy",
        evaluator_name="builtin.tool_call_accuracy",
        data_mapping={
            "query": "{{item.query}}",
            "response": "{{item.response}}",
            "tool_calls": "{{item.tool_calls}}",
            "tool_definitions": "{{item.tool_definitions}}",
        },
        initialization_parameters={"model": model_deployment_name},
    ),
    # Safety evaluators — work even with partial trace data
    TestingCriterionAzureAIEvaluator(
        type="azure_ai_evaluator",
        name="violence",
        evaluator_name="builtin.violence",
        data_mapping={
            "query": "{{item.query}}",
            "response": "{{item.response}}",
        },
        initialization_parameters={"threshold": 4},
    ),
]

次のステップ