Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
APLICA-SE A: SDK v4
A coleta de informações por meio da apresentação de perguntas é uma das principais formas de um bot interagir com os usuários. A biblioteca de diálogos fornece recursos internos úteis como classes prompt que tornam fácil fazer perguntas e validar as respostas para que elas correspondam a um tipo de dados específico ou atendam às regras de validação personalizadas.
É possível gerenciar fluxos de conversa lineares e mais complexos usando a biblioteca de diálogos. Em uma interação linear, o bot percorre uma sequência fixa de etapas e a conversa é encerrada. Um diálogo é útil quando o bot precisa coletar informações do usuário.
Este artigo mostra como implementar um fluxo de conversa linear ao criar solicitações e ao chamá-las usando um diálogo em cascata. Para obter exemplos de como escrever seus próprios prompts sem usar a biblioteca de caixas de diálogo, veja o artigo Criar seus próprios prompts para coletar entrada do usuário.
Observação
Para criar agentes com sua escolha de serviços de IA, orquestração e conhecimento, considere usar o SDK do Microsoft 365 Agents. O SDK de Agentes tem suporte para C#, JavaScript ou Python. Você pode saber mais sobre o SDK de Agentes em aka.ms/agents. Se você estiver procurando uma plataforma de agente baseada em SaaS, considere o Microsoft Copilot Studio. Se você tiver um bot existente criado com o SDK do Bot Framework, poderá atualizar o bot para o SDK de Agentes. Você pode examinar as principais alterações e atualizações nas orientações de migração do SDK do Bot Framework para o SDK do Agents. Os tíquetes de suporte para o SDK do Bot Framework não serão mais atendidos a partir de 31 de dezembro de 2025.
Pré-requisitos
- Conhecimento de noções básicas de bot, gerenciamento de estado e biblioteca de diálogos.
- Uma cópia da amostra de solicitações múltiplas em C#, JavaScript, Java e Python.
Sobre este exemplo
A amostra de solicitações múltiplas usa um diálogo em cascata, algumas solicitações e um diálogo do componente para criar uma interação linear que faz uma série de perguntas ao usuário. O código usa um diálogo para percorrer estas etapas:
Etapas | Tipo de prompt |
---|---|
Perguntar ao usuário qual é seu modo de transporte | Prompt de escolha |
Solicite ao usuário seu nome | Prompt de texto |
Perguntar se o usuário deseja fornecer a idade | Prompt de confirmação |
Se a resposta for afirmativa, pergunte a idade | Solicitação de número, com validação para aceitar somente idades superiores a 0 e inferiores a 150 |
Se ele não estiver usando o Microsoft Teams, solicite uma imagem do perfil | Solicitação de anexo, com validação para permitir um anexo ausente |
Pergunte se as informações coletadas estão "ok" | Reutilizar prompt de confirmação |
Por fim, se a resposta for afirmativa, exiba as informações coletadas. Caso contrário, informe ao usuário que suas informações não serão mantidas.
Criar diálogo principal
Para usar as caixas de diálogo, instale o pacote do NuGet, Microsoft.Bot.Builder.Dialogs.
O bot interage com o usuário por meio de UserProfileDialog
. Ao criar a classe DialogBot
do bot, UserProfileDialog
é definido como o diálogo principal. O bot, em seguida, usa um método auxiliar Run
para acessar o diálogo.
Caixas de diálogo\UserProfileDialog.cs
Comece com a criação de UserProfileDialog
que deriva da classe ComponentDialog
e tem sete etapas.
No construtor UserProfileDialog
, crie as etapas de cascata, os prompts e o diálogo de cascata, e adicione-os ao conjunto do diálogo. As solicitações precisam estar no mesmo conjunto de diálogos em que são usadas.
public UserProfileDialog(UserState userState)
: base(nameof(UserProfileDialog))
{
_userProfileAccessor = userState.CreateProperty<UserProfile>("UserProfile");
// This array defines how the Waterfall will execute.
var waterfallSteps = new WaterfallStep[]
{
TransportStepAsync,
NameStepAsync,
NameConfirmStepAsync,
AgeStepAsync,
PictureStepAsync,
SummaryStepAsync,
ConfirmStepAsync,
};
// Add named dialogs to the DialogSet. These names are saved in the dialog state.
AddDialog(new WaterfallDialog(nameof(WaterfallDialog), waterfallSteps));
AddDialog(new TextPrompt(nameof(TextPrompt)));
AddDialog(new NumberPrompt<int>(nameof(NumberPrompt<int>), AgePromptValidatorAsync));
AddDialog(new ChoicePrompt(nameof(ChoicePrompt)));
AddDialog(new ConfirmPrompt(nameof(ConfirmPrompt)));
AddDialog(new AttachmentPrompt(nameof(AttachmentPrompt), PicturePromptValidatorAsync));
// The initial child Dialog to run.
InitialDialogId = nameof(WaterfallDialog);
}
Em seguida, adicione as etapas que a caixa de diálogo usa para solicitar a entrada. Para usar um prompt, chame-o a partir de uma etapa no seu diálogo e recupere o resultado do prompt na próxima etapa usando stepContext.Result
. Nos bastidores, os prompts são uma caixa de diálogo em duas etapas. Primeiro, a solicitação pede pela entrada. Em seguida, ela retorna o valor válido ou recomeça desde o início com uma nova solicitação até receber uma entrada válida.
Você sempre deve ter um retorno de DialogTurnResult
não nulo em uma etapa de cascata. Caso contrário, o diálogo poderá não funcionar conforme planejado. Abaixo, é mostrada a implementação de NameStepAsync
no diálogo em cascata.
private static async Task<DialogTurnResult> NameStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
stepContext.Values["transport"] = ((FoundChoice)stepContext.Result).Value;
return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = MessageFactory.Text("Please enter your name.") }, cancellationToken);
}
Em AgeStepAsync
, especifique uma solicitação de nova tentativa para quando a entrada do usuário falhar na validação, seja porque está em um formato que a solicitação não pode analisar ou porque a entrada não é aprovada pelos critérios de validação. Nesse caso, se nenhuma solicitação de nova tentativa tiver sido fornecida, a solicitação usará o texto da solicitação inicial para solicitar novamente a entrada ao usuário.
private async Task<DialogTurnResult> AgeStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
if ((bool)stepContext.Result)
{
// User said "yes" so we will be prompting for the age.
// WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
var promptOptions = new PromptOptions
{
Prompt = MessageFactory.Text("Please enter your age."),
RetryPrompt = MessageFactory.Text("The value entered must be greater than 0 and less than 150."),
};
return await stepContext.PromptAsync(nameof(NumberPrompt<int>), promptOptions, cancellationToken);
}
else
{
// User said "no" so we will skip the next step. Give -1 as the age.
return await stepContext.NextAsync(-1, cancellationToken);
}
}
UserProfile.cs
O modo de transporte, o nome e a idade do usuário são salvos em uma instância da classe UserProfile
.
public class UserProfile
{
public string Transport { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public Attachment Picture { get; set; }
}
Caixas de diálogo\UserProfileDialog.cs
Na última etapa, verifique o stepContext.Result
retornado pelo diálogo chamado na etapa anterior em cascata. Se o valor retornado for “true”, o acessador do perfil de usuário obtém e atualiza o perfil de usuário. Para obter o perfil de usuário, chame GetAsync
e, em seguida, defina os valores das propriedades userProfile.Transport
, userProfile.Name
, userProfile.Age
e userProfile.Picture
. Por fim, resuma as informações para o usuário antes de chamar EndDialogAsync
, que encerra o diálogo. O fim do diálogo o remove da pilha de diálogo e retorna um resultado opcional ao pai dele. O pai é o método ou diálogo que iniciou o diálogo recém-terminado.
else
{
msg += $" Your profile will not be kept.";
}
await stepContext.Context.SendActivityAsync(MessageFactory.Text(msg), cancellationToken);
// WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is the end.
return await stepContext.EndDialogAsync(cancellationToken: cancellationToken);
}
private async Task<DialogTurnResult> SummaryStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
stepContext.Values["picture"] = ((IList<Attachment>)stepContext.Result)?.FirstOrDefault();
// Get the current profile object from user state.
var userProfile = await _userProfileAccessor.GetAsync(stepContext.Context, () => new UserProfile(), cancellationToken);
userProfile.Transport = (string)stepContext.Values["transport"];
userProfile.Name = (string)stepContext.Values["name"];
userProfile.Age = (int)stepContext.Values["age"];
userProfile.Picture = (Attachment)stepContext.Values["picture"];
var msg = $"I have your mode of transport as {userProfile.Transport} and your name as {userProfile.Name}";
if (userProfile.Age != -1)
{
msg += $" and your age as {userProfile.Age}";
}
msg += ".";
await stepContext.Context.SendActivityAsync(MessageFactory.Text(msg), cancellationToken);
if (userProfile.Picture != null)
{
try
{
await stepContext.Context.SendActivityAsync(MessageFactory.Attachment(userProfile.Picture, "This is your profile picture."), cancellationToken);
}
catch
{
await stepContext.Context.SendActivityAsync(MessageFactory.Text("A profile picture was saved but could not be displayed here."), cancellationToken);
Executar o diálogo
Bots\DialogBot.cs
O manipulador OnMessageActivityAsync
usa o método RunAsync
para iniciar ou continuar o diálogo.
OnTurnAsync
usa os objetos de gerenciamento de estado do bot para persistir quaisquer mudanças de estado no armazenamento. O método ActivityHandler.OnTurnAsync
chama diversos métodos manipuladores de atividades, como OnMessageActivityAsync
. Dessa forma, o estado é salvo após a conclusão do manipulador de mensagens, mas antes da conclusão do turno.
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
{
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);
}
Registrar serviços para o bot
Este bot usa os seguintes serviços:
- Serviços básicos para bot: um provedor de credenciais, um adaptador e a implantação do bot.
- Serviços para gerenciamento de estado: armazenamento, estado do usuário e estado da conversa.
- O diálogo que o bot usará.
Startup.cs
Registre serviços para o bot em Startup
. Esses serviços estão disponíveis para outros blocos do código por meio da injeção de dependência.
{
// 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>();
// Create the Conversation state. (Used by the Dialog system itself.)
services.AddSingleton<ConversationState>();
Observação
O armazenamento de memória é usado somente para fins de teste e não se destina ao uso em produção. Certifique-se de usar um tipo persistente de armazenamento para um bot de produção.
Testar seu bot
- Caso ainda não tenha feito isso, instale o Bot Framework Emulator.
- Execute o exemplo localmente em seu computador.
- Inicie o Emulador, conecte-se ao seu bot e envie mensagens conforme mostrado abaixo.
Informações adicionais
Sobre o estado do diálogo e do bot
Neste bot, dois acessadores de propriedade de estado são definidos:
- Um deles criado dentro do estado de conversa para a propriedade de estado do diálogo. O estado de diálogo monitora onde o usuário está nos diálogos de um conjunto de diálogos e é atualizado pelo contexto de diálogo, por exemplo, quando os métodos de iniciar diálogo ou de continuar diálogo são chamados.
- Um deles criado dentro do estado do usuário para a propriedade de perfil do usuário. O bot usa isso para acompanhar as informações que tem sobre o usuário, e você deve gerenciar explicitamente esse estado no código do diálogo.
Os métodos get e set de um acessador de propriedade de estado obtêm e definem o valor da propriedade no cache do objeto de gerenciamento de estado. O cache é preenchido na primeira vez em que o valor de uma propriedade de estado é solicitado em um turno, mas deve ser mantido explicitamente. Para manter as alterações em ambas as propriedades de estado, é realizada uma chamada ao método salvar alterações, do objeto de gerenciamento de estado correspondente.
Este exemplo atualiza o estado de perfil do usuário a partir do diálogo. Esta prática pode funcionar para alguns bots, mas não funcionará se você desejar reutilizar um diálogo entre bots.
Há várias opções para manter as etapas de diálogo e o estado de bot separados. Por exemplo, após o diálogo reunir todas as informações, você pode:
- Use o método end dialog para fornecer os dados coletados como valor de retorno ao contexto-pai. Este pode ser o manipulador de turnos do bot ou um diálogo ativo anterior na pilha de diálogos e é assim que as classes de solicitação são projetadas.
- Gere uma solicitação para um serviço apropriado. Isso pode funcionar bem se seu bot atuar como um front-end para um serviço maior.
Definição de um método validador de prompt
UserProfileDialog.cs
Abaixo, é apresentado um exemplo de código validador para a definição do método AgePromptValidatorAsync
.
promptContext.Recognized.Value
contém o valor interpretado, que é um inteiro aqui para a solicitação de número.
promptContext.Recognized.Succeeded
indica se o prompt foi capaz de analisar a entrada do usuário ou não. O validador deve retornar o valor “false” para indicar que o valor não foi aceito e o diálogo de solicitação deve realizar uma nova tentativa de solicitação ao usuário; caso contrário, o validador deve retornar o valor “true” para aceitar a entrada e encerrar o diálogo de solicitação. É possível alterar o valor no validador de acordo com o seu cenário.
}
// WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
return await stepContext.PromptAsync(nameof(ConfirmPrompt), new PromptOptions { Prompt = MessageFactory.Text("Is this ok?") }, cancellationToken);
}