AgentApplication w Zestawie SDK agentów usługi Microsoft 365

AgentApplication jest centralnym modułem konstrukcyjnym agenta zbudowanego przy użyciu Agents SDK. AgentApplication to punkt wejścia dla wszystkich działań przychodzących, w tym wiadomości od użytkowników, zdarzeń cyklu życia konwersacji, interakcji z kartami adaptacyjnymi i wywołań zwrotnych protokołu OAuth.

Agent jest w swojej istocie elementem typu AgentApplication. Konfigurujesz go za pomocą programów obsługujących, które opisują, co robi agent. SDK zajmuje się routingiem, zarządzaniem stanem oraz infrastrukturą niezbędną do uruchomienia agenta.

Jak działa AgentApplication

Każdy agent ma cykl życia, który rozpoczyna się, gdy kanał (Microsoft Teams, Bot Service lub niestandardowy klient) dostarcza aktywność do punktu końcowego agenta. AgentApplication znajduje się w centrum tego cyklu życia:

Channel → Hosting layer → AgentApplication → Your handlers

Warstwy przetwarzania w agencie zbudowanym za pomocą Agents SDK działają następująco:

  1. Warstwa hostingowa odbiera żądanie HTTP i uwierzytelnia je.
  2. Element AgentApplication przetwarza przychodzące działanie za pośrednictwem swojego potoku.
  3. Procedury obsługi są wywoływane na podstawie pasujących tras.

Agent ładuje stan tury przed uruchomieniem procedur obsługi. Następnie agent zapisuje stan tury.

Podstawowe pojęcia

Działania

Wszystkie elementy w zestawach SDK agentów przepływają jako działanie. Aktywność to uporządkowana wiadomość reprezentująca coś, co się wydarzyło. Aktywność ma typ, taki jak wiadomość, zdarzenie, wywołanie, conversationUpdate itd. Zawiera ładunek odpowiedni dla tego typu. AgentApplication odbiera aktywności i kieruje je do właściwej procedury obsługi.

Trasy

Trasa łączy selektor z procedurą obsługi. Selektor określa, czy trasa pasuje do aktualnej aktywności. Procedura obsługi uruchamia logikę, gdy trasa jest zgodna.

Rejestruj trasy podczas konfiguracji agenta. Mogą one być zgodne:

  • Wiadomość zawierająca konkretny tekst lub pasująca do wyrażenia regularnego
  • Dowolna aktywność danego typu
  • Zdarzenia cyklu życia rozmowy (dodanie członka, usunięcie członka)
  • Działania związane z kartami adaptacyjnymi
  • Warunki niestandardowe

Po nadejściu działania system ocenia trasy w kolejności do momentu znalezienia dopasowania. Domyślnie uruchomiona jest tylko jedna trasa.

Stan tury

AgentApplication zarządza stanem elementu _turn — magazyn strukturalny podzielony na partycje na podstawie zakresów:

Typ zakresu Podpis
Konwersacja Współdzielone przez wszystkich użytkowników rozmowy, przechowywane między turami
Użytkownika Przypisane do zakresu obejmującego pojedynczego użytkownika we wszystkich konwersacjach
Tymczasowe Tylko bieżąca kolejka — nigdy nieutrwalana

System automatycznie ładuje stan przed uruchomieniem procedur obsługi i zapisuje go automatycznie później.

Kontekst tury

Po uruchomieniu procedury obsługi otrzymuje kontekst sesji. Kontekst tury jest migawką bieżącego działania, połączenia z adapterem oraz narzędzi do wysyłania odpowiedzi. Kontekst tury to twój interfejs do bieżącej interakcji.

Oprogramowanie pośredniczące

AgentApplication obsługuje potok oprogramowania pośredniczącego. Oprogramowanie pośredniczące to łańcuch składników, które przetwarzają każdą turę przed i po uruchomieniu procedur obsługi. Oprogramowanie pośredniczące może analizować, transformować lub przerywać przepływ aktywności. Do typowych zastosowań należą logowanie, kontrola uwierzytelniania oraz normalizacja żądań.

Utwórz agenta

Rozszerz klasę AgentApplication i zarejestruj programy obsługujące w konstruktorze. Struktura hostingowa automatycznie wstrzykuje AgentApplicationOptions.

public class MyAgent : AgentApplication
{
    public MyAgent(AgentApplicationOptions options) : base(options)
    {
        OnConversationUpdate(ConversationUpdateEvents.MembersAdded, WelcomeAsync);
        OnActivity(ActivityTypes.Message, OnMessageAsync, rank: RouteRank.Last);
    }

    private async Task WelcomeAsync(ITurnContext context, ITurnState state, CancellationToken ct)
    {
        foreach (var member in context.Activity.MembersAdded)
        {
            if (member.Id != context.Activity.Recipient.Id)
            {
                await context.SendActivityAsync("Hello! How can I help you?", cancellationToken: ct);
            }
        }
    }

    private async Task OnMessageAsync(ITurnContext context, ITurnState state, CancellationToken ct)
    {
        await context.SendActivityAsync($"You said: {context.Activity.Text}", cancellationToken: ct);
    }
}

Zarejestruj agenta w Program.cs:

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

builder.Services.AddHttpClient();
builder.Services.AddSingleton<IStorage, MemoryStorage>();
builder.Services.AddAgent<MyAgent>();
builder.Services.AddAgentAspNetAuthentication(builder.Configuration);

WebApplication app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();
app.MapAgentApplicationEndpoints(requireAuth: !app.Environment.IsDevelopment());

app.Run();

Rejestrowanie procedur obsługi działań

Obsługa wiadomości

Dopasuj wiadomości po dokładnym tekście (niezależnie od wielkości liter):

OnMessage("help", async (context, state, ct) =>
{
    await context.SendActivityAsync("Here's what I can do...", cancellationToken: ct);
});

Dopasuj wiadomości za pomocą wyrażenia regularnego:

OnMessage(new Regex(@"^order\s+\d+$", RegexOptions.IgnoreCase), async (context, state, ct) =>
{
    await context.SendActivityAsync("Looking up your order...", cancellationToken: ct);
});

Obsługa aktualizacji rozmów

Zarejestruj procedury obsługi dla zdarzeń cyklu życia konwersacji, takich jak dołączanie członków lub opuszczanie przez członków.

OnConversationUpdate(ConversationUpdateEvents.MembersAdded, async (context, state, ct) =>
{
    foreach (var member in context.Activity.MembersAdded)
    {
        if (member.Id != context.Activity.Recipient.Id)
        {
            await context.SendActivityAsync("Welcome!", cancellationToken: ct);
        }
    }
});

OnConversationUpdate(ConversationUpdateEvents.MembersRemoved, async (context, state, ct) =>
{
    // Called when participants leave the conversation
});

Obsługa dowolnego typu aktywności

Dopasowywanie dowolnej aktywności według jej ciągu znaków typu dla pełnej kontroli nad routingiem.

OnActivity(ActivityTypes.Message, async (context, state, ct) =>
{
    // Handles all message activities
});

OnActivity(ActivityTypes.Event, async (context, state, ct) =>
{
    // Handles event activities
});

Używaj ActivityTypes stałych zamiast zakodowanych na stałe ciągów znaków.

Kontroluj kolejność oceny tras

System ustala ustaloną kolejność oceny tras podczas ich rejestracji, a nie w czasie działania programu. Sortowanie wykorzystuje dwa poziomy:

  1. Typ trasy: System grupuje trasy według typu i zawsze rozpatruje typy o wyższym priorytecie przed typami o niższym priorytecie, niezależnie od rangi:

    Priorytet Typ trasy
    1 (najwyższy) Trasy wywołania agentów
    2 Trasy wywoływania (akcje kart adaptacyjnych, wywołania zwrotne protokołu OAuth i inne wywołania zależne od czasu)
    3 Trasy agentów
    4 (najniższy) Wszystkie inne trasy
  2. Rank: W każdej grupie typu trasy system porządkuje trasy według wartości ich rangi. Najpierw oceniane są niższe wartości liczbowe.

Użyj RouteRank stałych do ustawiania rangi przy rejestracji procedury obsługi:

Stała Value Znaczenie
RouteRank.First 0 Oceniane przed wszystkimi innymi trasami w swojej grupie
RouteRank.Unspecified 32767 Domyślnie, gdy ranga nie jest określona
RouteRank.Last 65535 Oceniane po wszystkich innych trasach w swojej grupie

Domyślnie przetwarzanie zatrzymuje się na pierwszej pasującej trasie. Użyj RouteRank.Last jako ogólnego mechanizmu rezerwowego, który obsługuje wszystko, co nie pasuje do bardziej szczegółowej trasy.

// Specific handlers use the default rank
OnMessage("status", HandleStatusAsync);
OnMessage("help", HandleHelpAsync);

// Catch-all — handles anything not matched above
OnActivity(ActivityTypes.Message, HandleUnknownMessageAsync, rank: RouteRank.Last);

Elementy zaczepienia cyklu życia tury

Zarejestruj logikę, która działa przy każdej turze, przed lub po dopasowaniu tras. Te elementy zaczepienia są przydatne w przypadku rejestrowania, zagadnień przekrojowych i obsługi błędów.

OnBeforeTurn(async (context, state, ct) =>
{
    logger.LogInformation("Turn started: {Type}", context.Activity.Type);
    return true; // Return false to abort the turn
});

OnAfterTurn(async (context, state, ct) =>
{
    logger.LogInformation("Turn completed");
    return true; // Return false to skip state saving
});

OnTurnError(async (context, state, exception, ct) =>
{
    logger.LogError(exception, "Turn error");
    await context.SendActivityAsync("Something went wrong. Please try again.", cancellationToken: ct);
});

Gdy OnBeforeTurn zwraca wartość false, tura jest przerywana i nie są uruchamiane żadne trasy. Gdy OnAfterTurn zwraca false, stan tury nie jest zapisywany.

Korzystanie ze stanu tury

Agent automatycznie ładuje stan tury przed uruchomieniem procedur obsługi i zapisuje go później. Obiekt stanu tury przekazany do procedur obsługi zapewnia dostęp do różnych zakresów, dzięki czemu można odczytywać i zapisywać dane, które są utrwalane między turami lub są tymczasowe dla bieżącej tury.

  • Zakres rozmowy: Dla danych współdzielonych na wszystkich turach rozmowy
  • Zakres użytkownika: Dla danych indywidualnych użytkownika
  • Zakres tymczasowy: dla danych, które muszą istnieć tylko podczas bieżącej tury
OnActivity(ActivityTypes.Message, async (context, state, ct) =>
{
    // Conversation scope — persisted per conversation
    var count = state.Conversation.GetValue<int>("messageCount", () => 0);
    state.Conversation.SetValue("messageCount", count + 1);

    // User scope — persisted per user
    var name = state.User.GetValue<string>("displayName");

    // Temp scope — current turn only
    state.Temp.SetValue("parsedInput", context.Activity.Text?.Trim());

    await context.SendActivityAsync($"Message #{count + 1}: {context.Activity.Text}", cancellationToken: ct);
});

Notatka

Użyj MemoryStorage do lokalnego tworzenia i testowania. W przypadku wdrożeń produkcyjnych, zwłaszcza wdrożeń działających na wielu wystąpieniach, należy użyć dostawcy trwałej pamięci masowej, takiego jak Azure Cosmos DB lub Azure Blob Storage. Zobacz Używanie dostawców magazynu w agencie.

Następne kroki