Partilhar via


Usar uma caixa de diálogo para consumir uma habilidade

APLICA-SE A: SDK v4

Este artigo demonstra como usar uma caixa de diálogo de habilidades em um consumidor de habilidades. A caixa de diálogo de habilidades posta atividades do bot pai para o bot de habilidades e retorna as respostas de habilidade para o usuário. O bot de habilidades acessado por esse consumidor pode lidar com atividades de mensagens e eventos. Para obter um exemplo de manifesto de habilidade e informações sobre como implementá-la, consulte como usar diálogos dentro de uma habilidade.

Para obter informações sobre como usar um bot de habilidade fora das caixas de diálogo, consulte como implementar um consumidor de habilidades.

Nota

Os SDKs JavaScript, C# e Python do Bot Framework continuarão a ser suportados, no entanto, o Java SDK está sendo desativado com suporte final de longo prazo terminando em novembro de 2023.

Os bots existentes construídos com o Java SDK continuarão a funcionar.

Para a criação de novos bots, considere usar o Microsoft Copilot Studio e leia sobre como escolher a solução de copilot certa.

Para obter mais informações, consulte O futuro da criação de bots.

Pré-requisitos

Sobre este exemplo

O exemplo skillDialog de habilidades inclui projetos para dois bots:

  • O bot raiz de diálogo, que usa uma classe de diálogo de habilidade para consumir uma habilidade.
  • O bot de habilidade de diálogo, que usa uma caixa de diálogo para lidar com atividades provenientes de consumidores de habilidades.

Este artigo se concentra em como usar uma classe de diálogo de habilidade em um bot raiz para gerenciar a habilidade, enviar mensagens e atividades de eventos e cancelar a habilidade.

Para obter informações sobre outros aspetos da criação de um consumidor de habilidades, consulte como implementar um consumidor de habilidades.

Para obter informações sobre o bot de habilidade de diálogo, consulte como usar caixas de diálogo dentro de uma habilidade.

Recursos

Para bots implantados, a autenticação de bot para bot requer que cada bot participante tenha uma identidade válida. No entanto, você pode testar habilidades e consumidores de habilidades localmente com o Bot Framework Emulator sem informações de identidade.

Configuração da aplicação

  1. Opcionalmente, adicione as informações de identidade do bot raiz ao arquivo de configuração.
  2. Adicione o ponto de extremidade do host de habilidades (o URL de serviço ou retorno de chamada) ao qual as habilidades devem responder ao consumidor de habilidades.
  3. Adicione uma entrada para cada habilidade que o consumidor usará. Cada entrada inclui:
    • Um ID que o consumidor de habilidades usará para identificar cada habilidade.
    • Opcionalmente, o aplicativo ou ID do cliente do bot de habilidades.
    • O ponto de extremidade de mensagens da habilidade.

Nota

Se a habilidade ou o consumidor de habilidade especificar uma identidade, ambos devem.

DialogRootBot\appsettings.json

Opcionalmente, adicione as informações de identidade do bot raiz e adicione o aplicativo ou ID do cliente para o bot de habilidade de eco à BotFrameworkSkills matriz.

{
  "MicrosoftAppType": "",
  "MicrosoftAppId": "",
  "MicrosoftAppPassword": "",
  "MicrosoftAppTenantId": "",

  "SkillHostEndpoint": "http://localhost:3978/api/skills/",
  "BotFrameworkSkills": [
    {
      "Id": "DialogSkillBot",
      "AppId": "",
      "SkillEndpoint": "http://localhost:39783/api/messages"
    }
  ]
}

Lógica da caixa de diálogo

A caixa de diálogo principal do bot inclui uma caixa de diálogo de habilidade para cada habilidade que esse bot consome. A caixa de diálogo de habilidade gerencia a habilidade através dos vários objetos relacionados à habilidade para você, como o cliente de habilidade e os objetos de fábrica de ID de conversação de habilidade. A caixa de diálogo principal também demonstra como cancelar a habilidade (através da caixa de diálogo de habilidade) com base na entrada do usuário.

A habilidade que este bot usa suporta alguns recursos diferentes. Pode reservar um voo ou obter o clima para uma cidade. Além disso, se ele receber uma mensagem fora de qualquer um desses contextos e um reconhecedor LUIS estiver configurado, ele tentará interpretar a intenção do usuário.

Nota

O Language Understanding (LUIS) será aposentado em 1 de outubro de 2025. A partir de 1 de abril de 2023, não será possível criar novos recursos LUIS. Uma versão mais recente do entendimento de idiomas agora está disponível como parte do Azure AI Language.

O entendimento de linguagem conversacional (CLU), um recurso do Azure AI Language, é a versão atualizada do LUIS. Para obter mais informações sobre o suporte à compreensão de linguagem no Bot Framework SDK, consulte Compreensão de linguagem natural.

O manifesto de habilidade (C#, JavaScript, Java, Python) descreve as ações que a habilidade pode executar, seus parâmetros de entrada e saída e os pontos de extremidade da habilidade. De notar, a habilidade pode lidar com um evento "BookFlight" ou "GetWeather". Ele também pode lidar com mensagens.

A caixa de diálogo principal inclui código para:

A caixa de diálogo principal herda da classe de diálogo do componente. Para obter mais informações sobre caixas de diálogo de componentes, consulte como gerenciar a complexidade da caixa de diálogo.

Inicializar a caixa de diálogo principal

A caixa de diálogo principal inclui diálogos (para gerenciar o fluxo de conversa fora da habilidade) e um diálogo de habilidade (para gerenciar as habilidades). A cascata inclui as seguintes etapas, descritas com mais detalhes nas próximas seções.

  1. Solicite que o usuário selecione a habilidade a ser usada. (O bot raiz consome uma habilidade.)
  2. Solicite que o usuário selecione a ação a ser usada para essa habilidade. (O bot de habilidades define três ações.)
  3. Inicie a habilidade escolhida com uma atividade inicial baseada na ação escolhida.
  4. Quando a habilidade for concluída, exiba os resultados, se houver. Em seguida, reinicie a cachoeira.

DialogRootBot\Diálogos\MainDialog.cs

A MainDialog classe deriva de ComponentDialog. Além do estado da conversa, a caixa de diálogo precisa da identidade do bot raiz e das referências à fábrica de ID de conversação de habilidades, ao cliente HTTP de habilidade e aos objetos de configuração de habilidades.

O construtor de caixa de diálogo verifica seus parâmetros de entrada, adiciona caixas de diálogo de habilidade, adiciona caixas de diálogo de prompt e cascata para gerenciar o fluxo de conversa fora da habilidade e cria um acessador de propriedade para rastrear a habilidade ativa, se houver.

O construtor chama AddSkillDialogs, um método auxiliar, para criar um SkillDialog para cada habilidade incluída no arquivo de configuração, conforme lido do arquivo de configuração em um SkillsConfiguration objeto.

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

Selecionar uma competência

Em sua primeira etapa, a caixa de diálogo principal solicita ao usuário qual habilidade ele gostaria de chamar e usa o prompt de escolha "SkillPrompt" para obter a resposta. (Este bot define apenas uma habilidade.)

DialogRootBot\Diálogos\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);
}

Selecione uma ação de habilidade

Na próxima etapa, a caixa de diálogo principal:

  1. Salva informações sobre a habilidade selecionada pelo usuário.
  2. Solicita ao usuário qual ação de habilidade ele gostaria de usar e usa o prompt de escolha "SkillActionPrompt" para obter a resposta.
    • Ele usa um método auxiliar para obter uma lista de ações para escolher.
    • O validador de prompt associado a esse prompt enviará uma mensagem por padrão à habilidade se a entrada do usuário não corresponder a uma das opções.

As opções incluídas neste bot ajudam a testar as ações definidas para essa habilidade. Mais tipicamente, você leria as opções do manifesto da habilidade e apresentaria opções ao usuário com base nessa lista.

DialogRootBot\Diálogos\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);
}

Comece uma habilidade

Na próxima etapa, a caixa de diálogo principal:

  1. Recupera informações sobre a habilidade e a atividade de habilidade que o usuário selecionou.
  2. Usa um método auxiliar para criar a atividade a ser enviada inicialmente para a habilidade.
  3. Cria as opções de diálogo com as quais iniciar a caixa de diálogo de habilidades. Isso inclui a atividade inicial a ser enviada.
  4. Salva o estado antes de chamar a habilidade. (Isso é necessário, pois a resposta de habilidade pode chegar a uma instância diferente do consumidor de habilidades.)
  5. Inicia a caixa de diálogo de habilidades, passando o ID de habilidade para chamar e as opções com as quais chamá-lo.

DialogRootBot\Diálogos\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);
}

Resumir o resultado da habilidade

Na última etapa, a caixa de diálogo principal:

  1. Se a habilidade retornou um valor, exiba o resultado para o usuário.
  2. Limpa a habilidade ativa do estado da caixa de diálogo.
  3. Remove a propriedade de habilidade ativa do estado de conversação.
  4. Reinicia a si mesmo (a caixa de diálogo principal).

DialogRootBot\Diálogos\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);
}

Permitir que o usuário cancele a habilidade

A caixa de diálogo principal substitui o comportamento padrão do método de diálogo on continue para permitir que o usuário cancele a habilidade atual, se houver. Dentro do método:

  • Se houver uma habilidade ativa e o usuário enviar uma mensagem de "abortar", cancele todas as caixas de diálogo e enfileire a caixa de diálogo principal para reiniciar desde o início.
  • Em seguida, chame a implementação base do método de diálogo on continue para continuar processando o turno atual.

DialogRootBot\Diálogos\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);
}

Lógica do manipulador de atividades

Como a lógica de habilidades para cada turno é manipulada por uma caixa de diálogo principal, o manipulador de atividades se parece muito com outras amostras de diálogo.

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

Registo do serviço

Os serviços necessários para usar um diálogo de habilidades são os mesmos necessários para um consumidor de habilidades em geral. Veja como implementar um consumidor de habilidades para uma discussão sobre os serviços necessários.

Testar o bot raiz

Você pode testar a habilidade do consumidor no emulador como se fosse um bot normal; no entanto, você precisa executar os bots de consumidor de habilidade e habilidade ao mesmo tempo. Veja como usar diálogos dentro de uma habilidade para obter informações sobre como configurar a habilidade.

Baixe e instale o mais recente Bot Framework Emulator.

  1. Execute o bot de habilidade de diálogo e o bot raiz de diálogo localmente em sua máquina. Se precisar de instruções, consulte os exemplos para READMEC#, JavaScript, Java, Python.
  2. Use o emulador para testar o bot.
    • Quando você entra pela primeira vez na conversa, o bot exibe uma mensagem de boas-vindas e pergunta qual habilidade você gostaria de chamar. O bot de habilidade para este exemplo tem apenas uma habilidade.
    • Selecione DialogSkillBot.
  3. Em seguida, o bot pede que você escolha uma ação para a habilidade. Escolha "BookFlight".
    1. Responda às instruções.
    2. A habilidade é concluída e o bot raiz exibe os detalhes da reserva antes de solicitar novamente a habilidade que você gostaria de chamar.
  4. Selecione DialogSkillBot novamente e "BookFlight".
    1. Responda ao primeiro prompt e, em seguida, digite "abortar" para interromper a habilidade.
    2. O bot raiz cancela a habilidade e solicita a habilidade que você gostaria de chamar.

Mais sobre depuração

Como o tráfego entre habilidades e consumidores de habilidades é autenticado, há etapas extras ao depurar esses bots.

  • O consumidor de competências e todas as competências que consome, direta ou indiretamente, devem estar a correr.
  • Se os bots estiverem sendo executados localmente e se algum deles tiver um ID de aplicativo e senha, todos os bots deverão ter IDs e senhas válidas.
  • Se todos os bots estiverem implantados, veja como Depurar um bot de qualquer canal usando devtunnel.
  • Se alguns dos bots estiverem sendo executados localmente e alguns forem implantados, veja como Depurar uma habilidade ou consumidor de habilidades.

Caso contrário, você pode depurar um consumidor de habilidade ou habilidade da mesma forma que depurar outros bots. Para obter mais informações, consulte Depurando um bot e Depurando com o emulador do Bot Framework.

Informações adicionais

Veja como implementar um consumidor de habilidades para saber como implementar um consumidor de habilidades em geral.