Agent 365とエージェントの観察可能性を統合する方法を学びましょう。OpenTelemetry(OTLP/HTTP+JSON)上でテレメトリを直接送信する方法です。 このアプローチは、Microsoft OpenTelemetry Distroを使えないエージェントが効率的かつ安全にテレメトリーを送信するのに役立ちます。 始める前に、 Agent 365の観測可能性の概念 を読んでモデル、認証フロー、データの出現場所を理解しましょう。
Important
OTel の直接パスは例外であり、既定値ではありません。 すでにOpenTelemetryパイプラインを持っている場合、フレームワークがMicrosoft OpenTelemetry Distroを使えない場合、またはエージェントがDistroでまだサポートされていない言語(Java など)で実装されている場合のみ使用してください。 他のすべてのユーザーに対して推奨されるパスは、Microsoft OpenTelemetry Distro です。これは、Agent 365、Microsoft Foundry、Azure Monitor などの統一された可観測性 SDK を提供します。 非推奨のAgent 365 Observability SDK は既存の統合では引き続き動作しますが、新規統合には推奨されていません。
[前提条件]
テレメトリ フローの前に、次の構成が設定されていることを確認します。
| 誰 | What |
|---|---|
| テナント管理者 | Agent 365 に登録し、エージェント アプリに必要な同意を付与してください。
エージェント 365 へのオンボードを参照してください。 適格なテナントがない場合、応答の200 OKでスパンが拒否されたことが示されていても、インジェストでresultsが返されることがあります。 |
| テナント管理者 |
少なくとも 1 人のユーザーに Microsoft 365 E7 または Microsoft Agent 365 ライセンスを割り当てます。 SKU が存在するだけでは不十分です。 ユーザーへの割り当てにより、インジェストを有効にするDefenderバックエンド ワークフローが開始されます。 割り当てられたライセンスがない場合、取り込みはスパンを拒否しつつ 200 OK を返すことがあります。 |
| テナント管理者 | ルートで必要な場合は、テナントの同意を付与しますAgent365.Observability.OtelWrite。 S2Sルートでエクスポートする登録エージェントインスタンスは、Observabilityの同意を必要としません。 委任ルートのエクスポートと未登録の S2S ID は該当します。
Microsoft 365 リソースへのエージェントアクセスを参照してください。 必要な同意なしに、役割や範囲なしにトークンが発行され、リクエストは 403 を返します。 |
| 開発チーム | アプリ(標準的なMicrosoft Entraアプリまたはブループリント)を登録し、Blueprint由来のエージェントインスタンスのためにAgent 365の登録を完了します。 エージェント の識別性を参照してください。 |
| 開発チーム | ルートで必要な場合にのみ Agent365.Observability.OtelWrite を追加してください: 未登録のS2S ID にはアプリ ロール、OBO には委任されたスコープ。 まだ委任エクスポートが必要なブループリントについては、「継承可能な権限の設定」を参照してください。 Agent 365 オンボード チームと調整して、アクセス許可を有効にします。 |
認証レシピ
4 つのレシピはすべて、標準のMicrosoft Entra トークン エンドポイントを使用します。
| フィールド | 価値 |
|---|---|
| トークンエンドポイント | https://login.microsoftonline.com/{your-tenant-id}/oauth2/v2.0/token |
リソース (返されたトークン内のaud ) |
9b975845-388f-4429-889e-eab1ef63949c ( api://9b975845-388f-4429-889e-eab1ef63949cも受け入れます) |
| S2S スコープ | 9b975845-388f-4429-889e-eab1ef63949c/.default |
| OBO スコープ | 9b975845-388f-4429-889e-eab1ef63949c/Agent365.Observability.OtelWrite |
以下のレシピは、明確さのために生のHTTPを示しています。 本番環境では、トークンの更新とキャッシュを処理するMicrosoft.Identity.Webまたは他の MSAL ライブラリを使用します。
どのレシピが必要ですか?
| マイ アプリ モデル | マイ OAuth フロー | 移動先 |
|---|---|---|
| Standard Microsoft Entra アプリの登録 | S2S (クライアント資格情報) | S2S、Standard Microsoft Entra アプリ |
| Standard Microsoft Entra アプリの登録 | OBO (代理) | OBO、標準 Microsoft Entra アプリ |
| ブループリント由来のエージェント識別子 | S2S (クライアント資格情報) | S2S、ブループリントから派生したエージェント ID |
| ブループリント由来のエージェント識別子 | OBO / AI チームメイト | OBO、ブループリントから派生したエージェント ID |
S2S、標準 Microsoft Entra アプリ
テナントのトークンエンドポイントにPOSTリクエストを送信 grant_type=client_credentials。 クライアント シークレット、証明書 (署名された JWT アサーション)、またはマネージド ID またはフェデレーション資格情報を使用してアプリを認証します。
POST https://login.microsoftonline.com/{your-tenant-id}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded
client_id={your-app-id}
&scope=9b975845-388f-4429-889e-eab1ef63949c%2F.default
&client_secret={secret}
&grant_type=client_credentials
返されたトークンには、appidと/azp = を含む{your-app-id}、rolesAgent365.Observability.OtelWriteaud = 9b975845-...があります。
/observabilityService/.../traces ルートで使用します。 標準的なアプリ登録はAgent 365に登録されたエージェントインスタンスではないため、トークンにはこのアプリロールが必要です。
証明書ベースの認証の場合は、 client_secret={secret} を client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion={signed-jwt}に置き換えます。
S2S、設計図由来エージェント識別
エージェント ID には、独自の資格情報がありません。 エージェント ID ブループリントは、資格情報 (マネージド ID FIC、証明書、またはクライアント シークレット) を保持し、2 段階認証を通じて子エージェント ID に代わってトークンを作成します。 詳細については、 自律アプリの OAuth フローを参照してください。
ブループリントは認証され、フェデレーション ID 交換トークン
T1取得されます。-
{blueprint-credential}はブループリントの MSI トークン、証明書署名済み JWT、またはシークレット交換トークン アサーションです。ブループリント構成ごと。
POST https://login.microsoftonline.com/{your-tenant-id}/oauth2/v2.0/token Content-Type: application/x-www-form-urlencoded client_id={blueprint-app-id} &scope=api%3A%2F%2FAzureADTokenExchange%2F.default &fmi_path={agent-identity-app-id} &client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer &client_assertion={blueprint-credential} &grant_type=client_credentials-
エージェント ID は、Agent 365 Observability リソース トークンの
T1を交換します。POST https://login.microsoftonline.com/{your-tenant-id}/oauth2/v2.0/token Content-Type: application/x-www-form-urlencoded client_id={agent-identity-app-id} &scope=9b975845-388f-4429-889e-eab1ef63949c%2F.default &client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer &client_assertion={T1} &grant_type=client_credentials- 返却されたトークンには
appid/azp={agent-identity-app-id}、scpはなく、aud=9b975845-...があります。 Agent 365登録済みのエージェント インスタンスの場合、トークンにAgent365.Observability.OtelWriteロールは必要ありません。 - エージェント インスタンスが Agent 365 に登録されていない場合、サービスは同じロールのないアプリ専用トークンを拒否し、
403 insufficient_scopeを返します。 未登録のIDにはAgent365.Observability.OtelWriteアプリ ロールが必要です。 -
/observabilityService/.../tracesルートでこのトークンを使用します。 - URL
{agentId}は、エージェント ID の appId であり、ブループリントの appId ではありません。
- 返却されたトークンには
OBO、標準の Microsoft Entra アプリ
アップストリームの呼び出し元 (Bearer または PFAT) からユーザーの受信トークン Tc を受け取り、交換します。
POST https://login.microsoftonline.com/{your-tenant-id}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded
client_id={your-app-id}
&scope=9b975845-388f-4429-889e-eab1ef63949c%2FAgent365.Observability.OtelWrite
&client_secret={secret}
&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&assertion={Tc}
&requested_token_use=on_behalf_of
証明書認証の場合は、 client_secret={secret} を S2S と同じ client_assertion_type + client_assertion ペアに置き換えます。
返されたトークンには、appidと/azp = を含む{your-app-id}、scpAgent365.Observability.OtelWriteaud = 9b975845-...があります。
/observability/.../traces ルートで使用します。 更新トークンが一緒に返されます。キャッシュし、すべての呼び出しで交換を再実行する代わりにそれを再利用します。
OBO、設計図由来のエージェント識別(AIチームメイトを含む)
代理フローには、主に 3 つの手順があります。 詳細については、「 エージェント OAuth フロー: フローの代理」を参照してください。
ユーザー トークン
Tcを受け取ります。 AI チームメイトの場合、このトークンはエージェント自身のユーザー アカウントを表します。それ以外の場合は、人間の呼び出し元を表します。ブループリントは、S2S のブループリント由来のエージェント ID フローと同様に、認証を行って
T1を取得します。エージェント ID は、委任されたリソース トークンの
T1とTcを交換します。POST https://login.microsoftonline.com/{your-tenant-id}/oauth2/v2.0/token Content-Type: application/x-www-form-urlencoded client_id={agent-identity-app-id} &scope=9b975845-388f-4429-889e-eab1ef63949c%2FAgent365.Observability.OtelWrite &client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer &client_assertion={T1} &grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer &assertion={Tc} &requested_token_use=on_behalf_of
返されるトークンには、appidを含む/azp = {agent-identity-app-id}scpAgent365.Observability.OtelWriteがあり、エージェントのユーザーを表します。
/observability/.../traces ルートで使用します。 URL {agentId} は、エージェント ID の appId であり、ブループリントの appId ではありません。 更新トークンが一緒に返されます。キャッシュして再利用します。 委任ルートは委任範囲とテナント管理者の同意が必要です。
返されたトークンの必須クレーム
S2S ルート (/observabilityService/...) - アプリ専用トークン:
| 請求 | 必須の値 |
|---|---|
aud |
9b975845-388f-4429-889e-eab1ef63949c (または api://9b975845-...) |
roles |
Agent 365 に登録されたエージェント インスタンスの場合、必須ではありません。 未登録のIDには Agent365.Observability.OtelWrite を含める必要があります。 |
appid (v1) または azp (v2) |
URL と等しい必要があります {agentId} |
scp |
欠席している必要があります |
委任されたルート (/observability/...) - ユーザー委任トークン (ベアラーまたは PFAT):
| 請求 | 必須の値 |
|---|---|
aud |
9b975845-388f-4429-889e-eab1ef63949c (または api://9b975845-...) |
scp |
Agent365.Observability.OtelWrite を含める必要があります |
appid / azp |
URL と等しい必要があります {agentId} |
委任されたルートは、 Bearer トークンと MSAuth1.0 PFAT トークンの両方を受け入れます。 直接呼び出し元は、 Bearerを使用する必要があります。 持っているものがわからない場合は、 Bearerを使用します。
Endpoints
2 つのルート。ユーザーが行っていることではなく、 サービス の認証方法によって選択します。
POST https://agent365.svc.cloud.microsoft/observabilityService/tenants/{tenantId}/otlp/agents/{agentId}/traces?api-version=1 # S2S
POST https://agent365.svc.cloud.microsoft/observability/tenants/{tenantId}/otlp/agents/{agentId}/traces?api-version=1 # OBO
ヘッダー:
Authorization: Bearer <token> # or MSAuth1.0 ... for delegated PFAT
Content-Type: application/json
URL パラメーター
-
{tenantId}- 顧客テナントの GUID。 サーバーはこの値を権威的なものとして扱います。 もしスパンがmicrosoft.tenant.idに設定されていて一致しなければ、サーバーはリクエストを拒否します。 -
{agentId}- 呼び出し元アプリケーションの appId (OAuthclient_idも)。 ブループリント由来の識別子の場合、この値は エージェントの識別子 appIdであり、blueprint appIdではありません。 それはあなたのトークンのappidまたはazpの主張と一致しなければなりません。 -
api-version=1-必須。
入居者の適格性を確認してください
S2S 認証モデルを使用するオンボード済みのサードパーティ統合は、統合を有効にしたりテレメトリを送信したりする前に、顧客テナントが Agent 365 の可観測性の対象となるかどうかを確認できます。 このチェックは、現在対象外のテナントに対してテレメトリを送信してしまうことを、統合機能が回避するのに役立ちます。
S2S認証で説明されているのと同じアプリ専用トークンを使いましょう。
トークンには Agent365.Observability.OtelWrite アプリロールが含まれ、その tid 請求はリクエストURLの {tenantId} と一致しなければなりません。
GET https://agent365.svc.cloud.microsoft/observabilityService/tenants/{tenantId}/eligibility?api-version=1
Authorization: Bearer <access-token>
成功した回答には、適格性の結果が含まれます:
{
"enabled": true
}
回答は以下の通りに扱います:
| 地位 | Meaning | クライアント側の処理 |
|---|---|---|
200 OK、enabled: true |
テナントは可観測性の対象となります。 | この統合はテレメトリを送信できます。 |
200 OK、enabled: false |
テナントは現在、観測対象外です。 | テレメトリは送らないでください。 テナントが 前提条件を満たしているか確認し、ステータスが変わったら再度確認してください。 それでもテレメトリを送信すれば、インジェスションエンドポイントはスパンを拒否しながらも 200 OK を返すことができます。 |
400 Bad Request |
{tenantId} 空または無効です。 |
再挑戦する前に入居者IDを修正してください。 |
401 Unauthorized |
access トークンが見つからないか無効です。 | Agent 365の観測可能性リソースの有効なトークンを取得してください。 |
403 Forbidden |
トークンに必要なアプリロールがなかったり、テナントが {tenantId}と一致していない場合もあります。 |
再挑戦する前に、許可、同意、または入居者の不一致を修正してください。 |
429 Too Many Requests |
発信者は申請資格の上限を超えました。 |
Retry-After を尊重し、バックオフとジッターを用いて再試行します。 |
503 Service Unavailable |
適格性は判定できませんでした。 レスポンスにはボディがありません。 |
Retry-After: 30 を尊重して、再試行してください。 この返答を enabled: falseと受け取らないでください。 |
リクエスト本文のエンコーディング
本体は標準的なOTLP/HTTP+JSONフォーマット、すなわちresourceSpans → scopeSpans → spansを含むExportTraceServiceRequestを使用します。 次の詳細に注意してください。
-
traceId(16バイト)とspanId(8バイト)を小文字の十六進形文字列として送信します。 -
startTimeUnixNanoendTimeUnixNanoはUnixのエポックナノ秒を保持する文字列です。 -
kindは整数OTLPの列挙値(例:1INTERNAL)。status.codeは整数枚挙(例えば、OK1、ERROR2)。 - すべての属性値をそのまま送信
stringValue。
応答図形
200 OK応答はエージェント365がリクエストを処理したことを意味します。 すべてのスパンが目的地にルーティングされたことを保証するものではありません。
partialSuccessとresultsの両方を点検してください。
results配列は、各該当宛先における各スパンの結果を報告します:
-
sent- スパンは宛先にルーティングされました。 -
rejected- スパンはルーティングされていなかった。reason分野がその理由を説明しています。 -
not_routed- スパンに対して宛先が選択されていませんでした。reason分野がその理由を説明しています。
例えば、正常にルーティングされたスパンは次のように返されます:
{
"partialSuccess": {
"rejectedSpans": 0,
"errorMessage": ""
},
"results": [
{
"spanId": "0123456789abcdef",
"sinks": {
"flashpoint": {
"status": "sent"
},
"sentinel": {
"status": "sent"
},
"esp": {
"status": "sent"
}
}
}
]
}
入居者が資格がなければ、申請は返却可能です 200 OK。 この場合、resultsは、スパンが拒否されたことを示しています:
{
"partialSuccess": {
"rejectedSpans": 0,
"errorMessage": ""
},
"results": [
{
"spanId": "0123456789abcdef",
"sinks": {
"flashpoint": {
"status": "rejected",
"reason": "tenant_not_licensed"
},
"sentinel": {
"status": "rejected",
"reason": "tenant_not_licensed"
},
"esp": {
"status": "rejected",
"reason": "tenant_not_licensed"
}
}
}
]
}
全リクエストのルーティング決定の場合、resultsがすべてのスパンが拒否されたことを示してもpartialSuccess.rejectedSpans0のままです。
partialSuccessやHTTPステータスだけを摂取の証拠として使わないでください。 フィールド名は、通信上では camelCase です。 テレメトリが表示されない他の理由については 、制限とドロップ条件 を参照してください。
可能な限り最小の要求
最も単純なエンド ツー エンドテストでは、単一の invoke_agent スパンが送信されます。 このスパンは、Microsoft Defender に取り込まれる最小のデータ単位です。
ステップ 1. ベアラー トークンを取得します。 S2S の場合は、スコープ 9b975845-388f-4429-889e-eab1ef63949c/.default でクライアント資格情報を使用します (完全な レシピについては認証レシピ を参照してください)。
ステップ 2. 単一のスパンを POST する:
TOKEN="$(./get-token.sh)"
TENANT_ID="<customer-tenant-guid>"
AGENT_ID="<your-agent-app-id>"
curl -i -X POST \
"https://agent365.svc.cloud.microsoft/observabilityService/tenants/${TENANT_ID}/otlp/agents/${AGENT_ID}/traces?api-version=1" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
--data @- <<EOF
{
"resourceSpans": [{
"scopeSpans": [{
"scope": { "name": "my-instrumentation", "version": "1.0.0" },
"spans": [{
"traceId": "0102030405060708090a0b0c0d0e0f10",
"spanId": "1111111111111111",
"parentSpanId": "",
"name": "invoke_agent",
"kind": 1,
"startTimeUnixNano": "1736175600000000000",
"endTimeUnixNano": "1736175601500000000",
"status": { "code": 1 },
"attributes": [
{ "key": "gen_ai.operation.name", "value": { "stringValue": "invoke_agent" } },
{ "key": "gen_ai.agent.id", "value": { "stringValue": "${AGENT_ID}" } },
{ "key": "gen_ai.agent.name", "value": { "stringValue": "MyAgent" } },
{ "key": "microsoft.a365.agent.blueprint.id", "value": { "stringValue": "${AGENT_ID}" } },
{ "key": "gen_ai.conversation.id","value": { "stringValue": "conv-001" } },
{ "key": "microsoft.channel.name","value": { "stringValue": "web" } },
{ "key": "user.id", "value": { "stringValue": "<entra-user-objectid>" } },
{ "key": "client.address", "value": { "stringValue": "10.1.2.80" } },
{ "key": "server.address", "value": { "stringValue": "myagent.example.com" } },
{ "key": "server.port", "value": { "stringValue": "443" } },
{ "key": "gen_ai.input.messages", "value": { "stringValue": "[{\"role\":\"user\",\"content\":\"hi\"}]" } },
{ "key": "gen_ai.output.messages","value": { "stringValue": "[{\"role\":\"assistant\",\"content\":\"hello\"}]" } }
]
}]
}]
}]
}
EOF
ステップ 3.
200 OKを想定し、次にresultsで説明されているとおりにを確認してください。 該当する目的地が「 sent」のステータスであることを確認しましょう。
ステップ 4. データが実際に着陸したことを確認します。 200のOKはインジェストの証明ではありません。検証の流れについては「 インジェスションの検証 」を参照してください。 代わりに、保存した本文ファイルを POST するには、 --data @- <<EOF ... EOF を --data @./otlp-request.json に置き換えます。
エージェントの実行例
Microsoft Teamsのユーザーが「シアトルの天気は何ですか?」と尋ねます。 エージェントが GetWeather 関数を呼び出し、LLM に応答の書式を設定するよう求め、応答します。 その1回の実行は、4つのスパンから成ります。
graph TD
A["<b>invoke_agent</b> · spanId=A · parentSpanId=∅<br/><i>root - the run itself</i>"]
B["<b>chat</b> · spanId=B · parentSpanId=A<br/><i>LLM picks the tool / formats reply</i>"]
C["<b>execute_tool</b> · spanId=C · parentSpanId=A<br/><i>the GetWeather call</i>"]
D["<b>output_messages</b> · spanId=D · parentSpanId=A<br/><i>final reply emitted to the user</i>"]
A --> B
A --> C
A --> D
すべてのスパンで設定される実行全体の属性:
| Attribute | 値の例 |
|---|---|
traceId |
0102030405060708090a0b0c0d0e0f10 |
gen_ai.conversation.id |
19:abc@thread.tacv2 |
microsoft.session.id |
session-1234 |
microsoft.channel.name |
msteams |
gen_ai.agent.id |
<AGENT_APP_ID> |
gen_ai.agent.name |
WeatherBot |
microsoft.a365.agent.blueprint.id |
<BLUEPRINT_APP_ID> |
user.id |
<entra-user-objectid> |
client.address |
10.1.2.80 |
server.address |
weatherbot.example.com |
server.port |
443 |
Important
これらのラン全体の属性は自動的には引き継がれません。 すべてのスパンに gen_ai.conversation.id、 microsoft.channel.name、 microsoft.session.id を設定しなければなりません。
スパン A: invoke_agent (ルート)
{
"traceId": "0102030405060708090a0b0c0d0e0f10",
"spanId": "1111111111111111",
"parentSpanId": "",
"name": "invoke_agent",
"kind": 1,
"startTimeUnixNano": "1736175600000000000",
"endTimeUnixNano": "1736175601500000000",
"status": { "code": 1 },
"attributes": [
{ "key": "gen_ai.operation.name", "value": { "stringValue": "invoke_agent" } },
{ "key": "gen_ai.execution.type", "value": { "stringValue": "HumanToAgent" } },
{ "key": "gen_ai.input.messages", "value": { "stringValue": "[{\"role\":\"user\",\"content\":\"What's the weather in Seattle?\"}]" } },
{ "key": "gen_ai.output.messages", "value": { "stringValue": "[{\"role\":\"assistant\",\"content\":\"It's 65F and partly cloudy in Seattle.\"}]" } },
{ "key": "user.email", "value": { "stringValue": "alice@contoso.com" } }
/* plus all the run-wide attributes listed above */
]
}
Span B: chat(LLM 呼び出し)
{
"traceId": "0102030405060708090a0b0c0d0e0f10",
"spanId": "2222222222222222",
"parentSpanId": "1111111111111111",
"name": "chat",
"kind": 1,
"startTimeUnixNano": "1736175600200000000",
"endTimeUnixNano": "1736175600900000000",
"status": { "code": 1 },
"attributes": [
{ "key": "gen_ai.operation.name", "value": { "stringValue": "chat" } },
{ "key": "gen_ai.request.model", "value": { "stringValue": "gpt-4o" } },
{ "key": "gen_ai.provider.name", "value": { "stringValue": "openai" } },
{ "key": "gen_ai.usage.input_tokens", "value": { "stringValue": "42" } },
{ "key": "gen_ai.usage.output_tokens", "value": { "stringValue": "23" } }
/* plus all the run-wide attributes */
]
}
範囲 C: execute_tool
{
"traceId": "0102030405060708090a0b0c0d0e0f10",
"spanId": "3333333333333333",
"parentSpanId": "1111111111111111",
"name": "execute_tool",
"kind": 1,
"startTimeUnixNano": "1736175600950000000",
"endTimeUnixNano": "1736175601200000000",
"status": { "code": 1 },
"attributes": [
{ "key": "gen_ai.operation.name", "value": { "stringValue": "execute_tool" } },
{ "key": "gen_ai.tool.name", "value": { "stringValue": "GetWeather" } },
{ "key": "gen_ai.tool.type", "value": { "stringValue": "function" } },
{ "key": "gen_ai.tool.call.id", "value": { "stringValue": "call-001" } },
{ "key": "gen_ai.tool.call.arguments", "value": { "stringValue": "{\"location\":\"Seattle\"}" } },
{ "key": "gen_ai.tool.call.result", "value": { "stringValue": "{\"tempF\":65,\"condition\":\"partly cloudy\"}" } }
/* plus all the run-wide attributes */
]
}
スパン D: output_messages
{
"traceId": "0102030405060708090a0b0c0d0e0f10",
"spanId": "4444444444444444",
"parentSpanId": "1111111111111111",
"name": "output_messages",
"kind": 1,
"startTimeUnixNano": "1736175601400000000",
"endTimeUnixNano": "1736175601500000000",
"status": { "code": 1 },
"attributes": [
{ "key": "gen_ai.operation.name", "value": { "stringValue": "output_messages" } },
{ "key": "gen_ai.output.messages", "value": { "stringValue": "[{\"role\":\"assistant\",\"content\":\"It's 65F and partly cloudy in Seattle.\"}]" } }
/* plus all the run-wide attributes */
]
}
テレメトリの送信
OTelのSDKを使う
ほとんどのパートナーは、手動ロール HTTP ではなく OTel SDK を介してトレースを送信します。 SDK はバッチ処理、再試行、OTLP/HTTP+JSON エンコードを自動的に処理します。 エクスポーター エンドポイントを設定し、 Authorization ヘッダーを挿入します。
エクスポーター エンドポイントは、クエリ文字列を含むルート URL 自体です。
https://agent365.svc.cloud.microsoft/observabilityService/tenants/{tenantId}/otlp/agents/{agentId}/traces?api-version=1
(委任されたルートに/observability/...の代わりに/observabilityService/...を使用します)。
Python
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
exporter = OTLPSpanExporter(
endpoint="https://agent365.svc.cloud.microsoft/observabilityService/tenants/{tenantId}/otlp/agents/{agentId}/traces?api-version=1",
headers={"Authorization": f"Bearer {token}"},
)
パッケージ: opentelemetry-exporter-otlp-proto-http。
Node.js/ TypeScript
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
const exporter = new OTLPTraceExporter({
url: "https://agent365.svc.cloud.microsoft/observabilityService/tenants/{tenantId}/otlp/agents/{agentId}/traces?api-version=1",
headers: { Authorization: `Bearer ${token}` },
});
パッケージ: @opentelemetry/exporter-trace-otlp-http。
.NET
using OpenTelemetry.Exporter;
services.AddOpenTelemetry().WithTracing(b => b
.AddOtlpExporter(o =>
{
o.Endpoint = new Uri("https://agent365.svc.cloud.microsoft/observabilityService/tenants/{tenantId}/otlp/agents/{agentId}/traces?api-version=1");
o.Headers = $"Authorization=Bearer {token}";
o.Protocol = OtlpExportProtocol.HttpJson;
}));
パッケージ: OpenTelemetry.Exporter.OpenTelemetryProtocol。
HTTP(手動)
OTel SDK を使用できない場合、または使用したくない場合は、OTLP/HTTP+JSON 要求を自分でビルドして POST します。 OpenTelemetry OTLP/HTTP+JSON 仕様 はボディ形状を定義しています:
{
"resourceSpans": [{
"resource": { "attributes": [ ... ] }, // optional
"scopeSpans": [{
"scope": { "name": "<your-instrumentation>", "version": "1.0.0" },
"spans": [ <span>, <span>, ... ]
}]
}]
}
各 <span> は、必須フィールドが traceId、 spanId、 name、 kind、 startTimeUnixNano、 endTimeUnixNano、 attributes、および (非ルート スパンの場合) parentSpanIdを持つオブジェクトです。 エンコーディングルール(文字列エンコード時間、十六進数 traceId / spanId、整数 kind / status.code、すべての属性値 stringValue)については 、エンドポイント および リクエストボディエンコーディングを参照してください。
各スパンで設定する属性のセットは、 メッセージ コントラクトで定義されます。 完全な属性リストについては、 属性参照を参照してください。 ヘッダーと本文のインラインでベアラー トークンを使用したエンドツーエンドの作業サンプルについては、 エージェントの実行例 を参照してください。
実行のすべてのスパンを 1 つの POST 本文 (1 つの要求、1 つのトレース) で送信することも、複数の POST にまたがって送信することもできます。 サーバーは traceId + parentSpanId + gen_ai.conversation.idから実行を再構築するため、各スパンはどちらの方法でも相互に関連付けられるのに十分です。
メッセージ契約
このセクションでは、出力できるスパンと、それぞれの属性を定義します。 属性ごとの完全な仕様については、属性リファレンスを 参照してください。
操作の種類
送信する各 span では、gen_ai.operation.name にこれら4つの値のいずれかを設定する必要があります(大文字と小文字は区別しません)。 サーバーは、値が欠落しているか認識されない値を持つスパンを除外し、その数を partialSuccess.rejectedSpans にカウントします。
gen_ai.operation.name |
Meaning | Googleで最も検索されている落とし穴 |
|---|---|---|
invoke_agent |
エージェントの呼び出し。 エージェント実行の "ルート" です。 | 実行が Microsoft Defender のエージェント アクティビティ ビューまたは Microsoft 365 管理センターに表示されるには必要です。 これがないと、テレメトリは Microsoft Defender の高度なハンティング (CloudAppEvents) にのみ送られます。 |
execute_tool |
エージェントによって実行されるツール/関数呼び出し。 | -- |
chat |
LLMの推論呼び出し。 |
chatではなく、リテラル inferenceを使用します。 |
output_messages |
最終的に出力されるメッセージ。 | -- |
スパン階層と実行のグループ化
エージェント 365 は、標準の OTLP スパン グラフ(traceId、spanId、parentSpanId)と、属性リファレンスの実行全体にわたる属性から実行を再構築します。
6 つの規則:
- ルート以外のすべてのスパンで常に
parentSpanIdを設定してください。 それがなければ、ランの木構造を再構築することはできません。 -
実行内のすべてのスパンで同じ
traceIdを再利用します。 - 同じ値を持つすべてのスパンに
gen_ai.conversation.idを設定します。 この値は「このランのすべてのスパン」の主結合キーです。 自動的に伝播される わけではありません 。 - 同じ値を持つすべてのスパンに
microsoft.channel.nameを設定します。 チャネルまたは会話が設定されていないツールスパンは、invoke_agent親が同じ OTLP リクエスト内にある場合にのみ、親からそれらを継承できます。したがって、各スパンに自分で明示的に設定してください。 - 論理セッションがある場合は、すべてのスパンで
microsoft.session.idを設定します。 - 子エージェントが別の要求にあるエージェント間呼び出しの場合は、同じ
gen_ai.conversation.idを再利用し、microsoft.a365.caller.agent.*属性 ( 属性リファレンスを参照) を使用して呼び出し元エージェント コンテキストをキャプチャします。
エージェントの実行例の 4 スパン ツリーは正規の図形です。
一般的な実行図形
| 形状 | 送信するスパン | 注記 |
|---|---|---|
| 単一エージェント チャットボット (ツールなし、LLM スパンなし) |
invoke_agent は 1 つのみ |
実行全体の属性に加えて、 gen_ai.input.messages と gen_ai.output.messagesを設定します。 可能な 限り最小の要求と同じです。 |
| ツールを使用したエージェント (最も一般的) |
invoke_agent ルート + chat、execute_tool、output_messages 子要素 |
すべての子がルートの traceId を共有し、 parentSpanId = root.spanIdを設定します。 すべて同じ実行全体の属性を持っています。 完全な例については、 エージェントの実行例 を参照してください。 |
| エージェント間 | 各エージェントはそれぞれ独自の invoke_agent を出力します |
両方のエージェントで同じ gen_ai.conversation.id を再利用します。 ターゲットの invoke_agentで、 gen_ai.execution.type = "Agent2Agent" と microsoft.a365.caller.agent.* 属性 (呼び出し元エージェントの appId、名前、ブループリント appId、ユーザー ID、電子メール) を設定します。 呼び出し元エージェントに Entra 登録がない場合は、代わりに microsoft.a365.caller.agent.platform.id と gen_ai.caller.agent.type を使用します。 |
本番オンボーディングのチェックリスト
運用環境に移行する前に、このチェックリストを実行します。
| Category | 確認 |
|---|---|
| 認証 | お使いの Entra アプリ (またはブループリント) は登録されており、そのトークンを発行できます。 |
| 認証 | S2Sルートでブループリント由来のアイデンティティを使う場合、エージェントインスタンスはエージェント365に登録されます。 登録されたインスタンスは Agent365.Observability.OtelWrite アプリ ロールを必要としません。 |
| 認証 | S2Sルートで未登録のIDを使うと、アプリは Agent365.Observability.OtelWrite アプリ ロールを付与されます。 |
| 認証 | 委任ルートを使うと、アプリには委任された Agent365.Observability.OtelWrite スコープが付与されます。 |
| 認証 | 各エージェントには、URL にとして独自の Entra {agentId} があります。 ブループリント派生 ID の場合、その appId は、ブループリント appId ではなく、エージェント ID appId です。 エージェントに Entra 登録がない場合は、「 値の選択」を参照してください。 |
| 認証 | ルートがアプリ ロールまたは委任スコープを必要とする場合、テナント管理者は Agent365.Observability.OtelWrite を付与します。 必要な同意なしに、ロールまたはスコープが付与されないトークンが発行され、リクエストは 403 を伴って拒否されます。 |
| ライセンス | 顧客テナント内の少なくとも 1 人のユーザーに Microsoft 365 E7 または Microsoft Agent 365 ライセンスが割り当てられている (テナント内の SKU プレゼンスだけでなく、割り当て)。 ライセンスが割り当てられていない場合、回答内の results から、スパンが拒否されたことがわかります。 「前提条件」を参照してください。 |
| スパン | すべてのスパンは、実行全体の要点 (スパン階層と実行グループ) を設定します。 |
| スパン |
invoke_agent は、 gen_ai.input.messages と gen_ai.output.messagesを設定します。 |
| スパン |
execute_tool スパンセット gen_ai.tool.name、gen_ai.tool.type、gen_ai.tool.call.id、gen_ai.tool.call.arguments、gen_ai.tool.call.result。 |
| スパン |
chat スパンのセット gen_ai.request.model および gen_ai.provider.name(および理想的には gen_ai.usage.input_tokens / gen_ai.usage.output_tokens - 文字列としてエンコードされたもの)。 |
| スパン | ルート以外のすべてのスパンは parentSpanId設定されます。実行内のすべてのスパンは同じ traceIdを共有します。 |
| ペイロード | リクエスト本文は 1 MB 以下です。 |
| 確認 | すべての返信の partialSuccess と results の両方をチェックし、却下を記録します。 |
| 確認 | 最初の実行を対象に、インジェストの検証で検証フローを実行しました。 |
次のステップ
- 属性リファレンス - 属性ごとの仕様と値選択のガイダンス。
- トラブルシューティング - インジェスト、一般的な落とし穴、エラー応答の確認。