Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Apprenez à intégrer l’observabilité de l’agent avec l’Agent 365 en envoyant la télémétrie directement via OpenTelemetry (OTLP/HTTP+JSON). Cette approche aide les agents qui ne peuvent pas utiliser le SDK Agent 365 ou la distribution Microsoft OpenTelemetry à envoyer la télémétrie de manière efficace et sécurisée. Avant de commencer, lisez les concepts d’observabilité de l’Agent 365 pour comprendre le modèle, les flux d’authentification et l’emplacement de vos données.
Important
Le chemin OTel direct est l’exception, et non la valeur par défaut. Utilisez-le uniquement si vous disposez déjà d'un pipeline OpenTelemetry, que votre infrastructure ne peut pas utiliser le Kit de développement logiciel (SDK) Agent 365, ou que votre agent se trouve dans un langage que le Kit de développement logiciel (SDK) ne prend pas encore en charge (par exemple, Java). Pour tous les autres, l’approche recommandée est Microsoft OpenTelemetry Distro, qui fournit un SDK d’observabilité unifié pour Agent 365, Microsoft Foundry, Azure Monitor et plus encore. Le SDK Observability précédent continue de fonctionner sans changements majeurs incompatibles, mais il n’est plus recommandé pour les nouvelles intégrations ; des directives de migration destinées aux utilisateurs existants du SDK seront bientôt disponibles.
Prerequisites
Vérifiez que les configurations suivantes sont en place avant les flux de télémétrie.
| Qui | What |
|---|---|
| Administrateur du locataire | Inscrivez-vous à Agent 365 et accordez votre consentement pour votre application agent. Voir Intégration à l’agent 365. En l’absence de locataire éligible, l’ingestion peut renvoyer 200 OK même si les results de la réponse indiquent que les spans ont été rejetés. |
| Administrateur du locataire |
Attribuez une licence Microsoft 365 E7 ou Microsoft Agent 365 à au moins un utilisateur du locataire. La référence SKU présente n’est pas suffisante. L’affectation à un utilisateur démarre le flux de travail principal Defender qui active l’ingestion. Sans licence attribuée, l’ingestion peut renvoyer 200 OK tout en rejetant les segments. |
| Administrateur du locataire | Accordez le consentement du locataire. Consultez Autoriser les agents à accéder aux ressources Microsoft 365. Sans cela, les jetons sont émis sans le rôle/la portée, et les requêtes renvoient 403. |
| Votre équipe de développement | Inscrivez votre application (application standard Microsoft Entra ou blueprint). Voir Identité de l’agent. |
| Votre équipe de développement | Ajouter Agent365.Observability.OtelWrite dans Autorisations de l’API (rôle d’application pour S2S, portée pour les autorisations déléguées). Pour les blueprints, consultez Configurer les autorisations héritées. Coordonnez-vous avec l’équipe d’intégration Agent 365 pour activer l’autorisation. |
Recettes d’authentification
Les quatre recettes utilisent le point de terminaison standard des jetons Microsoft Entra :
| Champ | Valeur |
|---|---|
| Point de terminaison de jeton | https://login.microsoftonline.com/{your-tenant-id}/oauth2/v2.0/token |
Ressource (aud dans le jeton retourné) |
9b975845-388f-4429-889e-eab1ef63949c (accepte également api://9b975845-388f-4429-889e-eab1ef63949c) |
| Étendue S2S | 9b975845-388f-4429-889e-eab1ef63949c/.default |
| Étendue OBO | 9b975845-388f-4429-889e-eab1ef63949c/Agent365.Observability.OtelWrite |
Les recettes suivantes montrent HTTP brut pour plus de clarté. En production, utilisez Microsoft. Identity.Web ou une autre bibliothèque MSAL, qui gère le rafraîchissement des jetons et la mise en cache.
Quelle recette ai-je besoin ?
| Mon modèle d’application | Mon flux OAuth | Accéder à |
|---|---|---|
| Inscription d’application Microsoft Entra standard | S2S (informations d’identification du client) | S2S, application Microsoft Entra standard |
| Inscription d’application Microsoft Entra standard | OBO (délégué) | OBO, application standard Microsoft Entra |
| Identité de l’agent issue d’un modèle | S2S (informations d’identification du client) | Identité de l’agent dérivé de Blueprint S2S |
| Identité de l’agent issue d’un modèle | OBO / Collègue d’IA | OBO, identité d’agent dérivée de Blueprint |
S2S, application standard Microsoft Entra
Envoyez une requête POST au point de terminaison du token du locataire avec grant_type=client_credentials. Authentifiez l’application à l’aide d’une clé secrète client, d’un certificat (assertion JWT signée) ou d’une identité managée ou d’informations d’identification fédérées.
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
Le jeton retourné a appid/azp = {your-app-id}, roles contenant Agent365.Observability.OtelWriteet .aud = 9b975845-... Utilisez-le sur l’itinéraire /observabilityService/.../traces.
Pour l’authentification basée sur un certificat, remplacez client_secret={secret} par client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion={signed-jwt}.
S2S, identité d’agent dérivée d’un plan
Les identités d’agent n’ont pas d'identifiants propres. Le blueprint d’identité de l’assistant contient les informations d’identification (identité managée FIC, certificat ou secret client) et émet des jetons pour le compte de (on behalf of) ses identités d’assistant enfants au moyen d’un échange en deux étapes. Pour plus d’informations, consultez le flux OAuth pour application autonome.
Le blueprint s’authentifie et obtient un jeton d’échange d’identité fédérée
T1:-
{blueprint-credential}est le jeton MSI du blueprint, le JWT signé par certificat ou l’assertion de jeton d’échange secret par configuration de blueprint.
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-
L’identité de l’assistant échange
T1contre le jeton de la ressource Agent 365 Observability :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- Le jeton retourné a
appid/azp={agent-identity-app-id},rolescontenantAgent365.Observability.OtelWriteet .aud=9b975845-... - Utilisez ce jeton sur l’itinéraire
/observabilityService/.../traces. - L’URL
{agentId}correspond à l’appId d’identité de l’agent, et non à l’appId du plan directeur.
- Le jeton retourné a
OBO, application Microsoft Entra standard
Recevez le jeton utilisateur entrant Tc de l’appelant en amont (Bearer ou PFAT), puis échangez-le :
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
Pour l’authentification de certificat, remplacez client_secret={secret} par la même client_assertion_type + client_assertion paire que dans S2S.
Le jeton retourné a appid/azp = {your-app-id}, scp contenant Agent365.Observability.OtelWriteet .aud = 9b975845-... Utilisez-le sur l’itinéraire /observability/.../traces. Un jeton d’actualisation est retourné en même temps ; mettez en cache et réutilisez-le au lieu de réexécuter l’échange sur chaque appel.
OBO, identité d’assistant issue du blueprint (y compris un coéquipier IA)
Le flux On-Behalf-Of comporte trois étapes principales. Pour plus d’informations, consultez Flux OAuth de l’assistant : Flux On-Behalf-Of.
Recevez le jeton utilisateur
Tc. Pour un coéquipier IA, ce jeton représente le propre compte d’utilisateur de l’agent ; sinon, il représente l’appelant humain.Le blueprint s’authentifie et obtient
T1, identique au flux d’identité de l’agent dérivé du blueprint S2S.L’identité de l’assistant échange
T1etTccontre un jeton de ressource délégué :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
Le jeton retourné a appid/azp = {agent-identity-app-id}, scp contenant Agent365.Observability.OtelWriteet représente l’utilisateur de l’agent. Utilisez-le sur l’itinéraire /observability/.../traces. L’URL {agentId} correspond à l’appId d’identité de l’agent, et non à l’appId du plan directeur. Un jeton d’actualisation est retourné en même temps ; mettez en cache et réutilisez-le.
Revendications requises sur le jeton retourné
Route S2S (/observabilityService/...) - jeton d’application uniquement :
| Réclamation | Valeur requise |
|---|---|
aud |
9b975845-388f-4429-889e-eab1ef63949c (ou api://9b975845-...) |
roles |
Doit contenir Agent365.Observability.OtelWrite |
appid (v1) ou azp (v2) |
Doit correspondre à l’URL {agentId} |
scp |
Doit être absent |
Itinéraire délégué (/observability/...) - jeton délégué utilisateur (Bearer ou PFAT):
| Réclamation | Valeur requise |
|---|---|
aud |
9b975845-388f-4429-889e-eab1ef63949c (ou api://9b975845-...) |
scp |
Doit contenir Agent365.Observability.OtelWrite |
appid / azp |
Doit correspondre à l’URL {agentId} |
La route déléguée accepte à la fois les jetons Bearer et MSAuth1.0 PFAT. Les appelants directs doivent utiliser Bearer. Si vous ne savez pas lequel vous avez, utilisez Bearer.
Endpoints
Deux itinéraires ; choisissez la façon dont votre service s’authentifie, et non par ce que fait l’utilisateur :
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
En-têtes :
Authorization: Bearer <token> # or MSAuth1.0 ... for delegated PFAT
Content-Type: application/json
Paramètres URL
-
{tenantId}- le GUID du locataire client. Le serveur considère cette valeur comme faisant autorité. Si vos spans sont configurésmicrosoft.tenant.idet qu’ils ne correspondent pas, le serveur rejette la requête. -
{agentId}- appId de l’application appelante (également OAuthclient_id). Pour les identités dérivées du blueprint, cette valeur correspond à l’identité de l’agent appId, et non à l’appId du blueprint. Il doit correspondre à l’attributappidouazpde votre jeton. -
api-version=1-Obligatoire.
Vérifiez l’éligibilité du locataire
Les intégrations tierces intégrées utilisant le modèle d’authentification S2S peuvent vérifier si un locataire client est éligible à l’observabilité de l’Agent 365 avant d’activer une intégration ou d’envoyer une télémétrie. Cette vérification peut aider les intégrations à éviter d’envoyer des télémétries pour les locataires qui ne sont pas actuellement éligibles.
Utilisez le même jeton uniquement applicatif décrit dans l’authentification S2S.
Le jeton doit contenir le rôle d’application Agent365.Observability.OtelWrite, et la revendication tid doit correspondre à {tenantId} dans l’URL de la requête.
GET https://agent365.svc.cloud.microsoft/observabilityService/tenants/{tenantId}/eligibility?api-version=1
Authorization: Bearer <access-token>
Une réponse retenue contient le résultat d’éligibilité :
{
"enabled": true
}
Gérez la réponse comme suit :
| État | Sens | Action du client |
|---|---|---|
200 OK, enabled: true |
Le locataire est éligible à l’observabilité. | L’intégration peut envoyer de la télémétrie. |
200 OK, enabled: false |
Le locataire n’est actuellement pas éligible à l’observabilité. | N’envoyez pas de télémétrie. Vérifiez que le locataire remplit les prérequis, puis vérifiez à nouveau après que son statut change. Même si la télémétrie est envoyée, le point de terminaison d’ingestion peut renvoyer 200 OK tout en rejetant les spans. |
400 Bad Request |
{tenantId} est vide ou invalide. |
Corrigez l’identifiant locataire avant de réessayer. |
401 Unauthorized |
Le jeton d'accès est manquant ou non valide. | Acquérez un jeton valide pour la ressource Agent 365 Observabilité. |
403 Forbidden |
Le jeton n’a pas le rôle requis dans l’application, ou bien son tenant ne correspond {tenantId}pas à celui de l’application . |
Corrigez la permission, le consentement ou le décalage entre locataires avant de réessayer. |
429 Too Many Requests |
L’appelant a dépassé la limite d’éligibilité demandée. | Honorez Retry-After et réessayez avec du recul et du trac. |
503 Service Unavailable |
L’éligibilité n’a pas pu être déterminée. La réponse n’a pas de contenu. | Respectez Retry-After: 30 et réessayez. Ne traitez pas cette réponse comme enabled: false. |
Encodage du corps de la requête
Le corps utilise le format standard OTLP/HTTP+JSON : un ExportTraceServiceRequest avec resourceSpans → scopeSpans → spans. Gardez à l’esprit les détails suivants :
- Envoyer
traceId(16 octets) etspanId(8 octets) en chaînes hexagonales minuscules. -
startTimeUnixNanoetendTimeUnixNanosont des chaînes qui contiennent des nanosecondes d’époque Unix. -
kindest la valeur entière de l’enum OTLP (par exemple,1pourINTERNAL).status.codeest l’enum entier (par exemple,1pourOK,2pourERROR). - Envoyez toutes les valeurs d’attribut en tant que
stringValue.
Forme de réponse
Une 200 OK réponse signifie que l’Agent 365 a traité la demande. Cela ne garantit pas que chaque travée a été acheminée vers une destination. Inspectez à la fois partialSuccess et results.
Le results tableau indique le résultat pour chaque segment à chaque destination applicable :
-
sent- la travée était acheminée vers la destination. -
rejected- le span n’a pas été acheminé. Lereasondomaine explique pourquoi. -
not_routed- la destination n’a pas été sélectionnée pour le span. Lereasondomaine explique pourquoi.
Par exemple, un span acheminé avec succès peut renvoyer :
{
"partialSuccess": {
"rejectedSpans": 0,
"errorMessage": ""
},
"results": [
{
"spanId": "0123456789abcdef",
"sinks": {
"flashpoint": {
"status": "sent"
},
"sentinel": {
"status": "sent"
},
"esp": {
"status": "sent"
}
}
}
]
}
Si le client n’est pas éligible, la requête peut quand même renvoyer 200 OK. Dans ce cas, results indique que les spans ont été rejetés :
{
"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"
}
}
}
]
}
Pour les décisions de routage de requête entière, partialSuccess.rejectedSpans peut rester 0 même lorsque results indique que chaque span a été rejeté. N’utilisez pas partialSuccess ni le seul code d’état HTTP comme preuve que l’ingestion a bien eu lieu. Les noms de champs utilisent le format camelCase dans les échanges réseau. Voir Limites et conditions de suppression pour connaître d’autres raisons pour lesquelles la télémétrie peut ne pas apparaître.
Demande la plus petite possible
Le test de bout en bout le plus simple envoie un unique invoke_agent span. Ce span est le plus petit élément qui arrive dans Microsoft Defender.
Étape 1. Obtenez un jeton Bearer. Pour S2S, utilisez les identifiants client avec la portée 9b975845-388f-4429-889e-eab1ef63949c/.default (voir Recettes d’authentification pour la procédure complète).
Étape 2. POST un seul segment :
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
Étape 3. Attendez-vous à 200 OK, puis inspectez results comme décrit dans la structure de réponse. Confirmez que les destinations concernées ont un statut de sent.
Étape 4. Vérifiez que les données ont réellement atterri. Un 200 OK n’est pas une preuve d’ingestion ; voir Vérification de l’ingestion pour le flux de vérification. Pour effectuer une requête POST avec un fichier de corps de requête enregistré à la place, remplacez --data @- <<EOF ... EOF par --data @./otlp-request.json.
Exemple d’exécution de l’agent
Un utilisateur sur Microsoft Teams demande « Quelle est la météo à Seattle ? ». Votre agent appelle une fonction GetWeather, demande à un LLM de mettre en forme la réponse, puis répond. Cette seule exécution comporte quatre spans :
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
Attributs à l’échelle de l’exécution définis sur chaque span :
| Attribute | Exemple de valeur |
|---|---|
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
Ces attributs à l’échelle de l’exécution ne se propagent pas automatiquement. Vous devez régler gen_ai.conversation.id, microsoft.channel.name, et microsoft.session.id sur chaque travée.
Étendue A : invoke_agent (racine)
{
"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 (appel 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 */
]
}
Étendue 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 */
]
}
Étendue 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 */
]
}
Envoyer des données de télémétrie
Utilisez un SDK OTel
La plupart des partenaires envoient des traces via un SDK OTel plutôt que via une implémentation HTTP codée à la main. Le Kit de développement logiciel (SDK) gère le traitement par lots, les nouvelles tentatives et l’encodage OTLP/HTTP+JSON pour vous. Définissez le point de terminaison de l’exportateur et injectez l’en-tête Authorization .
Le point de terminaison de l’exportateur est l’URL de routage elle-même, y compris la chaîne de requête :
https://agent365.svc.cloud.microsoft/observabilityService/tenants/{tenantId}/otlp/agents/{agentId}/traces?api-version=1
(Utilisez /observability/... plutôt que /observabilityService/... pour l’itinéraire délégué.)
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}"},
)
Paquet : 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}` },
});
Paquet : @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;
}));
Paquet : OpenTelemetry.Exporter.OpenTelemetryProtocol.
HTTP manuel
Si vous ne pouvez pas ou ne souhaitez pas utiliser un SDK OTel, générez la requête OTLP/HTTP+JSON vous-même et postez-la. La spécification OTLP/HTTP+JSON d'OpenTelemetry définit la structure du corps :
{
"resourceSpans": [{
"resource": { "attributes": [ ... ] }, // optional
"scopeSpans": [{
"scope": { "name": "<your-instrumentation>", "version": "1.0.0" },
"spans": [ <span>, <span>, ... ]
}]
}]
}
Chaque <span> est un objet dont les champs obligatoires sont traceId, spanId, name, kind, startTimeUnixNano, endTimeUnixNano, attributes et, (pour les spans non racine) parentSpanId. Pour les règles d’encodage (temps encodés par chaîne, hexadécimal traceId / spanId, entierstatus.codekind / , toutes les valeurs d’attribut comme stringValue), voir Terminaux et encodage du corps de requête.
L’ensemble d’attributs à définir sur chaque étendue est défini dans les contrats de message. Pour la liste complète des attributs, voir Référence attribut. Reportez-vous à l’exemple d’exécution d’assistant pour obtenir un exemple fonctionnel complet avec le jeton du porteur dans l’en-tête et le corps inclus directement.
Vous pouvez envoyer tous les spans d’un run dans un seul corps de requête POST (de préférence : une requête, une trace) ou dans plusieurs requêtes POST. Le serveur reconstruit l’exécution à partir de traceId + parentSpanId + gen_ai.conversation.id, de sorte que chaque span contient suffisamment d’informations pour être corrélé dans les deux sens.
Contrats de messages
Cette section définit quels spans vous pouvez générer et quels attributs sont associés à chacun d’eux. Pour obtenir la spécification d’attribut par attribut complète, consultez la référence d’attribut.
Types d’opération
Chaque span que vous envoyez doit avoir gen_ai.operation.name défini sur l’une de ces quatre valeurs (sans distinction de casse). Le serveur supprime toute plage avec une valeur manquante ou non reconnue et la compte dans partialSuccess.rejectedSpans.
gen_ai.operation.name |
Sens | Le piège le plus recherché sur Google |
|---|---|---|
invoke_agent |
Appel d’un agent. La « racine » d’une exécution d’assistant. | Obligatoire pour que l’exécution apparaisse dans les vues d’activité de l’agent de Microsoft Defender ou dans le centre d’administration Microsoft 365. Sans cela, la télémétrie n’est transmise qu’à la fonctionnalité de recherche avancée de Microsoft Defender (CloudAppEvents). |
execute_tool |
Un appel d’outil / de fonction effectué par un agent. | -- |
chat |
Un appel d’inférence LLM. |
Utilisez le littéral chat, NOT inference. |
output_messages |
Un message de sortie final émis. | -- |
Hiérarchie des spans et regroupement des exécutions
Agent 365 reconstruit une exécution à partir du graphe standard des spans OTLP (traceId, spanId, parentSpanId), ainsi que des attributs globaux de l’exécution issus de la référence des attributs.
Six règles :
-
Toujours définir
parentSpanIdsur chaque étendue non racine. Sans cela, vous ne pouvez pas reconstruire la structure arborescente de la partie. -
Réutiliser le même
traceIdpour chaque plage d’un run. -
Définissez
gen_ai.conversation.idsur chaque étendue avec la même valeur. Cette valeur est la clé de jointure principale pour « tous les spans de cette exécution ». Ce n’est pas propagé automatiquement. -
Définissez
microsoft.channel.namesur chaque étendue avec la même valeur. Les spans d’outil qui n’ont pas de canal ni de conversation peuvent les hériter de leur parentinvoke_agentle parent se trouve dans la même requête OTLP ; définissez-les donc vous-même sur chaque span. -
Définissez
microsoft.session.idsur chaque span lorsque vous avez une session logique. - Pour les appels d’agent à agent où l’agent enfant est dans une requête distincte, réutilisez le même
gen_ai.conversation.idet utilisez les attributsmicrosoft.a365.caller.agent.*(voir Référence des attributs) pour capturer le contexte de l’agent appelant.
L’arborescence à quatre spans de l’exemple d’exécution de l’assistant est la forme canonique.
Types d’exécution courants
| Forme | Spans à émettre | Notes |
|---|---|---|
| Chatbot à agent unique (aucun outil, aucune étendue LLM) | Un invoke_agent seul |
Définir les attributs globaux de l’exécution ainsi que gen_ai.input.messages et gen_ai.output.messages. Identique à la demande la plus petite possible. |
| Agent avec outils (le plus courant) | Racine invoke_agent avec les spans enfants chat, execute_tool, output_messages |
Tous les enfants partagent la racine traceId et définissent parentSpanId = root.spanId. Tous portent les mêmes attributs à l’échelle de l’exécution. Consultez l’exemple d’exécution de l’agent pour obtenir un exemple complet. |
| Agent à agent | Chaque agent émet son propre invoke_agent |
Réutilisez le même gen_ai.conversation.id dans les deux agents. Sur le invoke_agent cible, définissez gen_ai.execution.type = "Agent2Agent" ainsi que les attributs microsoft.a365.caller.agent.* (l’appId de l’assistant appelant, son nom, l’appId du blueprint, l’ID utilisateur et l’adresse e-mail). Si l’agent appelant n’a pas d’inscription Entra, utilisez microsoft.a365.caller.agent.platform.id et gen_ai.caller.agent.type à la place. |
Liste de contrôle pour l’intégration en production
Exécutez cette liste de contrôle avant d’aller en production.
| Category | Cocher |
|---|---|
| Authentification | Votre application Entra (ou blueprint) est enregistrée et vous pouvez générer des jetons pour celle-ci. |
| Authentification | Votre application se voit accorder Agent365.Observability.OtelWrite (rôle d’application pour S2S, portée pour les autorisations déléguées). |
| Authentification | Chaque agent possède son propre ID d’application Entra appId, sous la forme de {agentId} dans l’URL. Pour les identités dérivées du blueprint, cet appId est l’identité de l’assistant, et non l’appId du blueprint. Si l’agent n’a pas d’enregistrement Entra, consultez Choix des valeurs. |
| Authentification | Un administrateur locataire accorde son consentement pour Agent365.Observability.OtelWrite. Sans consentement, les jetons sont émis sans le rôle ou l'étendue et les demandes sont rejetées avec 403. |
| Gestion des licences | Au moins un utilisateur du locataire client possède une licence Microsoft 365 E7 ou Microsoft Agent 365 attribuée (attribution réelle, et non simple présence du SKU dans le locataire). Sans licence assignée, les results de la réponse indiquent que les spans ont été rejetés. Voir Conditions préalables. |
| Spans | Chaque span définit les éléments essentiels communs à l’ensemble du run (Hiérarchie des spans et regroupement des runs). |
| Spans | Ensemble de spans invoke_agentgen_ai.input.messages et gen_ai.output.messages. |
| Spans | Ensemble de spans execute_toolgen_ai.tool.name, , gen_ai.tool.typegen_ai.tool.call.id, gen_ai.tool.call.arguments, gen_ai.tool.call.result. |
| Spans |
chat définit les étendues gen_ai.request.model et gen_ai.provider.name (et idéalement gen_ai.usage.input_tokens / gen_ai.usage.output_tokens - encodés sous forme de chaîne). |
| Spans | Tous les spans non racine définissent parentSpanId ; tous les spans d’une exécution partagent le même traceId. |
| Payload | Le corps de la demande est ≤ 1 Mo. |
| Vérification | Vous examinez à la fois partialSuccess et results pour chaque réponse et consignez les rejets. |
| Vérification | Vous avez exécuté le flux de vérification dans Vérification de l’ingestion sur vos premières exécutions. |
Étapes suivantes
- Informations de référence sur les attributs : spécifications par attribut et conseils de sélection de valeur.
- Résolution des problèmes : vérification de l’ingestion, des pièges courants et des réponses d’erreur.