Birden çok kullanıcıyı tek bir barındırılan ajan oturumunda çoklayın

Varsayılan olarak, her arayan, Kullanıcı başına barındırılan ajan oturumlarını yalıtma bölümünde açıklandığı gibi kendisine ait bir barındırılan ajan oturumu alır. Birçok kullanıcıya (Teams botu, ISV ağ geçidi veya müşteri desteği platformu) hizmet veren uygulamaların kullanıcı başına bir oturuma ihtiyacı yoktur. Bunun yerine, orta katman hizmeti birçok kullanıcıyı paylaşılan oturumlardan oluşan sınırlanmış bir havuza eşler ve her çağrıda her kullanıcıyı tanımlar.

Bu makale, orta katmanınızdan kullanıcılar arasında oturumları nasıl havuzlayacağınızı ve bunu yaparken her kullanıcının verilerini paylaşılan bir oturum içinde yalıtılmış tutmayı gösterir.

Platform, kullanıcılar bir oturumu paylaşsa bile konuşma durumunu sizin için yalıtır: bir kullanıcının oluşturduğu yanıt zinciri başka bir kullanıcı tarafından previous_response_id aracılığıyla devam ettirilemez ve context.get_history() yalnızca geçerli isteği yapan kullanıcının görme yetkisine sahip olduğu geçmişi döndürür. İki öğeye sahipsiniz: orta katmanınızdaki kullanıcı oturumu eşlemesi ve kapsayıcınızın kendisini depoladığınız tüm verilerin (dosyalar, satırlar veya önbellekler) platform tarafından yönetilen konuşma durumunun ötesinde bölümlenmesi.

Eksiksiz, çalıştırılabilir bir oturum çoklama örneği, hem orta katman oturum havuzunu hem de kapsayıcı işleyicisini gösterir; bu makale de ilerledikçe ilgili dosyalarına bağlantılar verir.

Prerequisites

  • Kapsayıcı protokolünün 2.0.0 sürümünü kullanan barındırılan bir aracı. Yükseltmek için Barındırılan aracıları geçirme konusuna bakın.
  • Microsoft.CognitiveServices/accounts/AIServices/agents/endpoints/UserIdentityImpersonation/action izni, orta katmanlı hizmetinizin kimliğine atanmıştır. Bu izin yerleşik rollere dahil değildir; özel bir rol aracılığıyla verme — bkz. Son kullanıcı kimliğini devretme. Bu olmadan, x-ms-user-identity başlığı 403 ile reddedilir.
  • Orta katman için Azure AI Projeleri istemci kitaplığı ve kapsayıcı için Azure AI AgentServer SDK'sı (azure-ai-agentserver-corePython için 2.0.0b7+ veya Azure.AI.AgentServer.Core .NET için 1.0.0-beta.26+ ).
  • Test etmek için dağıtılan bir aracı. Yerel çalıştırmalarda yalıtım zorunlu tutulmaz.

Paylaşılan oturumda iki kullanıcıyı yalıtma

Temel davranışla başlayın: iki kullanıcı - bunlara Alice ve Bob diyelim; örnekte temsil edilen kullanıcılar - tek bir agent_session_id öğesini paylaşabilir ve platform yine de her kullanıcının görüşmesini özel tutar. Orta katmanınız, her çağrıda x-ms-user-identity üst bilgisiyle adına işlem yapılan kullanıcıyı tanımlar (temsil). Kullanıcının kendi konuşmasına devam etmek için kullanıcının önceki yanıtlarını olarak previous_response_idgeçirir.

Azure Geliştirici CLI'sından aynı kimlik üst bilgisini göndermek için azd ai agent invoke --user-identity kullanın. Örnekler ve kullanıcının oturum ve konuşma durumunu seçme hakkında bilgi için bkz. Son kullanıcı kimliğini geçirme .

Örnekteki en basit invoke_previous_response_isolation.py çağırıcı, SDK'nın aracısına bağlı Responses istemcisini kullanarak tam olarak bunu gönderir:

# Agent-bound Responses client from the Foundry SDK.
responses_client = project_client.get_openai_client(agent_name=agent_name).responses

# Target the shared session with agent_session_id, and identify the acted-for
# user with x-ms-user-identity (delegation). Pass previous_response_id to
# continue this user's own chain. Don't send x-agent-user-id; Foundry sets the
# container-side request context after it resolves the user.
kwargs = {
    "input": user_message,
    "stream": False,
    "store": True,
    "extra_body": {"agent_session_id": session_id},
    "extra_headers": {"x-ms-user-identity": user_id},
}
if previous_response_id:
    kwargs["previous_response_id"] = previous_response_id

response = responses_client.create(**kwargs)

Platform, her yanıt zincirini onu oluşturan kullanıcıyla bağlar. Bob aynı oturumdayken Alice'in previous_response_id öğesini gönderirse çağrı başarısız olur; Bob, Alice'in konuşmasını sürdüremez. Bu garanti, kapsayıcınızda herhangi bir ek yalıtım kodu olmadan da geçerlidir.

Oturum havuzu olan birçok kullanıcıya ölçeklendirin

Bir oturumda iki kullanıcıyı yalıtma yapı taşıdır. Birçok kullanıcıya hizmet vermek için, bunları kullanıcı başına bir oturum açmak yerine sınırlanmış bir oturum kümesinde havuza alabilirsiniz.

Her oturum, bir sırayı etkin bir şekilde işlerken bölgesel eşzamanlı oturum sınırlarına göre sayılır, bu nedenle kullanıcı başına bir oturum ölçeklendirilemez. Kullanıcılar etkileşimler arasında okur, düşünür ve yazar; bu nedenle tepe eşzamanlı istek sayınız genellikle toplam kullanıcı sayınızın küçük bir kısmını oluşturur. Havuzu bu tepe değere göre boyutlandırın, ardından her kullanıcıyı bu havuzdaki bir oturumla eşleyin ve önceki bölümde olduğu gibi, her çağrıda o kullanıcının kimliğini iletin.

Kullanıcıları oturumlara nasıl eşleyeceğine karar verin. Yaygın stratejiler şunlardır:

  • Yapışkan, en az yüklü. Geri dönen bir kullanıcı oturumlarını yeniden kullanabilir; yeni kullanıcılar en az yüklenen oturuma gider. Bu strateji yükü eşit olarak yayar ve kullanıcının dönüşlerini bir arada tutar. Oturumlar kullanıcı başına bir sınıra ulaştığında havuzu büyütün.
  • Hash tabanlı. hash(user_id) % pool_size ile bir oturum atayın. Bu strateji basit ve durumsuzdur, ancak yük dağılımı dengesiz olabilir ve havuzun yeniden boyutlandırılması kullanıcıların yeniden dağıtılmasına neden olur.
  • Döngüsel. İstekleri havuz genelinde eşit olarak dağıtın. Bu strateji basittir, ancak bir kullanıcının iletileri farklı oturumlara yönlendirilebilir.
  • Grup tabanlı. İlgili kullanıcıların oturumları paylaşması için kiracı, ekip veya bölgeye göre yönlendirme. Bu strateji, bir grup paylaşımı bağlamındaki kullanıcılar için kullanışlıdır.

Örnekteki invoke_session_pool.py çağırıcı, çağırıcıya ait atamayı iki stratejiyle uygular: sticky-fill ve round-robin. Geri dönen bir kullanıcı oturumlarını her zaman korur; seçilen strateji tarafından yeni bir kullanıcı yerleştirilir. Yapışkan doldurma yolu en az yüklenen oturumu doldurur ve yalnızca her oturum kapasitede olduğunda yeni bir oturum açar:

def get_session_for_user(self, user_id: str) -> str:
    if user_id in self.user_to_session:
        return self.user_to_session[user_id]      # returning user is sticky
    session_id = self._next_fill_session()        # new user: place by strategy
    self.user_to_session[user_id] = session_id
    self.session_user_counts[session_id] += 1
    return session_id

def _next_fill_session(self) -> str:
    # Reuse a session with capacity; open a new one only when all are full.
    session_id = next(
        (s for s, count in self.session_user_counts.items()
         if count < self.max_users_per_session),
        None,
    )
    if session_id is None:
        session_id = self._session_name(len(self.session_user_counts))
        self.session_user_counts[session_id] = 0
    return session_id

Döndürülen oturum kimliğini daha önce gösterilen aynı yetkilendirilmiş çağrıya iletin: agent_session_id içinde extra_body olur ve x-ms-user-identity kullanıcıya özgü tanımlayıcı olarak kalır.

Kapsayıcınızdaki isteği işleme

Protokol 2.0.0’da platform, adına işlem yapılan kullanıcıyı belirler ve bunu get_request_context() aracılığıyla işleyicinize sunar. Bu bağlamı doğrulayın (yerel çalıştırmalarda olduğu gibi eksik olduğunda kapatılamaz), ardından platformun ile context.get_history()kullanıcı başına geçmişi döndürmesine izin verin. Örnekteki main.py işleyici kendine ait herhangi bir konuşma durumu bilgisi saklamaz:

from azure.ai.agentserver.core import get_request_context

@app.response_handler
async def handler(request, context, _cancellation_signal):
    ctx = get_request_context()
    if not (ctx.user_id and ctx.call_id):
        # Hosted protocol 2.0.0 populates this context; off-platform it's absent.
        raise ValueError("A user context is required on protocol 2.0.0.")

    user_input = await context.get_input_text() or "Hello!"
    history = await context.get_history()       # platform-authorized for this user
    input_items = _build_input(user_input, history)

    response = _responses_client.create(model=_model, input=input_items, store=False)
    return TextResponse(context, request, text=response.output_text)

Platform istek başına yetkilendirildiğinden context.get_history() , paylaşılan oturumdaki bir kullanıcı hiçbir zaman başka bir kullanıcının konuşma geçmişini almaz.

Kapsayıcınızın depoladığı kullanıcı başına verileri bölümlendirin

Platform konuşma geçmişini sizin için yalıtıyor. Kapsayıcınız kendi verilerini de depolarsa (dosyalar, veritabanı satırları veya önbellek) bu veriler otomatik olarak bölümlenmez. Hem oturum kimliğine hem de kullanıcı kimliğine göre anahtarlayın; böylece aynı oturumdaki iki kullanıcı birbirlerinin verilerini göremez:

partition = (agent_session_id, user_id)

Uyarı

Kullanıcılar bir oturumu paylaştığında platform, kapsayıcınızın kendisinin depoladığı verileri ayrıştırmaz. Kapsayıcınız bu verileri yalnızca oturum kimliğine göre anahtarlarsa havuzdaki her kullanıcı aynı verileri görür. Kullanıcı kimliğini her zaman bölüm anahtarına ekleyin.

İstek başına platform bağlamında kullanıcı kimliğini okuyun:

from azure.ai.agentserver.core import get_request_context

def partition_key() -> tuple[str, str]:
    ctx = get_request_context()
    if not ctx or not ctx.user_id:
        raise PermissionError("A user context is required on protocol 2.0.0.")
    return (ctx.session_id, ctx.user_id)   # key all user-owned data by this

Platform ayrıca kullanıcıyı x-agent-user-id istek üst bilgisi olarak ekler. Çalışma zamanınız SDK bağlamını kullanmıyorsa bu üst bilgiyi doğrudan okuyun.

Platform, 2.0.0 protokolünde get_request_context().user_id doldurur. Oturuma birden fazla kullanıcı girebiliyorsa, kullanıcıya ait veriler için hiçbir zaman oturum kimliğini tek başına kullanmayın.

Üzerinde derleme yapılması gereken oturum başına depolama örneği için not alma aracısı örneğine bakın. Her oturum için $HOME altında bir dosyayı anahtar olarak kullanır. Paylaşılan oturum için, her kullanıcının kendi bölümünü alması için bu anahtarı istek bağlamındaki kullanıcı kimliğiyle genişletin.

Yalıtımı doğrulayın

Garantiyi numunenin A-A-B testiyle doğrulayın, invoke_previous_response_isolation.py. Dağıtılan aracınızda iki ayrı kullanıcıyla çalıştırın (örnek varsayılan olarak Alice ve Bob'dır):

  1. Alice olarak, paylaşılan oturumda bir yanıt oluşturun ve id değerini yakalayın.
  2. Alice olarak, aynı oturumda previous_response_id değeri ilk yanıtın id değerine ayarlanmış ikinci bir yanıt oluşturun ve bunun id değerini yakalayın.
  3. Bob olarak, aynı oturumda, previous_response_id Alice'in ikinci yanıtına ayarlanmış bir istek gönderin. Çağrı başarısız olur - Bob, Alice'in zincirini devam ettiremiyor.

İki farklı Entra kullanıcısı veya nesne kimlikleri kullanın. Aynı kimliğe çözümleyen iki etiket geçerli bir kullanıcı arası test değildir.

Protokol 2.0.0 yolunda eski yalıtım üst bilgisinin gönderilmesi hataya neden olur, çünkü bu modelin yerini platformun kullanıcı bağlamı almıştır.