Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
AgentApplication является центральным строительным блоком агента, построенного с помощью SDK Agent.
AgentApplication является точкой входа для всей входящей активности, включая сообщения от пользователей, события жизненного цикла разговоров, адаптивные взаимодействия с картами, обратные звонки OAuth.
Агент в своей сути AgentApplication— это . Вы настраиваете его с помощью обработчиков, которые описывают, чем занимается ваш агент. SDK отвечает за маршрутизацию, управление штатами и инфраструктуру, необходимую для его работы.
Как работает AgentApplication
У каждого агента есть жизненный цикл, который начинается, когда канал (Microsoft Teams, бот-сервис или пользовательский клиент) доставляет активность на конечную точку вашего агента.
AgentApplication Находится в центре этого жизненного цикла:
Channel → Hosting layer → AgentApplication → Your handlers
Уровни обработки в агенте, построенном с помощью SDK агентов, работают следующим образом:
- Хостинговый уровень принимает HTTP-запрос и аутентифицирует его.
- Он обрабатывает
AgentApplicationвходящую активность через свой конвейер. - Ваши кураторы вызываются по совпадающим маршрутам.
Загрузка агента переходит в состояние до того, как хендлеры сбегают. После этого агент сохраняет состояние хода.
Основные понятия
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 константы вместо жёстко закодированных строк.
Порядок оценки маршрутов управления
Система сортирует маршруты в фиксированный порядок оценки при регистрации, а не во время выполнения. Сортировка включает два уровня:
Тип маршрута: система группирует маршруты по типу и всегда оценивает типы с более высоким приоритетом перед низкоприоритетными, независимо от ранга:
Priority Тип маршрута 1 (самая высокая) Агентные маршруты вызова 2 Вызов маршрутов (адаптивные действия карты, OAuth callback и другие временные вызовы) 3 Агентские маршруты 4 (самый низкий) Все остальные маршруты Ранг: Внутри каждой группы типов маршрутов система упорядочивает маршруты по их значению ранга. Сначала оцениваются более низкие числовые значения.
Используйте 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. См. «Использовать поставщики хранения в вашем агенте».