Использование диалога для использования навыка
ОБЛАСТЬ ПРИМЕНЕНИЯ: ПАКЕТ SDK версии 4
В этой статье показано, как использовать диалог навыка в потребителе навыка. Диалоговая система передает действия от родительского бота к боту навыка и возвращает пользователю ответы навыка. Бот навыка, к которому обращается этот потребитель, может обрабатывать сообщения и события. Пример манифеста навыка и сведения о реализации этого навыка см. в статье о применении диалогов в навыке.
Для получения информации о том, как использовать бота навыка вне диалогов, см. раздел о реализации потребителя навыка.
Примечание.
Пакеты SDK для JavaScript, C# и Python для Bot Framework по-прежнему будут поддерживаться, однако пакет SDK для Java выводится из эксплуатации, и окончание окончательной долгосрочной поддержки состоится в ноябре 2023 года.
Существующие боты, созданные с помощью пакета SDK для Java, будут продолжать функционировать.
Для создания нового бота рекомендуется использовать Microsoft Copilot Studio и изучить выбор подходящего решения copilot.
Дополнительные сведения см. в статье "Будущее создания бота".
Предварительные условия
- Понимание принципов работы ботов, принципов работы ботов навыков и принципов реализации потребителя навыка.
- При необходимости подписка Azure. Если у вас ее нет, создайте бесплатную учетную запись перед тем, как начать.
- Копия примера skills skillDialog в C#, JavaScript, Java или Python.
Об этом примере
В пример skills skillDialog включены проекты двух ботов:
- Корневой бот диалога, который использует класс диалога навыка для использования навыка.
- Бот диалогового навыка, который использует диалог для обработки действий, поступающих от пользователей навыков.
В этой статье основное внимание уделяется использованию класса диалога навыка в корневом боте для управления скиллом, отправки сообщений и выполнения действий событий, а также отмены скилла.
Сведения о других аспектах создания потребителя навыка см. в статье о реализации потребителя навыка.
Чтобы получить информацию о боте, использующем навыки диалога, см. как использовать диалоги в рамках навыка.
Ресурсы
Для развернутых ботов проверка подлинности "бот — бот" требует, чтобы каждый участвующий бот имеет допустимое удостоверение. Однако вы можете проверить навыки и потребителей навыков локально с помощью эмулятора Bot Framework без использования информации об идентификации.
Конфигурация приложений
- При необходимости добавьте данные удостоверения корневого бота в файл конфигурации.
- Добавьте конечную точку навыка (URL-адрес службы или обратного вызова), по которой навыки должны отвечать потребителю.
- Добавьте запись для каждого навыка, который будет использоваться потребителем навыка. Каждая запись включает:
- идентификатор, который потребитель навыка использует для идентификации навыка;
- При необходимости приложение или идентификатор клиента бота навыка.
- конечная точка обмена сообщениями для этого навыка.
Примечание.
Если пользователь навыка или навыка указывает удостоверение, необходимо и то, и другое.
DialogRootBot\appsettings.json
При необходимости добавьте сведения об удостоверениях основного бота и добавьте идентификатор приложения или клиента для бота с функцией эхо в BotFrameworkSkills
массив.
{
"MicrosoftAppType": "",
"MicrosoftAppId": "",
"MicrosoftAppPassword": "",
"MicrosoftAppTenantId": "",
"SkillHostEndpoint": "http://localhost:3978/api/skills/",
"BotFrameworkSkills": [
{
"Id": "DialogSkillBot",
"AppId": "",
"SkillEndpoint": "http://localhost:39783/api/messages"
}
]
}
Логика диалога
Основной диалог бота включает в себя диалог навыка для каждого потребляемого этим ботом навыка. Диалог навыка управляет навыком для вас посредством различных объектов, связанных с навыками, таких как клиент навыка и фабрика идентификаторов разговоров навыка. В основном диалоге также показано, как отменить навык (через диалог навыка) на основе вводимых пользователем данных.
Навык, используемый этим ботом, поддерживает несколько функций. Он может забронировать авиабилет и получить прогноз погоды для города. Кроме того, если он получает сообщение за пределами одного из этих контекстов и при этом настроен распознаватель LUIS, он пытается интерпретировать намерение пользователя.
Примечание.
Распознавание речи (LUIS) будет прекращен 1 октября 2025 года. Начиная с 1 апреля 2023 года вы не сможете создавать новые ресурсы LUIS. Новая версия распознавания речи теперь доступна как часть языка ИИ Azure.
Понимание разговорного языка (CLU), функция Azure AI Language, является обновленной версией LUIS. Дополнительные сведения о поддержке распознавания речи в пакете SDK Bot Framework см. в разделе "Распознавание естественного языка".
Манифест навыка (C#, JavaScript, Java, Python) описывает действия, которые может выполнять навык, его входные и выходные параметры, а также конечные точки навыка. Обратите внимание, что навык умеет обрабатывать события BookFlight и GetWeather. Он также обрабатывает сообщения.
Основной диалог содержит код для следующих действий:
- инициализация основного диалога;
- выбор навыка;
- Выберите действие навыка
- запуск навыка;
- оценка результата выполнения навыка;
- Позволить пользователю отменить навык
Основной диалог наследуется от класса компонентного диалога. Дополнительные сведения о компонентных диалогах см. в статье об управлении сложностью диалогов.
инициализация основного диалога;
Главный диалог включает диалоги (для управления потоком беседы за пределами навыка) и диалог навыков (для управления навыками). Водопад включает в себя следующие этапы, каждый из которых подробно описан в следующих разделах.
- Предложите пользователю выбрать навык. (Корневой бот использует один навык.)
- Попросите пользователя выбрать действие для этого навыка. (Бот навыка определяет три действия.)
- Начните выбранный навык с начальной активности, основанной на выбранном действии.
- Отобразите результаты после завершения навыка, если они есть. Затем перезапустите процесс водопада.
DialogRootBot\Dialogs\MainDialog.cs
Класс MainDialog
является производным от ComponentDialog
.
В дополнение к состоянию беседы диалогу требуется удостоверение корневого бота и ссылки на фабрику идентификаторов навыков, клиент навыка HTTP и объекты конфигурации навыков.
Конструктор диалогов проверяет входные параметры, добавляет диалоги для навыков и создает диалоговые окна запроса и каскадные диалоговые окна для управления потоком беседы за пределами навыка. Также он создает метод доступа к свойствам для отслеживания активного навыка при наличии такового.
Конструктор вызывает вспомогательный метод AddSkillDialogs
, чтобы создать SkillDialog
для каждого навыка, включенного в файл конфигурации, по мере считывания из файла конфигурации в объект SkillsConfiguration
.
// Helper method that creates and adds SkillDialog instances for the configured skills.
private void AddSkillDialogs(ConversationState conversationState, SkillConversationIdFactoryBase conversationIdFactory, SkillsConfiguration skillsConfig, string botId)
{
foreach (var skillInfo in _skillsConfig.Skills.Values)
{
// Create the dialog options.
var skillDialogOptions = new SkillDialogOptions
{
BotId = botId,
ConversationIdFactory = conversationIdFactory,
SkillClient = _auth.CreateBotFrameworkClient(),
SkillHostEndpoint = skillsConfig.SkillHostEndpoint,
ConversationState = conversationState,
Skill = skillInfo
};
// Add a SkillDialog for the selected skill.
AddDialog(new SkillDialog(skillDialogOptions, skillInfo.Id));
}
}
выбор навыка;
На первом шаге основное диалоговое окно предлагает пользователю выбрать, какой навык он хотел бы вызвать, и использует запрос выбора SkillPrompt, чтобы получить ответ. (Этот бот определяет только одно умение.)
DialogRootBot\Dialogs\MainDialog.cs
// Render a prompt to select the skill to call.
private async Task<DialogTurnResult> SelectSkillStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
// Create the PromptOptions from the skill configuration which contain the list of configured skills.
var messageText = stepContext.Options?.ToString() ?? "What skill would you like to call?";
var repromptMessageText = "That was not a valid choice, please select a valid skill.";
var options = new PromptOptions
{
Prompt = MessageFactory.Text(messageText, messageText, InputHints.ExpectingInput),
RetryPrompt = MessageFactory.Text(repromptMessageText, repromptMessageText, InputHints.ExpectingInput),
Choices = _skillsConfig.Skills.Select(skill => new Choice(skill.Value.Id)).ToList()
};
// Prompt the user to select a skill.
return await stepContext.PromptAsync("SkillPrompt", options, cancellationToken);
}
Выберите действие навыка
На следующем шаге основной диалог:
- Сохраняет сведения о навыке, выбранном пользователем.
- Пользователю предлагается выбрать, какое действие навыка он хотел бы использовать, и используется запрос на выбор SkillActionPrompt для получения ответа.
- Он использует вспомогательный метод для получения списка действий, из которых осуществляется выбор.
- Проверяющий элемент управления, связанный с этим запросом, по умолчанию отправит в навык сообщение, если введенные пользователем данные не совпадут с одним из доступных вариантов.
Варианты, предложенные в нашем боте, помогают проверить действия, определенные для этого навыка. В большинстве случаев эти варианты считываются из манифеста навыка и предоставляются пользователю на основе этого списка.
DialogRootBot\Dialogs\MainDialog.cs
// Render a prompt to select the action for the skill.
private async Task<DialogTurnResult> SelectSkillActionStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
// Get the skill info based on the selected skill.
var selectedSkillId = ((FoundChoice)stepContext.Result).Value;
var selectedSkill = _skillsConfig.Skills.FirstOrDefault(s => s.Value.Id == selectedSkillId).Value;
// Remember the skill selected by the user.
stepContext.Values[_selectedSkillKey] = selectedSkill;
// Create the PromptOptions with the actions supported by the selected skill.
var messageText = $"Select an action # to send to **{selectedSkill.Id}** or just type in a message and it will be forwarded to the skill";
var options = new PromptOptions
{
Prompt = MessageFactory.Text(messageText, messageText, InputHints.ExpectingInput),
Choices = GetSkillActions(selectedSkill)
};
// Prompt the user to select a skill action.
return await stepContext.PromptAsync("SkillActionPrompt", options, cancellationToken);
}
// Helper method to create Choice elements for the actions supported by the skill.
private IList<Choice> GetSkillActions(BotFrameworkSkill skill)
{
// Note: the bot would probably render this by reading the skill manifest.
// We are just using hardcoded skill actions here for simplicity.
var choices = new List<Choice>();
switch (skill.Id)
{
case "DialogSkillBot":
choices.Add(new Choice(SkillActionBookFlight));
choices.Add(new Choice(SkillActionBookFlightWithInputParameters));
choices.Add(new Choice(SkillActionGetWeather));
break;
}
return choices;
}
// This validator defaults to Message if the user doesn't select an existing option.
private Task<bool> SkillActionPromptValidator(PromptValidatorContext<FoundChoice> promptContext, CancellationToken cancellationToken)
{
if (!promptContext.Recognized.Succeeded)
{
// Assume the user wants to send a message if an item in the list is not selected.
promptContext.Recognized.Value = new FoundChoice { Value = SkillActionMessage };
}
return Task.FromResult(true);
}
запуск навыка;
На следующем шаге - основной диалог:
- Извлекает сведения о навыке и связанной с ним активности, выбранных пользователем.
- Применяет вспомогательный метод для создания действия, которое будет изначально отправлено в навык.
- Создает параметры диалога, с которыми начнется диалог навыка. Сюда входит и исходное действие для отправки.
- Сохраняет состояние перед вызовом навыка. (Это необходимо, так как ответ навыка может поступить в другой экземпляр потребителя навыка.)
- Запускает диалог навыка, передавая идентификатор вызываемого навыка и параметры для этого вызова.
DialogRootBot\Dialogs\MainDialog.cs
// Starts the SkillDialog based on the user's selections.
private async Task<DialogTurnResult> CallSkillActionStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var selectedSkill = (BotFrameworkSkill)stepContext.Values[_selectedSkillKey];
Activity skillActivity;
switch (selectedSkill.Id)
{
case "DialogSkillBot":
skillActivity = CreateDialogSkillBotActivity(((FoundChoice)stepContext.Result).Value, stepContext.Context);
break;
// We can add other case statements here if we support more than one skill.
default:
throw new Exception($"Unknown target skill id: {selectedSkill.Id}.");
}
// Create the BeginSkillDialogOptions and assign the activity to send.
var skillDialogArgs = new BeginSkillDialogOptions { Activity = skillActivity };
// Save active skill in state.
await _activeSkillProperty.SetAsync(stepContext.Context, selectedSkill, cancellationToken);
// Start the skillDialog instance with the arguments.
return await stepContext.BeginDialogAsync(selectedSkill.Id, skillDialogArgs, cancellationToken);
}
оценка результата выполнения навыка;
На последнем шаге основной диалог:
- Если навык вернул значение, отображает этот результат пользователю.
- Удаляет активный навык из состояния диалога.
- Удаляет активное свойство навыка из состояния беседы.
- Перезапускает сам себя (главный диалог).
DialogRootBot\Dialogs\MainDialog.cs
// The SkillDialog has ended, render the results (if any) and restart MainDialog.
private async Task<DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var activeSkill = await _activeSkillProperty.GetAsync(stepContext.Context, () => null, cancellationToken);
// Check if the skill returned any results and display them.
if (stepContext.Result != null)
{
var message = $"Skill \"{activeSkill.Id}\" invocation complete.";
message += $" Result: {JsonConvert.SerializeObject(stepContext.Result)}";
await stepContext.Context.SendActivityAsync(MessageFactory.Text(message, message, inputHint: InputHints.IgnoringInput), cancellationToken: cancellationToken);
}
// Clear the skill selected by the user.
stepContext.Values[_selectedSkillKey] = null;
// Clear active skill in state.
await _activeSkillProperty.DeleteAsync(stepContext.Context, cancellationToken);
// Restart the main dialog with a different message the second time around.
return await stepContext.ReplaceDialogAsync(InitialDialogId, $"Done with \"{activeSkill.Id}\". \n\n What skill would you like to call?", cancellationToken);
}
Позволить пользователю отменить навык
Основной диалог переопределяет стандартное поведение метода on continue dialog, чтобы пользователь мог отменить текущий навык, если применимо. В методе:
- Если есть активный навык и пользователь отправляет сообщение о прерывании, отмените все диалоги и перезапустите основной диалог с самого начала.
- Затем вызовите базовую реализацию метода on continue dialog, чтобы продолжить обработку текущего хода.
DialogRootBot\Dialogs\MainDialog.cs
protected override async Task<DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default)
{
// This is an example on how to cancel a SkillDialog that is currently in progress from the parent bot.
var activeSkill = await _activeSkillProperty.GetAsync(innerDc.Context, () => null, cancellationToken);
var activity = innerDc.Context.Activity;
if (activeSkill != null && activity.Type == ActivityTypes.Message && activity.Text.Equals("abort", StringComparison.OrdinalIgnoreCase))
{
// Cancel all dialogs when the user says abort.
// The SkillDialog automatically sends an EndOfConversation message to the skill to let the
// skill know that it needs to end its current dialogs, too.
await innerDc.CancelAllDialogsAsync(cancellationToken);
return await innerDc.ReplaceDialogAsync(InitialDialogId, "Canceled! \n\n What skill would you like to call?", cancellationToken);
}
return await base.OnContinueDialogAsync(innerDc, cancellationToken);
}
Логика обработчика действий
Поскольку логика действий для каждого хода обрабатывается основным диалогом, обработчик активности выглядит аналогично тому, как в остальных примерах диалогов.
DialogRootBot\Bots\RootBot.cs
public class RootBot<T> : ActivityHandler
where T : Dialog
private readonly ConversationState _conversationState;
private readonly Dialog _mainDialog;
public RootBot(ConversationState conversationState, T mainDialog)
{
_conversationState = conversationState;
_mainDialog = mainDialog;
}
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
{
if (turnContext.Activity.Type != ActivityTypes.ConversationUpdate)
{
// Run the Dialog with the Activity.
await _mainDialog.RunAsync(turnContext, _conversationState.CreateProperty<DialogState>("DialogState"), cancellationToken);
}
else
{
// Let the base class handle the activity.
await base.OnTurnAsync(turnContext, cancellationToken);
}
// Save any state changes that might have occurred during the turn.
await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
}
Регистрация службы
Для использования диалога навыка нужны те же службы, что и для самого потребителя навыка. Для получения информации о требуемых службах, посмотрите, как реализовать потребителя навыка.
Протестируйте корневого бота
Вы можете протестировать потребитель навыка в эмуляторе, как если бы это был обычный бот; однако необходимо, чтобы и навык, и потребитель навыка работали одновременно. Сведения о настройке навыка см. в статье об использовании диалогов в навыке.
Скачайте и установите последнюю версию Bot Framework Emulator.
- Запустите диалоговый навык бот и корневой диалоговый бот локально на вашем компьютере. Если вам нужны инструкции, ознакомьтесь с
README
для C#, JavaScript, Java, Python. - Примените эмулятор для тестирования бота.
- Когда вы впервые входите в беседу, бот отображает приветственное сообщение и спрашивает, какой навык вы хотите использовать. В этом примере у бота навыков есть всего один навык.
- Выберите DialogSkillBot.
- Затем бот просит выбрать действие для навыка. Выберите BookFlight.
- Ответьте на подсказки.
- После завершения работы навыка, корневой бот отобразит сведения о резервировании и снова попросит вас выбрать навык, который вы хотите вызвать.
- Снова выберите DialogSkillBot и BookFlight.
- Ответьте на первый вопрос, а затем введите "прервать", чтобы остановить выполнение навыка.
- Корневой бот отменяет текущий навык и запрашивает навык, который вы хотите вызвать.
Дополнительные сведения об отладке
Так как трафик между навыками и потребителями навыков проходит проверку подлинности, при отладке таких ботов выполняются дополнительные действия.
- Пользователь навыков и все навыки, используемые им напрямую или косвенно, должны быть активными.
- Если боты работают локально и если у любого из ботов есть идентификатор приложения и пароль, все боты должны иметь действительные идентификаторы и пароли.
- Если боты развернуты, узнайте, как отладить бота из любого канала с помощью devtunnel.
- Если некоторые боты выполняются локально, а некоторые развертываются, см. инструкции по отладке навыка или потребителя навыков.
В противном случае можно отладить потребителя навыка или сам навык так же, как отлаживать других ботов. Дополнительные сведения см. в статье отладка бота и отладка с помощью эмулятора Bot Framework.
Дополнительная информация:
Посмотрите, как реализовать потребителя навыка и как реализовать потребителя навыка в общем.