إعداد مصادقة المراقبة

يتطلب المُصدر Agent 365 وجود محلل رموز للمصادقة عند تصدير التليمترية. يغطي هذا الدليل إعداد العاملين المبنيين باستخدام Microsoft 365 Agents SDK، ويغطي كل من العاملين المدعومين لـ Agent 365 ووكلاء المحرك المخصص عبر .NET وPython و Node.js.

لتثبيت التوزيعات، والتكوين العام، وسيناريوهات حزمة غير Agent SDK ، راجع توزيعة Microsoft OpenTelemetry.

نظرة عامة

هناك أربعة سيناريوهات للمصادقة، حسب نوع عاملك وكيفية حصوله على الرموز. يمكن أن يستخدم اكتساب الرمز المميز تدفق نيابة عن (OBO) أو من خدمة إلى خدمة (S2S). اختر السيناريو الذي يتناسب مع إعدادك:

سيناريو الوصف
تمكين Agent 365 باستخدام OBO تتولى AgenticTokenCache المضمنة في التوزيعة الحصول على الرمز المميز تلقائيًا. لا حاجة إلى محلل رموز مخصص. هذا هو النهج الموصى به للوكلاء المُمكَّنين بواسطة Agent 365.
تمكين Agent 365 باستخدام S2S يكتسب العامل رمزا باستخدام سلسلة الهوية العائمة على العاملين (getAgenticApplicationToken + مكتبات المصادقة لـ Microsoft (MSAL)). يتطلب TokenResolver مخصصًا. استخدم هذا الأسلوب عندما لا تكون OBO متوفرة أو عندما تحتاج إلى رموز التطبيقات فقط.
محرك مخصص باستخدام OBO يحصل العامل على رمز المستخدم عبر Azure Bot OAuth، والذي يقتصر نطاقه على واجهة برمجة تطبيقات المراقبة. يتطلب TokenResolverاتصالا مخصصا واتصال OAuth لروبوت Azure.
محرك مخصص باستخدام S2S يحصل العامل على رمز مخصص للتطبيق فقط باستخدام بيانات اعتماد العميل. يتطلب TokenResolver مخصصًا. يجب أن يكون تسجيل التطبيق تطبيقاً قياسياً غير قائم على العاملين.

تم تمكين Agent 365 باستخدام OBO

يستقبل العاملون الممكّنون من Agent 365 طلبات ذات هوية القائم على العاملين (agenticAppId، agenticUserId) من منصة Agent 365. مع OBO، يتعامل التوزيعة المدمج AgenticTokenCache مع اكتساب الرموز تلقائيا: لا حاجة إلى حل رموز مخصص.

المتطلبات

  • تسجيل تطبيق Entra: مزود خدمة (تسجيل التطبيق) مع معرف العميل، وسر العميل، ومعرف المستأجر
  • أذونات API المفوضة: أضف Agent365.Observability.OtelWrite (مفوضة)، ثم امنح موافقة المسؤول. للخطوات التفصيلية، انظر منح الإذن.

الإعداد

في كل دورة، يستدعي عاملُك الدالة RegisterObservability مع سياق الدور. يستخدم الذاكرة المؤقتة المدمجة الرمز المفوض للمستخدم من AgenticUserAuthorization المعالج لإجراء تبادل OBO، وتحصل على رمز محدد النطاق لـ Agent365.Observability.OtelWrite.

للحصول على تعليمات الإعداد الكاملة بما في ذلك الحزم، والتكوين، وأمثلة الكود، راجع ذاكرة التخزين المؤقت للرموز المميزة القائمة على العاملين مع تطبيقات Agent Framework.

تم تمكين Agent 365 باستخدام S2S

يمكن للعاملين الممكنين لـ Agent 365 أيضا استخدام مصادقة S2S (خدمة إلى خدمة) بدلا من OBO. يكتسب عامل رمزاً باستخدام هوية الخدمة الرئيسية الخاصة به عبر سلسلة هوية القائم على العاملين مكونة من خطوتين:

  1. getAgenticApplicationToken(tenantId, agentId) : بيانات اعتماد العميل + مسار الهوية المدارة الموحدة (FMI)
  2. MSAL acquireTokenForClient مع الرمز المميزة للتطبيق ك وclientAssertion نطاق api://9b975845-388f-4429-889e-eab1ef63949c/.default

إشعار

الهوية المدارة الموحدة (FMI) هي بنية يشارك فيها هوية مدارة في اتحاد هويات عبء العمل عبر بيانات اعتماد الهوية المتحدة، مما يمكن تبادل الرموز والمصادقة غير السرية بناء على علاقات الثقة بين الهويات.

يجب عليك توفير قيمة مخصصة لـ TokenResolver وتعيين UseS2SEndpoint = true.

المتطلبات

  • تسجيل تطبيق Entra: مزود خدمة (تسجيل التطبيق) مع معرف العميل، وسر العميل، ومعرف المستأجر

  • أذونات API للتطبيقات: أضف Agent365.Observability.OtelWrite (تطبيق)، ومنح موافقة المسؤول

  • دور تطبيق Agent365.Observability.OtelWrite : يجب أن يكون لدى كيان خدمة العامل دور OtelWrite المعين على مورد مراقبة Agent365. استخدام Agent 365 CLI:

    a365 setup permissions bot --config-dir "<path-to-config-dir>"
    

    إشعار

    قد يستغرق نشر الأدوار بضع دقائق. من المتوقع حدوث أخطاء أولية من نوع 401 أو 403 من نقطة التصدير خلال هذه الفترة.

الخطوة 1: تكوين البيئة

توضح أمثلة الكود التالية كيفية تعيين إعدادات بيئة الاتصال المطلوبة، والمستأجر، وبيانات اعتماد العميل، وإعدادات تصدير الملاحظة قبل تفعيل تدفق الرموز المميز المخصص لـ S2S.

لا حاجة إلى معالج AgenticUserAuthorization. يستخدم S2S سلسلة الهوية القائمة على العاملين اليدوية (get_agentic_application_token + MSAL acquire_token_for_client) للحصول على رمز مميز محدد النطاق لمورد إمكانية المراقبة.

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

الخطوة 2: تكوين التوزيعة باستخدام محلل الرموز المخصص:

توضح الأمثلة التالية كيفية تمكين تصدير Agent 365 وتسجيله TokenResolver حتى يتمكن المصدر من استرجاع رموز S2S لكل وكيل ومستأجر.

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,
)

الخطوة 3: احصل على رمز S2S واحتفظ به مؤقتا

على كل رسالة واردة، احصل على رمز مميز S2S عبر سلسلة الهوية القائمة على العاملين وقم بتخزينه مؤقتا للمحلل.

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])

مهم

يتطلب التدفق اليدوي ذو الخطوتين (get_agentic_application_token + MSAL acquire_token_for_client) لـ S2S. AgenticUserAuthorization.get_token() يرجع رمزا مميزا محددا إلى 5a807f24-.../.default (Bot Framework)، وليس مورد الملاحظة api://9b975845-.../.default : نقطة نهاية S2S ترفضه باستخدام 401 InvalidAudience.

  • استخدم context.activity.get_agentic_instance_id() وget_agentic_tenant_id() لقراءة العامل والمستأجر من النشاط (مع القراءة من recipient وفقًا لاصطلاحات SDK).
  • احصل على رمز S2S واحتفظ به مؤقتا قبل إنشاء الامتدادات. قد يقوم مُصدِّر BatchSpanProcessor بتصدير البيانات قبل أن ينتهي المعالج؛ إذا لم يتم تخزين الرمز مؤقتًا بعد، ستفشل عملية التصدير.
  • غلف جميع نطاقات A365 ضمن BaggageBuilder لكي يعرف المصدر أي عامل وأي مستأجر يجب أن يحل الرموز لهما. بدون بيانات إضافية، يتم إسقاط النطاقات بصمت مع ظهور رسالة "لم يتم العثور على نطاقات بهوية المستأجر/العامل".

محرك مخصص باستخدام OBO

يستخدم عاملو المحركات المخصصون تسجيلات التطبيقات القياسية مع اتصالات Azure Bot OAuth، وليس سلسلة الهوية القائمة على العاملين. باستخدام OBO، يحصل العامل على رمز مستخدم عبر Azure Bot OAuth تم تجميعه بالفعل بواجهة برمجة تطبيقات الملاحظة A365 من قبل خدمة Bot Framework Token Service. مكالمة واحدة لـ getToken أو GetTurnTokenAsync تُرجع رمز وصول بالنطاق الصحيح، لذلك لا تحتاج إلى exchangeToken.

المتطلبات

تسجيل تطبيق Entra مع أذونات API المفوضة. أضف Agent365.Observability.OtelWrite (مفوَّض)، وامنح موافقة المسؤول

مهم

يجب أن يتطابق agentId في ذاكرة التخزين المؤقت مع معرف العميل CLIENT ID - وليس معرف النشاط agenticAppId، الذي لا يوجد لوكلاء المحرك المخصص. يتضمن عنوان URL للتصدير agentId، وأي عدم تطابق يؤدي إلى ظهور خطأ HTTP 403.

الخطوة 1: تكوين البيئة والتطبيق:

توضح الأمثلة التالية كيفية تكوين تطبيقك وبيئة التشغيل، بما في ذلك قيم اتصال الخدمة، وإعدادات المستأجر والعميل، وتعيينات التفويض المطلوبة.

# .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

مهم

load_configuration_from_env يحوّل جميع مفاتيح متغيرات البيئة إلى أحرف كبيرة. يصبح اسم المعالج OBOCONNECTIONPROFILE ويجب عليك الإشارة إليه بنفس الحالة في استدعاءات auth_handlers و get_token(). عدم وجود TYPE يؤدي إلى حدوث Auth handler ... not recognized or not configured أثناء وقت التشغيل.

الخطوة 2 - تكوين distro لـ OBO

توضح الأمثلة التالية كيفية تمكين تصدير Agent 365، والحفاظ على المصدر في نقطة نهاية OBO، وتسجيل مخصص TokenResolver يعيد الرموز المميزة المفوضة أثناء التصدير.

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,
)

إشعار

يتطلب وضع OBO jwt_authorization_middleware على aiohttpApplication (للتحقق من صحة JWT الوارد (رمز ويب JSON) من Bot Framework). مسار S2S/المحاكي لا يجب أن يشمل هذا البرنامج الوسيط.

from microsoft_agents.hosting.aiohttp import jwt_authorization_middleware
app = Application(middlewares=[jwt_authorization_middleware])

الخطوة 3: احصل على رمز OBO المميز

توضح الأمثلة التالية كيفية طلب رمز OBO مفوض من اتصال Azure روبوت OAuth المكوَّن، ثم تخزينه مؤقتًا حسب عميل التطبيق والمستأجر للمُصدِّر.

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

مهم

المتطلب الأساسي لمدخل Azure: اتصال Azure Bot OAuth المسمى oboConnectionProfile يجب أن يكون نطاقاته معينة على api://9b975845-388f-4429-889e-eab1ef63949c/Agent365.Observability.OtelWrite. بدون هذا الإعداد، يتم توجيه نطاق الرمز إلى جمهور الروبوت نفسه (api://botid-...) ويفشل التصدير برمز خطأ HTTP 401 InvalidAudience.

إشعار

AGENT_APP.auth.get_token() يقوم بإرجاع الرمز المميز بالنطاق الصحيح مباشرةً - ولا حاجة إلى استدعاء exchange_token(). تتولى Bot Framework Token Service معالجة تبادل OBO عندما يستهدف نطاق اتصال OAuth مورد قابلية المراقبة A365.

محرك مخصص باستخدام S2S

يمكن لعاملي المحرك المخصص استخدام S2S (بيانات اعتماد العميل) للحصول على رمز تطبيق فقط باستخدام بيانات اعتماد اتصال الخدمة. تستخدم هذه الطريقة بيانات اعتماد عملاء MSAL القياسية - دون الحاجة إلى سلسلة قائمة على العاملين.

المتطلبات

  • تسجيل تطبيق Azure AD: يجب أن يكون تطبيقا مخصصا (قياسيا ). لا يمكن لتسجيلات التطبيقات المُمكَّنة لـ Agent 365 استخدام client_credentials العادي لمورد الرصد (AADSTS82001).
  • أذونات التطبيق: أضفAgent365.Observability.OtelWrite (تطبيق، وليس مفوضًا)، ثم امنح موافقة المسؤول.

مهم

يجب أن يكون agentId المستخدم للتخزين المؤقت هو ClientId الخاص بـ ServiceConnection . رابط التصدير هو /observabilityService/tenants/{tenantId}/otlp/agents/{agentId}/traces: أي عدم تطابق يؤدي إلى خطأ HTTP 403.

الخطوة 1: تكوين البيئة والتطبيق:

توضح الأمثلة التالية كيفية تكوين تطبيقك وبيئة التشغيل، بما في ذلك قيم اتصال الخدمة، وإعدادات المستأجر والعميل، وتعيينات التفويض المطلوبة.

# .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

الخطوة 2 - تكوين distro لـ S2S

الأمثلة التالية توضح كيفية تمكين تصدير Agent 365، وتعيين المصدر إلى نقطة نهاية S2S، وتسجيل عملية بحث مخصصة TokenResolver للرموز المميزة أثناء التصدير.

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,
)

الخطوة 3: احصل على رمز S2S المميز

توضح الأمثلة التالية كيفية طلب رمز وصول خاص بالتطبيق لمورد المراقبة باستخدام بيانات اعتماد اتصال الخدمة، ثم تخزينه مؤقتًا حسب عامل والمستأجر للمُصدِّر.

# 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

الخطوة 4: تحديد الأمتعة لتصدير النطاق

يتطلب مُصدِّر Agent365 تعيين الأمتعة (معرف المستأجر ومعرف العامل) في سياق النطاق. بدون ذلك، يقوم المُصدِّر بإسقاط الامتدادات بصمت مع الرسالة 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])