Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
L'esportatore Agent 365 richiede un resolver di token per autenticarsi durante l'esportazione della telemetria. Questa guida tratta la configurazione per agenti sviluppati con l'SDK per agenti Microsoft 365, inclusi sia agenti abilitati Agent 365 che agenti con motore personalizzato su .NET, Python e Node.js.
Per l'installazione della distribuzione, la configurazione generale e gli scenari senza SDK non degli agenti, vedi Distribuzione Microsoft di OpenTelemetry.
Panoramica
Esistono quattro scenari di autenticazione, a seconda del tipo di agente e di come acquisisce i token. L'acquisizione del token può utilizzare On-Behalf-Of (OBO) o Service-to-Service (S2S). Scegli lo scenario che corrisponde alla tua configurazione:
| Scenario | Descrizione |
|---|---|
| Agent 365 abilitato con OBO | La distribuzione integrata AgenticTokenCache gestisce automaticamente l'acquisizione dei token. Non serve un resolver personalizzato. Questo è l'approccio consigliato per gli agenti con Agent 365 abilitato. |
| Agent 365 abilitato con S2S | L'agente acquisisce un token utilizzando la catena di identità agentica (getAgenticApplicationToken + Librerie di autenticazione Microsoft (MSAL)). Richiede un resolver personalizzato TokenResolver. Utilizza questo approccio quando OBO non è disponibile o hai bisogno di token applicativi. |
| Motore personalizzato che utilizza OBO | L'agente ottiene un token utente tramite Azure Bot OAuth, con ambito limitato all'API di osservabilità. Richiede un TokenResolver personalizzato e una connessione OAuth Bot di Azure. |
| Motore personalizzato che utilizza S2S | L'agente acquisisce un token applicativo utilizzando le credenziali client. Richiede un resolver personalizzato TokenResolver. La registrazione dell'app deve essere una registrazione standard (non agentica). |
Agent 365 abilitato con OBO
Gli agenti abilitati per Agent 365 ricevono richieste con identità agentica (agenticAppId, agenticUserId) dalla piattaforma Agent 365. Con OBO, il risolutore integrato AgenticTokenCache gestisce automaticamente l'acquisizione dei token: non è necessario alcun risolutore di token personalizzato.
Prerequisiti
- Registrazione app Entra: un'entità servizio (registrazione app) con ID client, segreto client e ID tenant
-
Permessi API delegati: aggiungi
Agent365.Observability.OtelWrite(Delegato), concedi il consenso dell'amministratore. Per passaggi dettagliati, vedi Concedi l'autorizzazione.
Impostare
Ad ogni turno, il tuo agente chiama la funzione RegisterObservability con il contesto del turno. La cache integrata utilizza il token delegato dell'utente fornito dal gestore AgenticUserAuthorization per eseguire uno scambio OBO, ottenendo un token con ambito su Agent365.Observability.OtelWrite.
Per istruzioni complete sulla configurazione, inclusi i pacchetti, la configurazione e gli esempi di codice, vedi Cache di token agentic con app Agent Framework.
Agent 365 abilitato con S2S
Gli agenti con Agent 365 abilitato possono anche utilizzare l'autenticazione S2S (service-to-service) in alternativa all'OBO. L'agente acquisisce un token utilizzando la propria identità dell'entità servizio tramite una catena di identità di agenti in due passaggi:
-
getAgenticApplicationToken(tenantId, agentId): credenziali client + flusso Federated Managed Identity (FMI) - MSAL
acquireTokenForClientcon il token dell'applicazione comeclientAssertione scopeapi://9b975845-388f-4429-889e-eab1ef63949c/.default
Nota
Federated Managed Identity (FMI) è un'architettura in cui un'identità gestita partecipa alla federazione delle identità di workload tramite credenziali di identità federata, abilitando lo scambio di token e l'autenticazione senza segreti basata su relazioni di fiducia tra identità.
Devi fornire un TokenResolver personalizzato e impostare UseS2SEndpoint = true.
Prerequisiti
Registrazione app Entra: un'entità servizio (registrazione app) con ID client, segreto client e ID tenant
Permessi API dell'applicazione: aggiungi
Agent365.Observability.OtelWrite(Applicazione), concedi il consenso dell'amministratoreAgent365.Observability.OtelWriteruolo dell'app : l'entità servizio dell'agente deve avere il ruoloOtelWriteassegnato sulla risorsa Agent365 Observability. Usa CLI di Agent 365:a365 setup permissions bot --config-dir "<path-to-config-dir>"Nota
La propagazione del ruolo potrebbe richiedere alcuni minuti. Durante questo periodo si prevedono errori iniziali 401 o 403 dall'endpoint di esportazione.
Passaggio 1: configurazione dell'ambiente
I seguenti esempi di codice mostrano come configurare i parametri richiesti di connessione, tenant, credenziali client e le variabili di ambiente dell'esportatore di osservabilità prima di abilitare il flusso S2S personalizzato.
Non è necessario alcun gestore AgenticUserAuthorization. S2S utilizza la catena di identità agentica manuale (get_agentic_application_token + MSAL acquire_token_for_client) per ottenere un token con ambito sulla risorsa di osservabilità.
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
Passaggio 2: configurare la distribuzione con un resolver di token personalizzato
I seguenti esempi mostrano come abilitare l'esportazione Agent 365 e registrare un TokenResolver personalizzato affinché l'esportatore possa recuperare i token S2S per ogni agente e tenant.
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,
)
Passaggio 3: acquisire e memorizzare nella cache il token S2S
Per ogni messaggio in arrivo, acquisisci il token S2S tramite la catena di identità agentica e memorizzalo nella cache per il risolutore.
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
Il flusso manuale a due passaggi (get_agentic_application_token + MSAL acquire_token_for_client) è richiesto per S2S.
AgenticUserAuthorization.get_token() restituisce un token con ambito su 5a807f24-.../.default (Bot Framework), non sulla risorsa di osservabilità api://9b975845-.../.default: l'endpoint S2S lo respinge con 401 InvalidAudience.
- Usa
context.activity.get_agentic_instance_id()eget_agentic_tenant_id()per recuperare l'agente e il tenant dall'attività (recuperandoli darecipientsecondo la convenzione dell'SDK). - Acquisisci e memorizza in cache il token S2S prima di creare span. Il
BatchSpanProcessordell'esportatore potrebbe effettuare il flush prima che l'handler termini: se il token non è ancora stato memorizzato in cache, l'esportazione fallisce. - Racchiudi tutti gli scope A365 tra i tag
BaggageBuilderin modo che l'utilità di esportazione sappia per quali agente e tenant risolvere i token. Senza baggage, gli intervalli vengono rilasciati automaticamente con "Nessun intervallo con identità tenant/agente trovato".
Motore personalizzato che utilizza OBO
Gli agenti del motore personalizzato usano registrazioni delle app standard con connessioni OAuth di Azure Bot, non la catena di identità di agenti. Usando OBO, l'agente ottiene un token utente tramite Azure Bot OAuth con ambito già limitato all'API di osservabilità A365 dal servizio token di Bot Framework. Una singola chiamata getToken o GetTurnTokenAsync restituisce il token con lo scope corretto, quindi non è necessario exchangeToken.
Prerequisiti
Registrazione dell'app Entra con Autorizzazioni API delegate. Aggiungi Agent365.Observability.OtelWrite (delegato) e concedi il consenso dell'amministratore
Importante
L'agentId nella cache dei token deve corrispondere all'ID client della registrazione dell'app, non a agenticAppId dell'attività, che non esiste per gli agenti del motore personalizzato. L'URL di esportazione contiene agentId e una discrepanza causa l'errore HTTP 403.
Passaggio 1: configurazione dell'ambiente e dell'applicazione
I seguenti esempi mostrano come configurare la tua app e l'ambiente di runtime, inclusi i valori di connessione al servizio, le impostazioni tenant e client, e i mapping di autorizzazione richiesti.
# .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 converte tutte le chiavi delle variabili di ambiente in maiuscolo. Il nome del gestore diventa OBOCONNECTIONPROFILE e devi farvi riferimento rispettando esattamente la distinzione tra maiuscole e minuscole nelle chiamate a auth_handlers e get_token(). La mancanza di TYPE causa Auth handler ... not recognized or not configured al runtime.
Passaggio 2: configurare la distribuzione per OBO
Gli esempi seguenti mostrano come abilitare l'esportazione tramite Agent 365, mantenere l'esportatore sull'endpoint OBO e registrare una personalizzazione TokenResolver che restituisca i token delegati durante l'esportazione.
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
La modalità OBO richiede jwt_authorization_middleware su aiohttpApplication (valida il JWT in ingresso (token Web JSON) dal Bot Framework). Il percorso S2S/emulatore non dovrebbe includere questo middleware.
from microsoft_agents.hosting.aiohttp import jwt_authorization_middleware
app = Application(middlewares=[jwt_authorization_middleware])
Passaggio 3: acquisire il token OBO
I seguenti esempi mostrano come richiedere un token OBO delegato dalla connessione Azure Bot OAuth configurata e successivamente memorizzarlo nella cache per ciascun client applicativo e tenant dell'esportatore.
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
Prerequisito dle portale di Azure la connessione OAuth del bot di Azure denominata oboConnectionProfile deve avere i suoi Ambiti impostati su api://9b975845-388f-4429-889e-eab1ef63949c/Agent365.Observability.OtelWrite. Senza questa impostazione, il token è destinato all'audience del bot stesso (api://botid-...) e l'esportazione fallisce con errore HTTP 401 InvalidAudience.
Nota
AGENT_APP.auth.get_token() restituisce direttamente il token con ambito corretto. Non è necessaria alcuna chiamata exchange_token(). Il servizio toke di Bot Framework gestisce lo scambio OBO quando l'ambito della connessione OAuth è configurato per la risorsa di osservabilità A365.
Motore personalizzato con S2S
Gli agenti del motore personalizzati possono usare S2S (credenziali del client) per acquisire un token di sola applicazione utilizzando le credenziali della connessione al servizio. Questo metodo utilizza le credenziali client standard MSAL: non è richiesta alcuna catena di identità degli agenti.
Prerequisiti
-
registrazione dell'app di Azure AD: deve essere un'app motore personalizzato (standard). Le registrazioni di app abilitate per Agent 365 non possono usare direttamente
client_credentialsper la risorsa di osservabilità (AADSTS82001). -
Autorizzazioni applicative: aggiungi
Agent365.Observability.OtelWrite(applicazione, non delegata) e concedi il consenso amministratore.
Importante
L'agentId usato per la cache deve essere quello di ClientId di ServiceConnection. L'URL di esportazione è /observabilityService/tenants/{tenantId}/otlp/agents/{agentId}/traces : una discrepanza causa HTTP 403.
Passaggio 1: configurazione dell'ambiente e dell'applicazione
I seguenti esempi mostrano come configurare la tua app e l'ambiente di runtime, inclusi i valori di connessione al servizio, le impostazioni tenant e client, e i mapping di autorizzazione richiesti.
# .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
Passaggio 2: configurare la distribuzione per S2S
I seguenti esempi mostrano come abilitare l'esportazione di Agent 365, impostare l'esportatore sull'endpoint S2S e registrare un TokenResolver personalizzato per la ricerca dei token durante l'esportazione.
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,
)
Passaggio 3: acquisire il token S2S
I seguenti esempi mostrano come richiedere un token di accesso solo per app per la risorsa di osservabilità utilizzando le credenziali di connessione di servizio, quindi memorizzarlo in cache per agente e tenant per l'esportatore.
# 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
Passaggio 4: Impostare il baggage per l'esportazione degli span
L'utilità di esportazione di Agent365 richiede che il baggage (ID del tenant e ID dell'agente) sia impostato nel contesto dello span. Senza di esso, l'esportatore scarta silenziosamente gli span con il messaggio 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])