Nota
L'accés a aquesta pàgina requereix autorització. Podeu provar d'iniciar la sessió o de canviar els directoris.
L'accés a aquesta pàgina requereix autorització. Podeu provar de canviar els directoris.
El exportador del Agente 365 requiere que un solucionador de tokens se autentique al exportar la telemetría. En esta guía se describe la configuración de los agentes creados con el SDK de agentes de Microsoft 365, que abarcan tanto agentes habilitados para agente 365 como agentes de motor personalizados en .NET, Python y Node.js.
Para la instalación de la distribución, la configuración general y los escenarios que no usan Agent SDK, consulte Microsoft OpenTelemetry Distro.
Overview
Hay cuatro escenarios de autenticación, en función del tipo de agente y de cómo adquiere tokens. La adquisición de tokens puede realizarse mediante el flujo On-Behalf-Of (OBO) o servicio a servicio (S2S). Elija el escenario que coincida con la configuración:
| Scenario | Description |
|---|---|
| Agente 365 habilitado mediante OBO | El AgenticTokenCache integrado de la distribución gestiona la adquisición automática de tokens en la ruta delegada. No se necesita ningún solucionador personalizado. Esta ruta requiere el permiso delegado Agent365.Observability.OtelWrite y el consentimiento del administrador, que a365 setup all no configura para los agentes blueprint. |
| Agente 365 habilitado con S2S | El agente adquiere un token solo para la aplicación utilizando la cadena de identidad agéntica (getAgenticApplicationToken + Microsoft Authentication Libraries (MSAL)). Requiere un TokenResolver personalizado y la opción de endpoint S2S. Una instancia de agente registrado no necesita un permiso de observabilidad ni consentimiento de administrador, por lo que este es el enfoque recomendado para agentes de plano técnico configurados con a365 setup all. |
| Motor personalizado con OBO | El agente obtiene un token de usuario mediante Azure Bot OAuth, con alcance limitado a la API de observabilidad. Requiere una conexión personalizadaTokenResolver, una conexión OAuth de Azure Bot y el permiso delegado Agent365.Observability.OtelWrite con consentimiento del administrador. |
| Motor personalizado con S2S | El agente adquiere un token de solo aplicación mediante credenciales de cliente. Requiere un TokenResolver personalizado. El registro de aplicaciones debe ser una aplicación estándar (no agentica). Los registros estándar de aplicaciones no son instancias de agente registrado, así que necesitan el Agent365.Observability.OtelWrite permiso de la aplicación con el consentimiento del administrador. |
Agente 365 habilitado mediante OBO
Los agentes habilitados para el agente 365 reciben solicitudes con identidad agente (agenticAppId, agenticUserId) desde la plataforma del Agente 365. Al usar OBO, la distribución integrada AgenticTokenCache gestiona la adquisición automática de tokens en la ruta delegada, así que no necesitas un resolver de tokens personalizado.
Prerrequisitos
Registro de la app Microsoft Entra: Un principal de servicio (registro de la app) con ID de cliente, secreto del cliente e Id. de inquilino.
Permisos delegados de API: Añadir
Agent365.Observability.OtelWrite(delegado) y conceder el consentimiento del administrador. Ela365 setup allcomando no añade este permiso para los agentes de blueprint. Un administrador global puede añadirlo y conceder el consentimiento del administrador ejecutando el siguiente comando:a365 setup permissions custom --resource-app-id 9b975845-388f-4429-889e-eab1ef63949c --scopes Agent365.Observability.OtelWritePara más opciones, incluido el Centro de administración Microsoft Entra, consulta Grant the permission.
Tip
Para evitar el permiso de observabilidad delegado y el consentimiento del administrador, utiliza Agent 365 habilitado con S2S para los agentes blueprint configurados con a365 setup all.
Configuración
En cada turno, el agente llama a la función RegisterObservability con el contexto del turno. La memoria caché integrada usa el token delegado del usuario del controlador AgenticUserAuthorization para realizar un intercambio OBO y adquirir un token con el ámbito de Agent365.Observability.OtelWrite.
Para obtener instrucciones de configuración completas, como paquetes, configuración y ejemplos de código, consulte Caché de tokens agente con aplicaciones de Agent Framework.
Agente 365 habilitado con S2S
Los agentes habilitados para Agent 365 también pueden usar la autenticación S2S (de servicio a servicio) en lugar de OBO. Este camino se recomienda para agentes de blueprint configurados con a365 setup all. El agente obtiene un token mediante su propia identidad del principal de servicio a través de una cadena de identidad agéntica de dos pasos:
- Llama
getAgenticApplicationToken(tenantId, agentId)para obtener un token de credenciales de cliente con la ruta de Identidad Gestionada Federada (FMI). - Llama a MSAL
acquireTokenForClientcon el token de la aplicación comoclientAssertiony el ámbitoapi://9b975845-388f-4429-889e-eab1ef63949c/.default.
Note
La identidad administrada federada (FMI) es una arquitectura en la que una identidad administrada participa en la federación de identidades de carga de trabajo a través de credenciales de identidad federada, lo que permite el intercambio de tokens y la autenticación sin secretos en función de las relaciones de confianza entre identidades.
La distribución OpenTelemetry de Microsoft utiliza por defecto la ruta delegada, por lo que debes proporcionar un TokenResolver personalizado y establecer la opción del endpoint S2S para tu lenguaje, como UseS2SEndpoint = true, useS2SEndpoint: true o a365_use_s2s_endpoint=True.
Prerrequisitos
-
Registro de Agent 365: La instancia del agente debe estar registrada en Agent 365. El
a365 setup allcomando registra instancias de agentes blueprint. Crear una identidad Microsoft Entra por sí sola no registra una instancia de agente. -
Credencial Blueprint para el intercambio FMI: Utiliza un secreto de cliente blueprint o una identidad gestionada para obtener el token Federated Managed Identity (FMI) para
api://AzureADTokenExchange/.default, y luego cámbialo por el token de Observability de la instancia del agente. - Coincidencia de valores de identidad: El ID del agente y el ID del tenant en baggage y la URL de exportación deben coincidir con el ID de cliente de la instancia del agente y el tenant en el token solo de la app.
Note
Una instancia de agente registrada en Agent 365 puede exportar en la ruta S2S con un token solo de aplicación que Agent365.Observability.OtelWrite no tiene ningún papel. No necesita un permiso de observabilidad ni el consentimiento del administrador. Las identidades no registradas, incluidos los registros estándar de aplicaciones, siguen necesitando el Agent365.Observability.OtelWrite rol de la app y el consentimiento del administrador.
Paso 1: Configuración del entorno
En los ejemplos de código siguientes se muestra cómo establecer la conexión necesaria, el inquilino, las credenciales de cliente y la configuración del entorno de exportador de observabilidad antes de habilitar el flujo de token S2S personalizado.
No se necesita ningún controlador AgenticUserAuthorization. S2S usa la cadena manual de identidad agéntica (get_agentic_application_token + MSAL acquire_token_for_client) para obtener un token con alcance para el recurso de observabilidad.
CONNECTIONSMAP__0__SERVICEURL=*
CONNECTIONSMAP__0__CONNECTION=SERVICE_CONNECTION
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTID=<your-client-id>
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTSECRET=<your-client-secret>
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__TENANTID=<your-tenant-id>
ENABLE_A365_OBSERVABILITY=true
ENABLE_A365_OBSERVABILITY_EXPORTER=true
Paso 2: Configurar la distribución con un resolvedor de tokens personalizado
Los siguientes ejemplos muestran cómo habilitar la exportación de Agent 365 y registrar un TokenResolver personalizado para que el exportador pueda recuperar tokens S2S para cada agente e inquilino.
from microsoft.opentelemetry import use_microsoft_opentelemetry
_token_cache: dict[str, str] = {}
def token_resolver(agent_id: str, tenant_id: str) -> str | None:
return _token_cache.get(f"{agent_id}:{tenant_id}")
use_microsoft_opentelemetry(
enable_a365=True,
a365_token_resolver=token_resolver,
a365_use_s2s_endpoint=True,
a365_enable_observability_exporter=True,
)
Paso 3: Adquirir y almacenar en caché el token S2S
Con cada mensaje entrante, obtenga el token S2S a través de la cadena de identidad agéntica y almacénelo en caché para el resolvedor.
import asyncio
from msal import ConfidentialClientApplication
from microsoft.opentelemetry.a365.core import BaggageBuilder, InvokeAgentScope, InvokeAgentScopeDetails, Request
OBSERVABILITY_S2S_SCOPE = "api://9b975845-388f-4429-889e-eab1ef63949c/.default"
async def get_agentic_s2s_token(connection, tenant_id: str, agent_id: str) -> str:
# Step 1: Get agentic application token (client_credentials + fmi_path)
app_token = await connection.get_agentic_application_token(tenant_id, agent_id)
if not app_token:
raise ValueError(f"Failed to get agentic app token for agent {agent_id}")
# Step 2: Exchange for observability-scoped token
cca = ConfidentialClientApplication(
client_id=agent_id,
authority=f"https://login.microsoftonline.com/{tenant_id}",
client_credential={"client_assertion": app_token},
)
result = await asyncio.to_thread(
lambda: cca.acquire_token_for_client(scopes=[OBSERVABILITY_S2S_SCOPE])
)
if not result or "access_token" not in result:
raise ValueError(f"Token acquisition failed: {result}")
return result["access_token"]
# In your message handler : use SDK helpers to get agent/tenant from the activity:
@AGENT_APP.activity("message")
async def on_message(context: TurnContext, _state: TurnState):
# get_agentic_instance_id reads from recipient (SDK convention)
agent_id = context.activity.get_agentic_instance_id()
tenant_id = context.activity.get_agentic_tenant_id()
# Acquire S2S token and cache BEFORE creating spans
connection = CONNECTION_MANAGER.get_connection("SERVICE_CONNECTION")
token = await get_agentic_s2s_token(connection, tenant_id, agent_id)
_token_cache[f"{agent_id}:{tenant_id}"] = token
# Wrap spans in BaggageBuilder so the exporter can resolve the token
request = Request(content=user_message, session_id=None)
with BaggageBuilder().tenant_id(tenant_id).agent_id(agent_id).build():
invoke_scope = InvokeAgentScope.start(request, InvokeAgentScopeDetails(), agent_details)
with invoke_scope:
invoke_scope.record_input_messages([user_message])
invoke_scope.record_output_messages([response])
Importante
El flujo manual de dos pasos (get_agentic_application_token + MSAL acquire_token_for_client) es necesario para S2S.
AgenticUserAuthorization.get_token() devuelve un token con ámbito de 5a807f24-.../.default (Bot Framework), no el recurso api://9b975845-.../.default de observabilidad : el punto de conexión S2S lo rechaza con 401 InvalidAudience.
- Usa
context.activity.get_agentic_instance_id()yget_agentic_tenant_id()para leer el agente y el inquilino a partir de la actividad (lee desderecipientsegún la convención del SDK). - Adquiera y almacene en caché el token S2S antes de crear intervalos. Puede que el
BatchSpanProcessordel exportador se vacíe antes de que termine el controlador: si el token aún no está almacenado en caché, la exportación falla. - Envuelve todos los ámbitos de permisos de A365 en
BaggageBuilderpara que el exportador sepa para qué agente y tenant debe resolver los tokens. Sin equipaje, los intervalos se quitan silenciosamente con "No se encuentran intervalos con la identidad del inquilino o agente encontrado".
Importante
Antes de que tu resolver devuelva y almacene en caché el token final de Observabilidad:
- Valida que el token sea solo para la aplicación. Acepta
idtyp=app. Siidtypestá ausente, acepta solo un token que tenga un claimrolesno vacío o un claimoidno vacío igual asub. Rechaza tokens que tengan unascpdeclaración u otroidtypvalor. - Comprueba que
audsea9b975845-388f-4429-889e-eab1ef63949coapi://9b975845-388f-4429-889e-eab1ef63949c, y que el token no esté caducado. - Nunca envíes la aserción intermedia de blueprint, un token de blueprint o un token de usuario u OBO a Observability.
- Almacena en caché el token final y refrescalo antes de que caduque. El exportador llama al solucionador una vez para cada identidad de tenant y agente en cada lote de exportación.
Para implementaciones completas que usan la distro, consulte los ejemplos de Agent 365 para Node.js, Python y .NET.
Motor personalizado mediante OBO
Los agentes de motor personalizado usan registros de aplicaciones estándar con conexiones OAuth de Azure Bot, no la cadena de identidad agéntica. Mediante el uso de OBO, el agente obtiene un token de usuario a través de Azure Bot OAuth que ya está en el ámbito de la API de observabilidad de A365 mediante Bot Framework Token Service. Una sola llamada a getToken o GetTurnTokenAsync devuelve el token con el ámbito correcto, por lo que no necesitas exchangeToken.
Prerrequisitos
Registro de la app Microsoft Entra con permisos delegados de API. Añadir Agent365.Observability.OtelWrite (Delegado) y conceder el consentimiento de administrador.
Importante
El agentId de la caché de tokens debe coincidir con el identificador de cliente del registro de la aplicación, no con el agenticAppId de la actividad, que no existe para los agentes de motor personalizados. La URL de exportación incluye agentId, y una discrepancia provoca un error HTTP 403.
Paso 1: Entorno y configuración de la aplicación
Los ejemplos siguientes muestran cómo configurar tu aplicación y el entorno de ejecución, incluidos los valores de conexión del servicio, la configuración del tenant y del cliente, y las asignaciones de autorización necesarias.
# .env
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTID=<your-client-id>
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTSECRET=<your-client-secret>
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__TENANTID=<your-tenant-id>
CONNECTIONSMAP__0__CONNECTION=SERVICE_CONNECTION
CONNECTIONSMAP__0__SERVICEURL=*
# Auth handler config : TYPE is required, name is uppercased by load_configuration_from_env
AGENTAPPLICATION__USERAUTHORIZATION__HANDLERS__OBOCONNECTIONPROFILE__TYPE=UserAuthorization
AGENTAPPLICATION__USERAUTHORIZATION__HANDLERS__OBOCONNECTIONPROFILE__SETTINGS__AZUREBOTOAUTHCONNECTIONNAME=oboConnectionProfile
AGENTAPPLICATION__USERAUTHORIZATION__HANDLERS__OBOCONNECTIONPROFILE__SETTINGS__SCOPES=api://9b975845-388f-4429-889e-eab1ef63949c/Agent365.Observability.OtelWrite
ENABLE_A365_OBSERVABILITY=true
ENABLE_A365_OBSERVABILITY_EXPORTER=true
Importante
load_configuration_from_env convierte todas las claves de las variables de entorno a mayúsculas. El nombre del manejador pasa a ser OBOCONNECTIONPROFILE y debe referirse a él respetando exactamente las mayúsculas y minúsculas en las llamadas a auth_handlers y get_token(). La ausencia de TYPE causa Auth handler ... not recognized or not configured en tiempo de ejecución.
Paso 2: Configurar la distribución para OBO
En los ejemplos siguientes se muestra cómo habilitar la exportación de Agent 365, mantener el exportador en el punto de conexión OBO y registrar un TokenResolver personalizado que devuelve tokens delegados durante la exportación.
from microsoft.opentelemetry import use_microsoft_opentelemetry
_token_cache: dict[str, str] = {}
def token_resolver(agent_id: str, tenant_id: str) -> str | None:
return _token_cache.get(f"{agent_id}:{tenant_id}")
environ["ENABLE_A365_OBSERVABILITY_EXPORTER"] = "true"
use_microsoft_opentelemetry(
enable_a365=True,
a365_token_resolver=token_resolver,
a365_use_s2s_endpoint=False, # OBO uses /observability endpoint
a365_enable_observability_exporter=True,
)
Note
El modo OBO requiere jwt_authorization_middleware en aiohttpApplication (valida el JWT entrante (JSON Web Token) de Bot Framework). La ruta de acceso del emulador o S2S no debe incluir este middleware.
from microsoft_agents.hosting.aiohttp import jwt_authorization_middleware
app = Application(middlewares=[jwt_authorization_middleware])
Paso 3: Adquisición del token de OBO
En los ejemplos siguientes se muestra cómo solicitar un token de OBO delegado desde la conexión OAuth de bot configurada Azure y, a continuación, almacenarla en caché por cliente de aplicación e inquilino para el exportador.
from microsoft_agents.hosting.core import (
AgentApplication, Authorization, MemoryStorage, TurnContext, TurnState,
)
from microsoft_agents.activity import load_configuration_from_env
from microsoft_agents.authentication.msal import MsalConnectionManager
from microsoft_agents.hosting.aiohttp import CloudAdapter
# Auth handlers are loaded from .env via load_configuration_from_env (see Environment config above)
agents_sdk_config = load_configuration_from_env(environ)
STORAGE = MemoryStorage()
CONNECTION_MANAGER = MsalConnectionManager(**agents_sdk_config)
ADAPTER = CloudAdapter(connection_manager=CONNECTION_MANAGER)
AUTHORIZATION = Authorization(STORAGE, CONNECTION_MANAGER, **agents_sdk_config)
AGENT_APP = AgentApplication[TurnState](
storage=STORAGE, adapter=ADAPTER, authorization=AUTHORIZATION, **agents_sdk_config,
)
CLIENT_ID = environ.get("CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTID", "")
TENANT_ID = environ.get("CONNECTIONS__SERVICE_CONNECTION__SETTINGS__TENANTID", "")
# Message handler : get_token returns a token already scoped to the observability API.
# The Azure Bot Token Service performs the OBO exchange internally based on the
# OAuth connection's configured scope. No manual MSAL exchange_token call is needed.
@AGENT_APP.activity("message", auth_handlers=["OBOCONNECTIONPROFILE"])
async def on_message(context: TurnContext, _state: TurnState):
token_response = await AGENT_APP.auth.get_token(context, "OBOCONNECTIONPROFILE")
# token_response.token has aud=<a365-observability-app-id>,
# scp=Agent365.Observability.OtelWrite
_token_cache[f"{CLIENT_ID}:{TENANT_ID}"] = token_response.token
Importante
Requisito previo del portal Azure: Establezca los Scopes de la conexión OAuth de Azure Bot denominada oboConnectionProfile en api://9b975845-388f-4429-889e-eab1ef63949c/Agent365.Observability.OtelWrite. Sin esta configuración, el token se limita a la audiencia propia del bot (api://botid-...) y se produce un error en la exportación con HTTP 401 InvalidAudience.
Note
AGENT_APP.auth.get_token() devuelve directamente el token con el ámbito correcto; no es necesario llamar a exchange_token(). Bot Framework Token Service gestiona el intercambio de OBO cuando el ámbito de la conexión de OAuth tiene como destino el recurso de observabilidad A365.
Motor personalizado con S2S
Los agentes de motores personalizados pueden usar S2S (credenciales de cliente) para obtener un token solo de aplicación utilizando las credenciales de conexión de servicio. Este método utiliza credenciales estándar de cliente MSAL: no necesita una cadena de identidad agentic.
Prerrequisitos
-
Registro de la aplicación Microsoft Entra: El registro de la aplicación debe ser un motor personalizado (estándar). Los registros de aplicaciones con Agent 365 habilitado no pueden usar solo
client_credentialspara el recurso de observabilidad (AADSTS82001). -
Permisos de aplicación: Añadir
Agent365.Observability.OtelWrite(Aplicación, no Delegada) y conceder el consentimiento del administrador. Los registros estándar de aplicaciones no son instancias de agente registradas en Agent 365, así que necesitan este rol de aplicación en la ruta S2S.
Importante
El agentId que uses para el almacenamiento en caché debe ser el de ServiceConnection ClientId La dirección URL de exportación es /observabilityService/tenants/{tenantId}/otlp/agents/{agentId}/traces : una falta de coincidencia provoca HTTP 403.
Paso 1: Entorno y configuración de la aplicación
Los ejemplos siguientes muestran cómo configurar tu aplicación y el entorno de ejecución, incluidos los valores de conexión del servicio, la configuración del tenant y del cliente, y las asignaciones de autorización necesarias.
# .env
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTID=<your-client-id>
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTSECRET=<your-client-secret>
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__TENANTID=<your-tenant-id>
CONNECTIONSMAP__0__CONNECTION=SERVICE_CONNECTION
CONNECTIONSMAP__0__SERVICEURL=*
ENABLE_A365_OBSERVABILITY=true
ENABLE_A365_OBSERVABILITY_EXPORTER=true
Paso 2: Configurar la distribución para S2S
Los siguientes ejemplos muestran cómo habilitar la exportación de Agent 365, configurar el exportador para que use el punto de conexión S2S y registrar un TokenResolver personalizado para buscar tokens durante la exportación.
from microsoft.opentelemetry import use_microsoft_opentelemetry
_token_cache: dict[str, str] = {}
def token_resolver(agent_id: str, tenant_id: str) -> str | None:
return _token_cache.get(f"{agent_id}:{tenant_id}")
use_microsoft_opentelemetry(
enable_a365=True,
a365_token_resolver=token_resolver,
a365_use_s2s_endpoint=True, # S2S uses /observabilityService endpoint
a365_enable_observability_exporter=True,
)
Paso 3: Adquisición del token de S2S
En los ejemplos siguientes se muestra cómo solicitar un token de acceso de solo aplicación para el recurso de observabilidad mediante las credenciales de conexión de servicio y, a continuación, almacenarlo en caché por agente e inquilino para el exportador.
# Force agentId to ServiceConnection ClientId (custom engine agents have no agenticAppId)
agent_id = os.environ.get("CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTID")
tenant_id = os.environ.get("CONNECTIONS__SERVICE_CONNECTION__SETTINGS__TENANTID")
connection = CONNECTION_MANAGER.get_connection("SERVICE_CONNECTION")
token = await connection.get_access_token(
resource_url="https://login.microsoftonline.com",
scopes=["api://9b975845-388f-4429-889e-eab1ef63949c/.default"],
)
_token_cache[f"{agent_id}:{tenant_id}"] = token
Paso 4: Configurar baggage para la exportación de spans
El exportador Agent365 requiere baggage (ID del tenant e ID de agente) en el contexto de span. Sin este bagaje, el exportador suelta spans y registra el mensaje No spans with tenant/agent identity found..
from microsoft.opentelemetry.a365.core import BaggageBuilder, InvokeAgentScope
# Baggage must wrap the span as a context manager
with BaggageBuilder().tenant_id(tenant_id).agent_id(agent_id).build():
invoke_scope = InvokeAgentScope.start(request, InvokeAgentScopeDetails(), agent_details)
with invoke_scope:
invoke_scope.record_input_messages([user_message])
invoke_scope.record_output_messages([response])