Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Lernen Sie, wie Sie die Agenten-Observabilität mit Agent 365 integrieren, indem Sie Telemetrie direkt über OpenTelemetry (OTLP/HTTP+JSON) senden. Dieser Ansatz hilft Agenten, die die Microsoft OpenTelemetry Distro nicht nutzen können, Telemetrie effizient und sicher zu senden. Bevor Sie beginnen, lesen Sie die Observability-Konzepte von Agent 365 , um das Modell, die Authentifizierungsflüsse und den Standort Ihrer Daten zu verstehen.
Important
Der direkte OTel-Pfad ist die Ausnahme, nicht der Standardwert. Nutze es nur, wenn du bereits eine OpenTelemetry-Pipeline hast, dein Framework die Microsoft OpenTelemetry Distro nicht nutzen kann oder dein Agent in einer Sprache ist, die die Distro noch nicht unterstützt (wie zum Beispiel Java). Für alle anderen ist der empfohlene Pfad der Microsoft OpenTelemetry Distro, der ein einheitliches Observability SDK für Agent 365, Microsoft Foundry, Azure Monitor und vieles mehr bereitstellt. Das veraltete Agent 365 Observability SDK funktioniert weiterhin für bestehende Integrationen, wird aber nicht für neue Integrationen empfohlen.
Voraussetzungen
Stellen Sie sicher, dass die folgenden Konfigurationen eingerichtet sind, bevor Telemetriedaten übertragen werden.
| Wer | What |
|---|---|
| Mandantenadministrator | Melden Sie sich bei Agent 365 an und erteilen Sie die erforderliche Zustimmung für Ihre Agent-App. Weitere Informationen finden Sie unter Einführung in Agent 365. Ohne einen berechtigten Mandanten kann die Erfassung 200 OK zurückgeben, obwohl die results der Antwort zeigen, dass die Spans abgelehnt wurden. |
| Mandantenadministrator |
Weisen Sie mindestens einem Benutzer im Mandanten eine Microsoft 365 E7- oder eine Microsoft Agent 365-Lizenz zu. Die vorhandene SKU reicht nicht aus. Die Zuweisung zu einem Benutzer startet den Defender Back-End-Workflow, der die Aufnahme ermöglicht. Ohne eine zugewiesene Lizenz kann die Ingestion 200 OK zurückgeben und dabei die Spannen ablehnen. |
| Mandantenadministrator | Erteile die Einwilligung des Mandanten, wenn deine Route dies erfordert Agent365.Observability.OtelWrite. Registered Agent-Instanzen, die auf der S2S-Route exportieren, benötigen keine Observability-Einwilligung. Delegierte Routenexporte und nicht registrierte S2S-Identitäten hingegen schon. Siehe Grant Agents Zugriff auf Microsoft 365 Ressourcen. Ohne erforderliche Zustimmung werden Token ohne Rolle oder Umfang ausgegeben, und Anfragen geben 403 zurück. |
| Ihr Entwicklerteam | Registrieren Sie Ihre App (Standard-Microsoft Entra-App oder Blueprint) und schließen Sie die Agent-365-Registrierung für von Blueprint abgeleitete Agenteninstanzen durch. Siehe Agentenidentität. |
| Ihr Entwicklerteam |
Agent365.Observability.OtelWrite nur hinzufügen, wenn deine Route es erfordert: App-Rolle für nicht registrierte S2S-Identitäten und delegierter Bereich für OBO. Für Blueprints, die noch delegierten Export benötigen, siehe Vererbbare Berechtigungen konfigurieren. Stimmen Sie sich mit dem Agent 365-Onboarding-Team ab, um die Berechtigung zu aktivieren. |
Authentifizierungsrezepte
Alle vier Rezepte verwenden den standardmäßigen Microsoft Entra Tokenendpunkt:
| Feld | Wert |
|---|---|
| Tokenendpunkt | https://login.microsoftonline.com/{your-tenant-id}/oauth2/v2.0/token |
Ressource (aud im zurückgegebenen Token) |
9b975845-388f-4429-889e-eab1ef63949c (akzeptiert auch api://9b975845-388f-4429-889e-eab1ef63949c) |
| S2S-Umfang | 9b975845-388f-4429-889e-eab1ef63949c/.default |
| OBO-Geltungsbereich | 9b975845-388f-4429-889e-eab1ef63949c/Agent365.Observability.OtelWrite |
Die folgenden Rezepte zeigen zur Klarheit Roh-HTTP. In der Produktion verwenden Sie Microsoft. Identity.Web oder eine andere MSAL-Bibliothek, die Token-Aktualisierung und Caching übernimmt.
Welches Rezept benötige ich?
| Mein App-Modell | Mein OAuth-Fluss | Gehe zu |
|---|---|---|
| Standard-Microsoft Entra-App-Registrierung | S2S (Clientanmeldeinformationen) | S2S, Standard Microsoft Entra App |
| Standard-Microsoft Entra-App-Registrierung | OBO (delegiert) | OBO, Standard Microsoft Entra App |
| Vom Blueprint abgeleitete Agentidentität | S2S (Clientanmeldeinformationen) | S2S, Vom Blueprint abgeleitete Agentidentität |
| Vom Blueprint abgeleitete Agentidentität | OBO / KI-Teammitglied | OBO, Vom Blueprint abgeleitete Agentidentität |
S2S, Standard-Microsoft Entra-App
Senden Sie eine POST-Anfrage an den Token-Endpunkt des Tenants mit grant_type=client_credentials. Authentifizieren Sie die App mithilfe eines geheimen Clientschlüssels, eines Zertifikats (signierter JWT-Assertion) oder einer verwalteten Identität oder Verbundanmeldeinformationen.
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
Das zurückgegebene Token enthält appid/azp = {your-app-id}, roles enthält Agent365.Observability.OtelWriteund .aud = 9b975845-... Verwenden Sie es auf der /observabilityService/.../traces-Route. Standard-App-Registrierungen sind keine Agent-365-registrierten Agenten-Instanzen, daher benötigt das Token diese App-Rolle.
Ersetzen Sie für die zertifikatbasierte Authentifizierung client_secret={secret} durch client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion={signed-jwt}.
S2S, vom Blueprint abgeleitete Agentenidentität
Agentidentitäten besitzen keine eigenen Anmeldeinformationen. Der Agentidentitäts-Blueprint enthält die Anmeldeinformationen (verwaltete Identitäten FIC, Zertifikat oder geheimen Clientschlüssel) und stellt Token im Auftrag seiner untergeordneten Agentidentitäten über einen zweistufigen Austausch bereit. Weitere Informationen finden Sie unter OAuth-Ablauf für eigenständige Apps.
Der Blueprint authentifiziert sich und ruft ein Verbundidentitätsaustauschtoken
T1ab:-
{blueprint-credential}ist das MSI-Token, das zertifikatsignierte JWT oder die geheime Exchange-Token-Assertion des Blueprints – je nach Blueprint-Konfiguration.
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-
Die Agentenidentität tauscht
T1gegen das Ressourcentoken für Agent 365 Observability ein: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- Der zurückgegebene Token hat
appid/azp={agent-identity-app-id}, keinscp, undaud=9b975845-.... Für eine Agent 365-registrierte Agent-Instanz benötigt das Token die RolleAgent365.Observability.OtelWritenicht. - Wenn die Agenteninstanz nicht bei Agent 365 registriert ist, lehnt der Dienst dasselbe rollenlose App-Only-Token mit
403 insufficient_scopeab. Nicht registrierte Identitäten benötigen dieAgent365.Observability.OtelWriteApp-Rolle. - Verwenden Sie dieses Token auf der
/observabilityService/.../tracesRoute. - Die URL
{agentId}ist die Agent-Identitäts-appId, nicht die Blueprint-AppId.
- Der zurückgegebene Token hat
OBO, die Standard-Microsoft Entra-App
Empfangen Sie das eingehende Token Tc des Benutzers von Ihrem upstream-Aufrufer (Bearer oder PFAT), und tauschen Sie es aus:
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
Ersetzen Sie bei der Zertifikatauthentifizierung client_secret={secret} durch dasselbe client_assertion_type + client_assertion-Paar wie bei S2S.
Das zurückgegebene Token enthält appid/azp = {your-app-id}, scp enthält Agent365.Observability.OtelWriteund .aud = 9b975845-... Verwenden Sie es auf der /observability/.../traces-Route. Zusätzlich wird ein Refresh-Token zurückgegeben; speichern Sie es im Cache und verwenden Sie es wieder, anstatt den Austauschvorgang bei jedem Aufruf erneut auszuführen.
OBO, aus dem Blueprint abgeleitete Agentenidentität (einschließlich KI-Teammitglied)
Es gibt drei Hauptschritte des On-behalf-of-Flows. Weitere Informationen finden Sie unter "Agent OAuth flows: On behalf of flow".
Empfangen des Benutzertokens
Tc. Für einen KI-Teamkollegen stellt dieses Token das eigene Benutzerkonto des Agenten dar; andernfalls stellt sie den menschlichen Aufrufer dar.Das Blueprint authentifiziert sich und ruft
T1ab, genauso wie der aus dem S2S-Blueprint abgeleitete Agent-Identitätsfluss.Die Agentenidentität tauscht
T1undTcgegen ein delegiertes Ressourcentoken aus: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
Das zurückgegebene Token enthält appid/azp = {agent-identity-app-id}, scp enthält Agent365.Observability.OtelWriteund stellt den Benutzer des Agents dar. Verwenden Sie es auf der /observability/.../traces-Route. Die URL {agentId} ist die Agent-Identitäts-appId, nicht die Blueprint-AppId. Daneben wird ein Aktualisierungstoken zurückgegeben; zwischenspeichern und wiederverwenden. Der delegierte Pfad erfordert den delegierten Bereich und die Zustimmung des Mandantenadministrators.
Erforderliche Ansprüche für das zurückgegebene Token
S2S-Route (/observabilityService/...) – Nur-App-Token:
| Anspruch | Erforderlicher Wert |
|---|---|
aud |
9b975845-388f-4429-889e-eab1ef63949c (oder api://9b975845-...) |
roles |
Für eine Agent 365-registrierte Agent-Instanz ist das nicht erforderlich. Für eine nicht registrierte Identität muss Agent365.Observability.OtelWrite enthalten sein. |
appid (v1) oder azp (v2) |
Muss URL entsprechen {agentId} |
scp |
Muss nicht vorhanden sein |
Delegierte Route (/observability/...) - benutzerdelegiertes Token (Bearer oder PFAT):
| Anspruch | Erforderlicher Wert |
|---|---|
aud |
9b975845-388f-4429-889e-eab1ef63949c (oder api://9b975845-...) |
scp |
Muss Agent365.Observability.OtelWrite enthalten |
appid / azp |
Muss URL entsprechen {agentId} |
Die delegierte Route akzeptiert sowohl Bearer- als auch MSAuth1.0 PFAT-Token. Direkte Anrufer sollten verwenden Bearer. Wenn Sie nicht wissen, welches Sie haben, verwenden Sie Bearer.
Endpoints
Zwei Routen; wählen Sie aus, wie Sich Ihr Dienst authentifiziert, nicht durch die Aktionen des Benutzers:
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
Kopfzeilen:
Authorization: Bearer <token> # or MSAuth1.0 ... for delegated PFAT
Content-Type: application/json
URL-Parameter
-
{tenantId}- die Kundenmandanten-GUID. Der Server behandelt diesen Wert als maßgeblich. Wenn die von Ihnen aufmicrosoft.tenant.idgesetzten Spans nicht übereinstimmen, lehnt der Server die Anfrage ab. -
{agentId}- die appId der aufrufenden Anwendung (auch OAuthclient_id). Für vom Blueprint abgeleitete Identitäten ist dieser Wert die Agentenidentität appId, nicht die Blueprint appId. Es muss mit demappid- oderazp-Claim Ihres Tokens übereinstimmen. -
api-version=1- erforderlich.
Überprüfe die Mieterberechtigung
Integrierte Drittanbieter-Integrationen, die das S2S-Authentifizierungsmodell verwenden, können prüfen, ob ein Kundenmieter für die Agent-365-Observabilität berechtigt ist, bevor sie eine Integration aktivieren oder Telemetrie senden. Diese Überprüfung kann Integrationen helfen, Telemetrie für Mieter zu vermeiden, die derzeit nicht berechtigt sind.
Verwenden Sie dasselbe reine App-Token wie in der S2S-Authentifizierung beschrieben.
Das Token muss die Agent365.Observability.OtelWrite App-Rolle enthalten, und sein tid Claim muss mit {tenantId} in der Anfrage-URL übereinstimmen.
GET https://agent365.svc.cloud.microsoft/observabilityService/tenants/{tenantId}/eligibility?api-version=1
Authorization: Bearer <access-token>
Eine erfolgreiche Antwort enthält das Eignungsergebnis:
{
"enabled": true
}
Gehen Sie mit der Antwort wie folgt um:
| Status | Bedeutung | Clientaktion |
|---|---|---|
200 OK, enabled: true |
Der Mieter ist für Observability berechtigt. | Die Integration kann Telemetrie senden. |
200 OK, enabled: false |
Der Mieter ist derzeit nicht für Observability berechtigt. | Senden Sie keine Telemetrie. Überprüfen Sie, ob der Mieter die Voraussetzungen erfüllt, und überprüfen Sie es erneut, nachdem sich sein Status geändert hat. Wenn Telemetrie trotzdem gesendet wird, kann der Ingestionsendpunkt 200 OK zurückgeben, dabei aber die Spans ablehnen. |
400 Bad Request |
{tenantId} leer oder ungültig ist. |
Korrigiere die Mieter-ID, bevor du es erneut versuchst. |
401 Unauthorized |
Das access Token fehlt oder ist ungültig. | Erhalte ein gültiges Token für die Agent 365 Observability-Ressource. |
403 Forbidden |
Dem Token fehlt die erforderliche App-Rolle, oder sein Tenant stimmt nicht mit {tenantId} überein. |
Beheben Sie den Berechtigungs-, Zustimmungs- oder Mandantenkonflikt, bevor Sie es erneut versuchen. |
429 Too Many Requests |
Der Anrufer hat die Berechtigungsbeantragungsgrenze überschritten. |
Retry-After beachten und mit Backoff und Jitter erneut versuchen. |
503 Service Unavailable |
Die Berechtigung konnte nicht festgestellt werden. Die Antwort hat keinen Inhalt. | Beachten Sie Retry-After: 30 und versuchen Sie es erneut. Behandle diese Reaktion nicht als enabled: false. |
Kodierung des Anfragetexts
Der Nachrichtentext verwendet das Standard-OTLP/HTTP+JSON-Format: ein ExportTraceServiceRequest mit der Struktur resourceSpans → scopeSpans → spans. Beachten Sie die folgenden Details:
- Senden
traceId(16 Bytes) undspanId(8 Bytes) als Kleinbuchstaben-Hex-Strings. -
startTimeUnixNanoundendTimeUnixNanosind Strings, die Unix-Epochen-Nanosekunden enthalten. -
kindist der ganzzahlige OTLP-Enumwert (zum Beispiel1fürINTERNAL).status.codeist das ganzzahlige Enum (zum Beispiel1fürOK,2fürERROR). - Senden Sie alle Attributwerte als
stringValue.
Antwortform
Eine Antwort bedeutet, dass Agent 365 die Anfrage bearbeitet hat 200 OK . Es wird nicht garantiert, dass jeder Abschnitt an ein Ziel weitergeleitet wurde. Überprüfen Sie sowohl partialSuccess als auch results.
Das Array results meldet das Ergebnis für jede Spannweite an jedem relevanten Ziel:
-
sent- der Span wurde an das Ziel weitergeleitet. -
rejected- die Leiterbahn wurde nicht geroutet. Das Feldreasonerklärt warum. -
not_routed- Das Ziel wurde für die Spannweite nicht ausgewählt. Das Feldreasonerklärt warum.
Zum Beispiel kann eine erfolgreich geroutete Spann Folgendes zurückgeben:
{
"partialSuccess": {
"rejectedSpans": 0,
"errorMessage": ""
},
"results": [
{
"spanId": "0123456789abcdef",
"sinks": {
"flashpoint": {
"status": "sent"
},
"sentinel": {
"status": "sent"
},
"esp": {
"status": "sent"
}
}
}
]
}
Wenn der Mieter nicht berechtigt ist, kann die Anforderung trotzdem 200 OK zurückgeben. In diesem Fall zeigt results, dass die Spannen abgelehnt wurden:
{
"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"
}
}
}
]
}
Für Routing-Entscheidungen für die gesamte Anfrage kann 0 weiterhin results bleiben, auch wenn partialSuccess.rejectedSpans zeigt, dass jeder Span abgelehnt wurde. Verwende weder partialSuccess noch den HTTP-Status allein als Nachweis für die Ingestion. Feldnamen werden bei der Übertragung in camelCase geschrieben. Weitere Gründe, aus denen Telemetrie möglicherweise nicht angezeigt wird, finden Sie unter Grenzwerte und Verwerfungsbedingungen.
Kleinste mögliche Anforderung
Der einfachste End-to-End-Test sendet eine einzelne invoke_agent Spanne. Diese Spanne ist der kleinste Körper, der in Microsoft Defender landet.
Schritt 1. Rufen Sie ein Bearer-Token ab. Verwenden Sie für S2S Clientanmeldeinformationen mit Bereich 9b975845-388f-4429-889e-eab1ef63949c/.default (siehe Authentifizierungsrezepte für das vollständige Rezept).
Schritt 2. Eine einzelne Spanne per POST senden:
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
Schritt 3: Erwarten Sie 200 OK, und überprüfen Sie dann results, wie in Antwortstruktur beschrieben. Bestätigen Sie, dass die entsprechenden Ziele den Status sent haben.
Schritt 4. Bestätigen Sie, dass die Daten tatsächlich gelandet sind. Ein HTTP-Statuscode 200 OK ist kein Nachweis der Erfassung; siehe Überprüfen der Erfassung für den Ablauf zur Überprüfung. Um stattdessen eine gespeicherte Body-Datei zu POSTEN, ersetzen Sie --data @- <<EOF ... EOF durch --data @./otlp-request.json.
Beispiel für einen Agentenlauf
Ein Benutzer auf Microsoft Teams fragt "Was ist das Wetter in Seattle?". Ihr Agent ruft eine GetWeather Funktion auf, bittet ein LLM, die Antwort zu formatieren, und antwortet. Dieser einzelne Lauf umfasst vier Abschnitte:
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
Laufweite Attribute, die für jede every Textspanne festgelegt sind:
| Attribute | Beispielwert |
|---|---|
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
Diese laufweiten Attribute verbreiten sich nicht automatisch. Du musst microsoft.channel.name, microsoft.session.id und gen_ai.conversation.id für jeden Span festlegen.
Span A: invoke_agent (Wurzel)
{
"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-Aufruf)
{
"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 */
]
}
Span 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 */
]
}
Spanne 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 */
]
}
Senden von Telemetriedaten
Verwenden Sie ein OTel SDK
Die meisten Partner senden Traces über ein OTel-SDK statt über selbst implementiertes HTTP. Das SDK übernimmt für Sie die Stapelverarbeitung, Wiederholungsversuche und die OTLP/HTTP+JSON-Kodierung. Legen Sie den Exporter-Endpunkt fest und fügen Sie den Authorization-Header ein.
Der Exporterendpunkt ist die Routen-URL selbst, einschließlich der Abfragezeichenfolge:
https://agent365.svc.cloud.microsoft/observabilityService/tenants/{tenantId}/otlp/agents/{agentId}/traces?api-version=1
(Verwenden Sie /observability/... anstelle von /observabilityService/... für die delegierte Route.)
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}"},
)
Paket: 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}` },
});
Paket: @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;
}));
Paket: OpenTelemetry.Exporter.OpenTelemetryProtocol.
HTTP manuell
Wenn Sie kein OTel-SDK verwenden können oder möchten, erstellen Sie die OTLP/HTTP+JSON-Anfrage selbst und senden Sie sie per POST. Die OpenTelemetry OTLP/HTTP+JSON-Spezifikation definiert die Körperform:
{
"resourceSpans": [{
"resource": { "attributes": [ ... ] }, // optional
"scopeSpans": [{
"scope": { "name": "<your-instrumentation>", "version": "1.0.0" },
"spans": [ <span>, <span>, ... ]
}]
}]
}
Jedes <span> Objekt ist ein Objekt, dessen erforderliche Felder sind traceId, , spanId, name, kind, startTimeUnixNano, endTimeUnixNano, , und attributes(für Nicht-Stamm-Spans) parentSpanId. Für Codierungsregeln (stringcodierte Zeiten, hexazymaltraceId / spanId, ganzzahlig / kindstatus.code , alle Attributwerte als stringValue), siehe Endpunkte und Request-Body-Codierung.
Der Satz von Attributen, die für jeden Bereich festgelegt werden sollen, wird in Nachrichtenverträgen definiert. Für die vollständige Attributliste siehe Attributreferenz. Verweisen Sie auf das Agent-Ausführungsbeispiel für ein End-to-End-Arbeitsbeispiel mit dem Bearer-Token in der Kopfzeile und dem Textkörper inline.
Sie können alle Spannen einer Ausführung in einem einzelnen POST-Textkörper (bevorzugt – eine Anforderung, eine Ablaufverfolgung) oder über mehrere POSTs senden. Der Server rekonstruiert den Ablauf anhand von traceId + parentSpanId + gen_ai.conversation.id, sodass jeder Span genügend Informationen enthält, um in beide Richtungen korreliert werden zu können.
Nachrichtenverträge
In diesem Abschnitt wird definiert, welche Spans Sie erzeugen können und welche Attribute jeweils zu ihnen gehören. Die vollständige Attribut-nach-Attribut-Spezifikation finden Sie in der Attributreferenz.
Vorgangstypen
Jede von Ihnen gesendete Zeitspanne muss einen dieser vier Werte aufweisen gen_ai.operation.name (Groß-/Kleinschreibung wird nicht beachtet). Der Server lässt jede Spanne mit fehlendem oder nicht erkanntem Wert fallen und zählt sie in partialSuccess.rejectedSpans.
gen_ai.operation.name |
Bedeutung | Der meistgesuchte Fallstrick |
|---|---|---|
invoke_agent |
Aufruf eines Agenten. Die „Wurzel“ eines Agentenlaufs. | Erforderlich, damit die Ausführung in den Microsoft Defender-Ansichten zur Agentenaktivität oder im Microsoft 365 Admin Center angezeigt wird. Ohne sie landet die Telemetrie nur in der erweiterten Suche von Microsoft Defender (CloudAppEvents). |
execute_tool |
Ein Tool-/Funktionsaufruf, der von einem Agent ausgeführt wird. | -- |
chat |
Ein LLM-Inferenzaufruf. |
Verwenden Sie das Literal chat, NICHT inference. |
output_messages |
Eine abschließende ausgegebene Meldung. | -- |
Span-Hierarchie und Run-Gruppierung
Agent 365 rekonstruiert einen Lauf aus dem Standard-OTLP-Span-Graphen (traceId, spanId, parentSpanId) sowie den für den Lauf geltenden Attributen aus der Attributreferenz.
Sechs Regeln:
-
Immer festlegen
parentSpanIdauf jeder Nicht-Stammspanne. Ohne diese können Sie die Baumstruktur des Runs nicht wiederherstellen. -
Dasselbe
traceIdüber alle Spans in einem Durchlauf hinweg wiederverwenden. -
Legen Sie
gen_ai.conversation.idfür jeden Bereich mit demselben Wert fest. Dieser Wert ist der primäre Join-Schlüssel für „alle Spannen in dieser Ausführung“. Es wird nicht automatisch weitergegeben. -
Legen Sie
microsoft.channel.namefür jeden Bereich mit demselben Wert fest. Tool-Spans, denen der Kanal oder die Konversation fehlen, können diese nur von ihrem übergeordneteninvoke_agentSpan übernehmen, wenn sich der übergeordnete Span in derselben OTLP-Anfrage befindet. Legen Sie sie daher bei jedem Span selbst fest. -
Legen Sie
microsoft.session.idfür jede Spanne fest , wenn Sie eine logische Sitzung haben. - Verwenden Sie für Agent-zu-Agent-Aufrufe, bei denen sich der untergeordnete Agent in einer separaten Anfrage befindet, dasselbe
gen_ai.conversation.idwieder und verwenden Sie die Attributemicrosoft.a365.caller.agent.*(siehe Attributreferenz), um den Kontext des aufrufenden Agenten zu erfassen.
Die vierspannige Struktur im Beispiel für die Agent-Ausführung ist die kanonische Form.
Allgemeine Formen
| Gestalt | Zu emittierende Spannweiten | Hinweise |
|---|---|---|
| Einzel-Agent-Chatbot (keine Tools, keine LLM-Spanne) | Nur ein invoke_agent |
Legen Sie run-weite Attribute sowie gen_ai.input.messages und gen_ai.output.messages fest. Identisch mit der kleinsten möglichen Anforderung. |
| Agent mit Tools (am häufigsten) |
invoke_agent Stamm + chat, execute_tool, output_messages untergeordnete Elemente |
Alle Kinder verwenden das traceId des Stammelements und setzen parentSpanId = root.spanId. Alle weisen dieselben Attribute für den gesamten Textlauf auf. Ein vollständiges Beispiel finden Sie unter Beispiel für einen Agentenlauf. |
| Agent-zu-Agenten | Jeder Agent emittiert seine eigene invoke_agent |
Verwenden Sie dasselbe gen_ai.conversation.id für beide Agents. Legen Sie im invoke_agent des Ziels gen_ai.execution.type = "Agent2Agent" und die Attribute microsoft.a365.caller.agent.* fest (die appId des aufrufenden Agenten, den Namen, die Blueprint-appId, die Benutzer-ID und die E-Mail). Wenn der aufrufende Agent über keine Entra-Registrierung verfügt, verwenden Sie stattdessen microsoft.a365.caller.agent.platform.id und gen_ai.caller.agent.type. |
Checkliste für Produktions-Onboarding
Führen Sie diese Checkliste durch, bevor Sie zur Produktion wechseln.
| Category | Prüfen |
|---|---|
| Authentifizierung | Ihre Entra-App (oder Ihr Blueprint) ist registriert und Sie können dafür Tokens erstellen. |
| Authentifizierung | Wenn du auf der S2S-Route eine von Blueprint abgeleitete Identität verwendest, ist die Agenteninstanz bei Agent 365 registriert. Eine registrierte Instanz benötigt nicht die Agent365.Observability.OtelWrite App-Rolle. |
| Authentifizierung | Wenn du auf der S2S-Route eine nicht registrierte Identität verwendest, erhält deine App die Agent365.Observability.OtelWrite App-Rolle. |
| Authentifizierung | Wenn du die delegierte Route nutzt, erhält deine App den delegierten Agent365.Observability.OtelWrite Bereich. |
| Authentifizierung | Jeder Agent verfügt über eine eigene Entra-appId als {agentId} in der URL. Bei von Blueprint abgeleiteten Identitäten ist diese appId die Agent-Identitäts-AppId, nicht die Blueprint-AppId. Wenn der Agent keine Entra-Registrierung hat, siehe Werte auswählen. |
| Authentifizierung | Ein Tenant-Admin erteilt die Zustimmung für Agent365.Observability.OtelWrite, wenn die Route die App-Rolle oder den delegierten Scope erfordert. Ohne erforderliche Zustimmung werden Token ohne Rolle oder Umfang ausgegeben, und Anfragen werden mit 403abgelehnt. |
| Lizenzierung | Mindestens ein Benutzer im Kundenmandanten verfügt über eine Microsoft 365 E7- oder Microsoft Agent 365-Lizenz zugewiesen (Zuordnung, nicht nur SKU-Anwesenheit im Mandanten). Ohne eine zugewiesene Lizenz zeigen die results der Antwort, dass die Textspannen abgelehnt wurden. Siehe Voraussetzungen. |
| Spannweiten | Jeder Span definiert die runweiten Grundlagen (Span-Hierarchie und Run-Gruppierung). |
| Spannweiten |
invoke_agent Spanmenge gen_ai.input.messages und gen_ai.output.messages. |
| Spannweiten |
execute_tool Spannenmenge gen_ai.tool.name, gen_ai.tool.type, gen_ai.tool.call.id, gen_ai.tool.call.arguments, gen_ai.tool.call.result. |
| Spannweiten |
chat setzt gen_ai.request.model und gen_ai.provider.name fest (und idealerweise gen_ai.usage.input_tokens / gen_ai.usage.output_tokens – als Zeichenfolge codiert). |
| Spannweiten | Alle Nicht-Root-Spans sind auf parentSpanId gesetzt; alle Spans in einem Lauf haben dieselbe traceId. |
| Nutzlast | Der Anfragetextkörper ist ≤ 1 MB. |
| Überprüfung | Du inspizierst beide partialSuccess und results bei jeder Antwort und protokollierst Ablehnungen. |
| Überprüfung | Sie haben den Verifizierungsablauf in Verifying ingestion anhand Ihrer ersten Durchläufe ausgeführt. |
Nächste Schritte
- Attributreferenz – Spezifikation je Attribut und Leitfaden zur Wertauswahl.
- Problembehandlung : Überprüfen der Aufnahme, allgemeiner Fallstricke und Fehlerantworten.