AgentApplication в Пакет SDK агентов Microsoft 365

AgentApplication является центральным строительным блоком агента, построенного с помощью SDK Agent. AgentApplication является точкой входа для всей входящей активности, включая сообщения от пользователей, события жизненного цикла разговоров, адаптивные взаимодействия с картами, обратные звонки OAuth.

Агент в своей сути AgentApplication— это . Вы настраиваете его с помощью обработчиков, которые описывают, чем занимается ваш агент. SDK отвечает за маршрутизацию, управление штатами и инфраструктуру, необходимую для его работы.

Как работает AgentApplication

У каждого агента есть жизненный цикл, который начинается, когда канал (Microsoft Teams, бот-сервис или пользовательский клиент) доставляет активность на конечную точку вашего агента. AgentApplication Находится в центре этого жизненного цикла:

Channel → Hosting layer → AgentApplication → Your handlers

Уровни обработки в агенте, построенном с помощью SDK агентов, работают следующим образом:

  1. Хостинговый уровень принимает HTTP-запрос и аутентифицирует его.
  2. Он обрабатывает AgentApplication входящую активность через свой конвейер.
  3. Ваши кураторы вызываются по совпадающим маршрутам.

Загрузка агента переходит в состояние до того, как хендлеры сбегают. После этого агент сохраняет состояние хода.

Основные понятия

Activities

Всё в SDK Agents течёт как активность. Активность — это структурированное сообщение, представляющее то, что произошло. У активности есть тип, например, сообщение, событие, вызов, conversationUpdate и так далее. Он несёт полезный груз, соответствующий этому типу. AgentApplication получает задания и направляет их правому куратору.

Routes

Маршрут сочетает селектор с обработчиком. Селектор определяет, соответствует ли маршрут текущей активности. Хендлер запускает вашу логику, когда маршрут совпадает.

Регистрируйте маршруты при настройке агента. Они могут совпадать:

  • Сообщение, содержащее определённый текст или соответствующее регулярному выражению
  • Любая активность заданного типа
  • События жизненного цикла разговора (добавлен участник, удалён)
  • Адаптивные действия карты
  • Настраиваемые условия

Когда активность приходит, система оценивает маршруты по порядку, пока не найдёт совпадение. По умолчанию работает только один маршрут.

Поворотное состояние

AgentApplication управляет _turn состоянием — структурированное хранилище, разделённое на области измерения:

Тип области Description
Разговор Общая для всех пользователей в разговоре, сохранялась между ходами
Пользователь Охватывает отдельного пользователя во всех переписках
Температура Только текущий ход — никогда не сохранялся

Система автоматически загружает состояние до запуска ваших обработчиков и сохраняет его после.

Контекст поворота

Когда обработчик выполняется, он получает контекст хода. Контекст поворота — это снимок текущей активности, подключения адаптера и утилит для отправки ответов. Контекст хода — это ваш интерфейс к текущему взаимодействию.

Middleware

AgentApplication поддерживает промежуточную конвейерную систему. Промежуточное ПО — это цепочка компонентов, которые обрабатывают каждый ход до и после запуска ваших обработчиков. Промежуточное ПО может инспектировать, преобразовывать или отключать поток активности. Распространённые применения включают логирование, проверку аутентификации и нормализацию запросов.

Создание агента

Подкласс AgentApplication и регистрация своих хендлеров в конструкторе. Фреймворк хостинга автоматически вводит 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);
    }
}

Зарегистрируйте своего агента в 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();

Обработчики активности регистров

Обработка сообщений

Сопоставьте сообщения по точному тексту (без учета регистра):

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

Сопоставьте сообщения с помощью регулярного выражения:

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

Обработка обновлений в переписке

Регистрируйте кураторов для событий жизненного цикла разговоров, таких как присоединение участников или уход.

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
});

Обрабатывайте любой тип активности

Сопоставьте любую активность по её типовой строке для полного контроля маршрутизации.

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

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

Используйте ActivityTypes константы вместо жёстко закодированных строк.

Порядок оценки маршрутов управления

Система сортирует маршруты в фиксированный порядок оценки при регистрации, а не во время выполнения. Сортировка включает два уровня:

  1. Тип маршрута: система группирует маршруты по типу и всегда оценивает типы с более высоким приоритетом перед низкоприоритетными, независимо от ранга:

    Priority Тип маршрута
    1 (самая высокая) Агентные маршруты вызова
    2 Вызов маршрутов (адаптивные действия карты, OAuth callback и другие временные вызовы)
    3 Агентские маршруты
    4 (самый низкий) Все остальные маршруты
  2. Ранг: Внутри каждой группы типов маршрутов система упорядочивает маршруты по их значению ранга. Сначала оцениваются более низкие числовые значения.

Используйте RouteRank константы для установки ранга при регистрации обработчика:

Постоянный Ценность Значение
RouteRank.First 0 Оценивается раньше всех остальных маршрутов своей группы
RouteRank.Unspecified 32767 По умолчанию, когда ранг не указан
RouteRank.Last 65535 Оценивается после всех остальных маршрутов своей группы

По умолчанию оценка останавливается на первом маршруте совпадения. Используйте RouteRank.Last универсальный запасной вариант, который справляется с тем, что не соответствует более конкретному маршруту.

// 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);

Крючки жизненного цикла поворота

Регистрируйте логику, которая работает на каждом ходу, до или после совпадения маршрутов. Эти крючки полезны для ведения логов, пересечения задач и обработки ошибок.

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);
});

При OnBeforeTurn возвращении falseход отменяется, и маршруты не проходят. Когда OnAfterTurn возвращается false, состояние хода не сохраняется.

Используйте состояние хода

Агент автоматически загружает состояние хода до запуска ваших обработчиков и сохраняет его после. Объект состояния хода, передаемый вашим обработчикам, даёт доступ к разным областям, чтобы вы могли читать и записывать данные, которые сохраняются на протяжении ходов или являются эфемерными для текущего хода:

  • Область разговора: Для данных, передающихся по всем ходам разговора
  • Объём пользователя: Для данных на каждого пользователя
  • Временный диапазон: для данных, которые должны существовать только во время текущего хода
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);
});

Замечание

Использование MemoryStorage для локальной разработки и тестирования. Для производственных развертываний, особенно для развертываний, работающих на нескольких экземплярах, используйте постоянного поставщика хранения, такого как Azure Cosmos DB или Хранилище BLOB-объектов Azure. См. «Использовать поставщики хранения в вашем агенте».

Дальнейшие шаги