你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
适用于:SDK v4
可以使用对话库来创建复杂的聊天流。 本文介绍如何管理可分支和循环的复杂聊天,以及如何在对话的不同部分之间传递参数。
注意
若要使用所选的 AI 服务、业务流程和知识生成代理,请考虑使用 Microsoft 365 代理 SDK。 代理 SDK 支持 C#、JavaScript 或 Python。 可以在 aka.ms/agents 了解有关代理 SDK 的详细信息。 如果要查找基于 SaaS 的代理平台,请考虑 Microsoft Copilot Studio。 如果现有的机器人是使用 Bot Framework SDK 生成的,则可以将机器人更新到代理 SDK。 可以查看 Bot Framework SDK 到代理 SDK 迁移指南的核心更改和更新。 自 2025 年 12 月 31 日起,Bot Framework SDK 的支持票证将不再提供服务。
先决条件
关于此示例
本示例演示一个可以注册用户,让其针对列表中的最多两家公司发表评论的机器人。 该机器人使用 3 个组件对话来管理对话流。 每个组件对话包含一个瀑布对话,以及收集用户输入所需的任何提示。 这些对话在以下部分详述。 它使用聊天状态管理其对话,并使用用户状态来保存有关用户及其所要评论的公司的信息。
此机器人派生自活动处理程序。 与许多示例机器人一样,它会欢迎用户,使用对话处理来自用户的消息,并在该轮聊天结束之前保存用户和聊天状态。
若要使用对话,请安装 Microsoft.Bot.Builder.Dialogs NuGet 包。
定义用户配置文件
用户配置文件会包含通过对话收集的信息、用户的姓名、年龄,以及选择要评论的公司。
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>();
创建对话
此机器人包含 3 个对话:
- 主对话会启动整个进程,并汇总收集的信息。
- 顶级对话根据用户的年龄收集用户信息并包括分支逻辑。
- 用户可以通过“评论-选择”对话以迭代方式选择要评论的公司。 它使用循环逻辑来这样做。
主对话
主对话有 2 个步骤:
- 启动顶级对话。
- 检索并汇总顶级对话框收集的用户资料,将这些信息保存到用户状态,然后标示主对话的结束。
Dialogs\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);
}
顶层对话
顶级对话有 4 个步骤:
- 询问用户的姓名。
- 询问用户的年龄
- 根据用户的年龄,启动“评论-选择”对话或转到下一步。
- 最后,感谢用户参与并返回收集的信息。
第一步是创建一个空的用户角色,作为会话状态的一部分。 该对话从一个空的个人资料开始,随着交流的进行不断向个人资料中添加信息。 结束时,最后一步会返回收集的信息。
在第三(开始选择)步中,会根据用户的年龄将聊天流分支。
Dialogs\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);
}
}
}
review-selection 对话
review-selection 对话包含两个步骤:
- 请求用户选择要评论的公司,或选择
done
以完成操作。- 如果对话是使用任何初始信息启动的,则可通过瀑布步骤上下文的 options 属性获取该信息。 “评论-选择”对话可以自行重启,并使用它来允许用户选择多个要评论的公司。
- 如果用户已选择要评论的公司,则会从可用的选项中删除该公司。
- 添加了
done
选项,允许用户早退出循环。
- 根据情况重复此对话或退出。
- 如果用户选择了要评论的公司,请将其添加到列表中。
- 如果用户选择了 2 个公司或选择了退出,请结束对话并返回收集的列表。
- 否则,请重启对话,并使用列表的内容将其初始化。
Dialogs\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);
}
}
运行对话
“对话机器人” 类扩展了活动处理程序,包含用于运行对话的逻辑。 “对话和欢迎机器人” 类扩展了对话机器人,在用户加入聊天时也会欢迎用户。
机器人的轮次处理程序重复这 3 个对话定义的对话流。 当它收到来自用户的消息时:
- 它运行主对话。
- 如果对话堆栈为空,这将启动主对话。
- 否则,对话仍处于中间进程,这将继续活动对话。
- 它会保存状态,以持久保存对用户、聊天和对话状态所做的任何更新。
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);
}
注册机器人的服务
根据需要创建并注册服务:
- 机器人的基本服务:适配器和机器人实现。
- 用于管理状态的服务:存储、用户状态和聊天状态。
- 机器人将使用的根对话。
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>();
注意
内存存储仅用于测试,不用于生产。 请务必对生产用机器人使用持久型存储。
测试机器人
安装 Bot Framework Emulator(如果尚未安装)。
在计算机本地运行示例。
按如下所示启动 Emulator,连接到机器人,然后发送消息。
其他资源
有关如何实现对话的介绍,请参阅实现有序的对话流,其中使用了单个瀑布对话和一些提示来向用户提出一系列问题。
“对话”库包含提示的基本验证。 你也可以添加自定义验证。 有关详细信息,请参阅使用对话提示收集用户输入。
若要简化对话代码并将其重复用于多个机器人,可将对话集的某些部分定义为单独的类。 有关详细信息,请参阅重复使用对话。