Compartir a través de


Creación de un flujo de conversación avanzado con bifurcaciones y bucles

SE APLICA A: SDK versión 4

La biblioteca Dialogs se puede usar para crear flujos de conversación complejos. En este artículo se describe cómo administrar conversaciones complejas que se bifurcan y crean bucles, y cómo pasar argumentos entre las diferentes partes del diálogo.

Nota:

Para crear agentes con su elección de servicios de inteligencia artificial, orquestación y conocimientos, considere la posibilidad de usar el SDK de agentes de Microsoft 365. El SDK de agentes admite C#, JavaScript o Python. Puede obtener más información sobre el SDK de agentes en aka.ms/agents. Si busca una plataforma de agente basada en SaaS, considere Microsoft Copilot Studio. Si tiene un bot existente creado con Bot Framework SDK, puede actualizar el bot al SDK de agentes. Puede revisar los cambios principales y las actualizaciones en la guía de migración del Bot Framework SDK al SDK de Agentes. Las incidencias de soporte técnico del SDK de Bot Framework ya no se atenderán a partir del 31 de diciembre de 2025.

Requisitos previos

Acerca de este ejemplo

Este ejemplo representa un bot que puede registrar usuarios para revisar hasta dos compañías de una lista. El bot utiliza tres componentes de diálogo para administrar el flujo de la conversación. Cada diálogo de componente incluye un diálogo en cascada y las solicitudes necesarias para recopilar los datos de entrada del usuario. En las secciones siguientes se describen estos diálogos de forma más detallada. Usa el estado de la conversación para administrar sus diálogos y utiliza el estado del usuario para guardar información sobre el usuario y qué compañías quiere revisar.

El bot se deriva del controlador de actividad. Al igual que muchos de los bots de ejemplo, da la bienvenida al usuario, usa diálogos para administrar los mensajes del usuario y guarda el estado del usuario y la conversación antes de finalizar el turno.

Para usar diálogos, instale el paquete de NuGet Microsoft.Bot.Builder.Dialogs.

Diagrama de clases para el ejemplo de C#.

Definición del perfil de usuario

El perfil de usuario contendrá la información recopilada por los diálogos, el nombre del usuario, la edad y las compañías seleccionadas para su revisión.

UserProfile.cs

/// <summary>Contains information about a user.</summary>
public class UserProfile
{
    public string Name { get; set; }

    public int Age { get; set; }

    // The list of companies the user wants to review.
    public List<string> CompaniesToReview { get; set; } = new List<string>();

Creación de los diálogos

Este bot contiene tres diálogos:

  • El diálogo principal inicia el proceso general y, después, resume la información recopilada.
  • El diálogo de nivel superior recopila la información del usuario e incluye lógica de bifurcación, en función de la edad del usuario.
  • El cuadro de diálogo para seleccionar revisiones permite al usuario elegir de forma iterativa las compañías que se van a revisar. Para ello, usa la lógica de bucle.

El diálogo principal

El diálogo principal tiene dos pasos:

  1. Iniciar el diálogo de nivel superior.
  2. Recuperar y resumir el perfil de usuario que recopiló el diálogo de nivel superior, guardar esa información en el estado del usuario y señalizar el final del diálogo principal.

Cuadros de diálogo\MainDialog.cs

private async Task<DialogTurnResult> InitialStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    return await stepContext.BeginDialogAsync(nameof(TopLevelDialog), null, cancellationToken);
}

private async Task<DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    var userInfo = (UserProfile)stepContext.Result;

    string status = "You are signed up to review "
        + (userInfo.CompaniesToReview.Count is 0 ? "no companies" : string.Join(" and ", userInfo.CompaniesToReview))
        + ".";

    await stepContext.Context.SendActivityAsync(status);

    var accessor = _userState.CreateProperty<UserProfile>(nameof(UserProfile));
    await accessor.SetAsync(stepContext.Context, userInfo, cancellationToken);

    return await stepContext.EndDialogAsync(null, cancellationToken);
}

El diálogo de nivel superior

El diálogo de nivel superior tiene cuatro pasos:

  1. Preguntar por el nombre del usuario.
  2. Preguntar por la edad del usuario.
  3. Iniciar el cuadro de diálogo de revisión de la selección o continuar con el paso siguiente, en función de la edad del usuario.
  4. Por último, agradecer al usuario su participación y devolver la información recopilada.

En el primer paso se crea un perfil de usuario vacío como parte del estado del diálogo. El diálogo se inicia con un perfil vacío y agrega información al perfil a medida que progresa. Cuando termina, el último paso devuelve la información recopilada.

En el tercer paso (selección inicial), el flujo de conversación se ramifica, en función de la edad del usuario.

Cuadros de diálogo\TopLevelDialog.cs

            stepContext.Values[UserInfo] = new UserProfile();

            var promptOptions = new PromptOptions { Prompt = MessageFactory.Text("Please enter your name.") };

            // Ask the user to enter their name.
            return await stepContext.PromptAsync(nameof(TextPrompt), promptOptions, cancellationToken);
        }

        private async Task<DialogTurnResult> AgeStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            // Set the user's name to what they entered in response to the name prompt.
            var userProfile = (UserProfile)stepContext.Values[UserInfo];
            userProfile.Name = (string)stepContext.Result;

            var promptOptions = new PromptOptions { Prompt = MessageFactory.Text("Please enter your age.") };

            // Ask the user to enter their age.
            return await stepContext.PromptAsync(nameof(NumberPrompt<int>), promptOptions, cancellationToken);
        }

        private async Task<DialogTurnResult> StartSelectionStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            // Set the user's age to what they entered in response to the age prompt.
            var userProfile = (UserProfile)stepContext.Values[UserInfo];
            userProfile.Age = (int)stepContext.Result;

            if (userProfile.Age < 25)
            {
                // If they are too young, skip the review selection dialog, and pass an empty list to the next step.
                await stepContext.Context.SendActivityAsync(
                    MessageFactory.Text("You must be 25 or older to participate."),
                    cancellationToken);
                return await stepContext.NextAsync(new List<string>(), cancellationToken);
            }
            else
            {
                // Otherwise, start the review selection dialog.
                return await stepContext.BeginDialogAsync(nameof(ReviewSelectionDialog), null, cancellationToken);
            }
        }

        private async Task<DialogTurnResult> AcknowledgementStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            // Set the user's company selection to what they entered in the review-selection dialog.
            var userProfile = (UserProfile)stepContext.Values[UserInfo];
            userProfile.CompaniesToReview = stepContext.Result as List<string> ?? new List<string>();

            // Thank them for participating.
            await stepContext.Context.SendActivityAsync(
                MessageFactory.Text($"Thanks for participating, {((UserProfile)stepContext.Values[UserInfo]).Name}."),
                cancellationToken);

            // Exit the dialog, returning the collected user information.
            return await stepContext.EndDialogAsync(stepContext.Values[UserInfo], cancellationToken);
        }
    }
}

El diálogo de selección de revisión

El diálogo de revisión-selección tiene dos pasos:

  1. Pide al usuario que elija una empresa para revisar o seleccione done para terminar.
    • Si el diálogo se inició con información inicial, la información está disponible en la propiedad options del contexto del paso en cascada. El diálogo de selección de revisión puede reiniciarse a sí mismo y usa esto para permitir que el usuario elija más de una empresa para revisar.
    • Si el usuario ya ha seleccionado una empresa para revisar, esta se quita de las opciones disponibles.
    • Se agrega una opción done para que el usuario pueda salir del bucle antes del final.
  2. Repita este diálogo o salga, según corresponda.
    • Si el usuario eligió una empresa para revisar, añádala a su lista.
    • Si el usuario ha elegido dos empresas o elige salir, el diálogo termina y vuelve a la lista recopilada.
    • En caso contrario, reinicia el diálogo inicializándolo con el contenido de su lista.

Cuadros de diálogo\ReviewSelectionDialog.cs

private async Task<DialogTurnResult> SelectionStepAsync(
    WaterfallStepContext stepContext,
    CancellationToken cancellationToken)
{
    // Continue using the same selection list, if any, from the previous iteration of this dialog.
    var list = stepContext.Options as List<string> ?? new List<string>();
    stepContext.Values[CompaniesSelected] = list;

    // Create a prompt message.
    string message;
    if (list.Count is 0)
    {
        message = $"Please choose a company to review, or `{DoneOption}` to finish.";
    }
    else
    {
        message = $"You have selected **{list[0]}**. You can review an additional company, " +
            $"or choose `{DoneOption}` to finish.";
    }

    // Create the list of options to choose from.
    var options = _companyOptions.ToList();
    options.Add(DoneOption);
    if (list.Count > 0)
    {
        options.Remove(list[0]);
    }

    var promptOptions = new PromptOptions
    {
        Prompt = MessageFactory.Text(message),
        RetryPrompt = MessageFactory.Text("Please choose an option from the list."),
        Choices = ChoiceFactory.ToChoices(options),
    };

    // Prompt the user for a choice.
    return await stepContext.PromptAsync(nameof(ChoicePrompt), promptOptions, cancellationToken);
}

private async Task<DialogTurnResult> LoopStepAsync(
    WaterfallStepContext stepContext,
    CancellationToken cancellationToken)
{
    // Retrieve their selection list, the choice they made, and whether they chose to finish.
    var list = stepContext.Values[CompaniesSelected] as List<string>;
    var choice = (FoundChoice)stepContext.Result;
    var done = choice.Value == DoneOption;

    if (!done)
    {
        // If they chose a company, add it to the list.
        list.Add(choice.Value);
    }

    if (done || list.Count >= 2)
    {
        // If they're done, exit and return their list.
        return await stepContext.EndDialogAsync(list, cancellationToken);
    }
    else
    {
        // Otherwise, repeat this dialog, passing in the list from this iteration.
        return await stepContext.ReplaceDialogAsync(InitialDialogId, list, cancellationToken);
    }
}

Ejecución de los diálogos

La clase bot de diálogo amplía el controlador de actividades y contiene la lógica para ejecutar los diálogos. El bot de diálogo y bienvenida amplía el bot de diálogo para dar la bienvenida a un usuario cuando se une a la conversación.

El controlador de turnos del bot repite el flujo de conversación definido por estos tres diálogos. Cuando recibe un mensaje del usuario:

  1. Ejecuta el diálogo principal.
    • Si la pila del diálogo está vacía, se iniciará el diálogo principal.
    • De lo contrario, los diálogos siguen en mitad del proceso y se continuará con el diálogo activo.
  2. Guarda el estado para conservar todas las actualizaciones del usuario, la conversación y el diálogo.

Bots\DialogBot.cs

public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
    await base.OnTurnAsync(turnContext, cancellationToken);

    // Save any state changes that might have occurred during the turn.
    await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
    await UserState.SaveChangesAsync(turnContext, false, cancellationToken);
}

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    Logger.LogInformation("Running dialog with Message Activity.");

    // Run the Dialog with the new message Activity.
    await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
}

Registro de los servicios del bot

Cree y registre los servicios que sean necesarios:

  • Servicios básicos del bot: un adaptador y la implementación del bot.
  • Servicios para administrar el estado: almacenamiento, estado del usuario y estado de la conversación.
  • El diálogo raíz que va a usar el bot.

Startup.cs

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient().AddControllers().AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.MaxDepth = HttpHelper.BotMessageSerializerSettings.MaxDepth;
    });

    // Create the Bot Framework Authentication to be used with the Bot Adapter.
    services.AddSingleton<BotFrameworkAuthentication, ConfigurationBotFrameworkAuthentication>();

    // Create the Bot Adapter with error handling enabled.
    services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();

    // Create the storage we'll be using for User and Conversation state. (Memory is great for testing purposes.)
    services.AddSingleton<IStorage, MemoryStorage>();

    // Create the User state. (Used in this bot's Dialog implementation.)
    services.AddSingleton<UserState>();

Nota:

El almacenamiento en memoria se usa solo con fines de prueba y no está pensado para su uso en producción. Asegúrese de usar un tipo de almacenamiento persistente para un bot de producción.

Probar el bot

  1. Si aún no lo ha hecho, instale Bot Framework Emulator.

  2. Ejecute el ejemplo localmente en la máquina.

  3. Inicie el emulador, conéctese al bot y envíe mensajes como se muestra a continuación.

    Transcripción de ejemplo de una conversación con el bot de diálogo complejo.

Recursos adicionales

Para ver una introducción acerca de cómo implementar un diálogo, consulte el artículo sobre cómo implementar el flujo de conversación secuencial, que utiliza un único diálogo en cascada y unas pocas indicaciones para formular al usuario una serie de preguntas.

La biblioteca de diálogos incluye una validación básica de los mensajes. También puede agregar una validación personalizada. Para más información, consulte el artículo acerca de la recopilación de datos de entrada del usuario mediante una solicitud de diálogo.

Para simplificar el código de diálogo y reutilizarlo en varios bots, puede definir partes de un conjunto de diálogo como una clase independiente. Para más información, consulte Reutilización de diálogos.

Pasos siguientes