Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
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.
Visión general
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 | La AgenticTokenCache integrada de la distribución gestiona automáticamente la obtención de tokens. No se necesita ningún solucionador personalizado. Este es el enfoque recomendado para los agentes con Agent 365 habilitado. |
| Agente 365 habilitado con S2S | El agente obtiene un token mediante la cadena de identidad agéntica (getAgenticApplicationToken + Microsoft Authentication Libraries (MSAL)). Requiere un TokenResolver personalizado. Use este enfoque cuando OBO no esté disponible o necesite tokens exclusivos de la aplicación. |
| Motor personalizado con OBO | El agente obtiene un token de usuario mediante Azure Bot OAuth, con alcance limitado a la API de observabilidad. Requiere un TokenResolver personalizado y una conexión OAuth de Azure Bot. |
| Motor personalizado con S2S | El agente adquiere un token de solo aplicación mediante credenciales de cliente. Requiere TokenResolver personalizado. El registro de aplicaciones debe ser una aplicación estándar (no agentica). |
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. Con OBO, el AgenticTokenCache integrado de la distribución se encarga automáticamente de obtener los tokens: no se necesita ningún resolutor de tokens personalizado.
Prerrequisitos
- Registro de aplicaciones de Entra : una entidad de servicio (registro de aplicaciones) con el id. de cliente, el secreto de cliente y el id. de inquilino.
-
Permisos de API delegados : agregue
Agent365.Observability.OtelWrite(delegado), conceda el consentimiento del administrador. Para obtener pasos detallados, consulte Concesión del permiso.
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. 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:
-
getAgenticApplicationToken(tenantId, agentId): credenciales de cliente + ruta de acceso de identidad administrada federada (FMI) - MSAL
acquireTokenForClientcon el token de la aplicación comoclientAssertiony el alcanceapi://9b975845-388f-4429-889e-eab1ef63949c/.default
Nota:
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.
Debe proporcionar TokenResolver personalizado y establecer UseS2SEndpoint = true.
Prerrequisitos
Registro de aplicaciones de Entra : una entidad de servicio (registro de aplicaciones) con el identificador de cliente, el secreto de cliente y el identificador de inquilino.
Permisos de API de aplicación : Agregar
Agent365.Observability.OtelWrite(aplicación), conceder consentimiento del administradorAgent365.Observability.OtelWriterol de la aplicación: la entidad de servicio del agente debe tener asignado el rolOtelWriteen el recurso Agent365 Observability. Use la CLI de Agent 365:a365 setup permissions bot --config-dir "<path-to-config-dir>"Nota:
La propagación de roles puede tardar unos minutos. Durante este período, es de esperar que se produzcan errores 401 o 403 iniciales desde el extremo de exportación.
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".
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 aplicaciones de Entra con permisos delegados de API. Agregar Agent365.Observability.OtelWrite (delegado) y conceder consentimiento del 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,
)
Nota:
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 de Azure: La conexión de OAuth de Azure Bot llamada oboConnectionProfile debe tener los Ámbitos configurados como 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.
Nota:
AGENT_APP.auth.get_token() devuelve directamente el token con el ámbito correcto; no es necesaria ninguna llamada 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 del motor personalizado pueden usar S2S (credenciales de cliente) para adquirir un token de solo aplicación mediante las credenciales de conexión de servicio. Este método usa credenciales de cliente MSAL estándar: no se requiere ninguna cadena de identidades agente.
Prerrequisitos
-
Registro de aplicaciones de Azure AD: debe ser una aplicación de 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 : agregue
Agent365.Observability.OtelWrite(aplicación, no delegado) y conceda consentimiento del administrador.
Importante
El agentId utilizado para el almacenamiento en caché debe ser el de ClientIdServiceConnection. 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
En los siguientes ejemplos se muestra cómo configurar tu aplicación y el entorno de ejecución, incluidos los valores de la conexión de servicio, la configuración del inquilino 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 de Agent365 requiere que el baggage (ID del tenant e ID del agente) esté configurado en el contexto del span. Sin él, el exportador quita silenciosamente intervalos con 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])