我们之前学习过了如何进行状态管理,状态管理的最佳场景就是在和机器人会话的过程中保持参与对话双方的状态,这也利于我们设计更多的组件,并利用状态管理来维持组件的运行状态。我们本节就来介绍一下提供的最为重要的流程管理概念。在了解系统之前,建议大家熟悉一下如下的文章:
场景介绍
当我们开发聊天机器人(无论是通过语音还是文字)时候,最重要的一点是机器人在理解了用户对话的主题之后,如何围绕主题对对话进行跟进。为了更真实的模拟真人对话,在很多场景下并不限制主题范围(当然我们也是可以限制的), 当用户突然改变话题,机器人需要保存当前话题的状态并进入下一个话题的,并在某些时候再恢复之前的话题并继续。举一个例子:用户在进行某项业务操作,例如购买商品,预订酒店等等动作,类似场景要给用户一个引导的过程,添加必要的小组件,例如各种卡片,方便用户进行操作,并管理用户的状态。完成这些场景我们无法通过在代码中一直使用,我们可以利用组件处理这些场景,请记住所有的组件都是有状态的, 必须依赖状态管理。
一睹为快
为了更好的说明是干嘛的以及如何使用,我们先看一个快速的例子: 我在这个例子里是需要使用收集用户的名称,年纪两个信息,并展示给用户。
在开始之前,请先使用文档:创建一个全功能的聊天机器人项目模板,
创建一个机器人模板。创建好了之后,你会拥有一个目录, 该目录里即是我们的项目模板。
在根目录下运行命令:
添加一个新的软件包引用,该包主要定义库相关的类。
在根目录下创建一个新的目录: , 然后在该目录创建一个文件, 内容如下:
usingMicrosoft.Bot.Builder.Dialogs;
usingMicrosoft.Bot.Builder;
namespaceCoreBot.Dialogs;
publicclassMainDialog:ComponentDialog
{
publicMainDialog() :base(nameof(MainDialog))
{
AddDialog(newTextPrompt("get-nick-name", NickNameNotNull));
AddDialog(newNumberPrompt("get-age"));
AddDialog(newWaterfallDialog(nameof(WaterfallDialog),newWaterfallStep[]{
GetNickName,
GetAge,
ShowNickNameAndAge,
}));
InitialDialogId=nameof(WaterfallDialog);
}
publicasyncTaskGetNickName(WaterfallStepContextwaterfallStepContext,CancellationTokencancellationToken)
{
varoptions=newPromptOptions()
{
Prompt=MessageFactory.Text("请输入您的昵称:"),
};
returnawaitwaterfallStepContext.PromptAsync("get-nick-name", options, cancellationToken);
}
publicasyncTaskGetAge(WaterfallStepContextwaterfallStepContext,CancellationTokencancellationToken)
{
varNickName=waterfallStepContext.Result.ToString();
waterfallStepContext.Values["NickName"]=NickName;
varoptions=newPromptOptions()
{
Prompt=MessageFactory.Text("请输入您的年龄:"),
};
returnawaitwaterfallStepContext.PromptAsync("get-age", options, cancellationToken);
}
publicasyncTaskShowNickNameAndAge(WaterfallStepContextwaterfallStepContext,CancellationTokencancellationToken)
{
varAge=waterfallStepContext.Result.ToString();
varNickName=waterfallStepContext.Values["NickName"];
varreply=waterfallStepContext.Context.Activity.CreateReply();
reply.Text=$"您好,您输入的昵称是:, 您输入的年龄是:";
awaitwaterfallStepContext.Context.SendActivityAsync(reply, cancellationToken);
returnawaitwaterfallStepContext.EndDialogAsync(null, cancellationToken);
}
publicasyncTaskNickNameNotNull(PromptValidatorContextpromptContext,CancellationTokencancellationToken)
{
varNickName=promptContext.Recognized.Value;
if(!string.IsNullOrEmpty(NickName))
{
returnawaitTask.FromResult(true);
}
else
{
returnawaitTask.FromResult(false);
}
}
}
这个代码有点长,但是主要是分成如下几个部分:
定义类,并且从类继承: 每一个类都需要从继承,当然你也可以从根类集成,但是这样就少了很多已经实现的方法,因此建议所有的从从这个类继承。这个类有一些已经实现了的方法,例如内置了一个数据集合,用于放置该拥有的多个变量。
实现构造函数,在构造函数里添加需要用于展示的类,例如本例中的类和类,以及我们经常使用的类,请记住是一个非常重要的流程类。
在类里定义会执行的方法,这些方法会被顺序执行。
完善每一个在里定义的顺序执行的方法。
如上这四个部分是定义一个类全部的步骤,步骤很清晰,要做的就是填充代码,仅此而已。
定义了类之后,我们需要应用该类,首先要加入到自动注入依赖的容器里:请打开, 在之前添加一行: , 如下所示:
builder.Services.AddSingleton();
builder.Services.AddTransient();
然后我们需要在中使用这个类。
注意
我们前面讨论如果要保持状态,那么我们必须要添加状态管理的组件,这个部分我们之前一篇文章也详细的讨论过了,如果您还不熟悉,那么请再复习一遍之前讨论的状态管理的部分。
要在中使用, 我们首先要注入状态管理的组件,主要是和的实例,同时为了同步每一个的结束后,的状态,并持久化,我们需要在每一个结束后保存状态。为了达到这些目的,我们给添加如下的代码:
添加两个字段,用于注入状态的引用。
添加方法, 用于保存状态。
构造函数中注入状态管理器和的实例。
定义对于的引用。
privatereadonlyDialog_mainDialog;
privatereadonlyConversationState_conversationState;
privatereadonlyUserState_userState;
publicTestBot(MainDialogmainDialog,ConversationStateconversationState,UserStateuserState)
{
_mainDialog=mainDialog;
_conversationState=conversationState;
_userState=userState;
}
publicoverrideasyncTaskOnTurnAsync(ITurnContextturnContext,CancellationTokencancellationToken=default(CancellationToken))
{
awaitbase.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);
}
最后我们需要启动, 为此我们需要更改方法:
protectedoverrideasyncTaskOnMessageActivityAsync(ITurnContextturnContext,CancellationTokencancellationToken)
{
await_mainDialog.RunAsync(turnContext, _conversationState.CreateProperty(nameof(DialogState)), cancellationToken);
}
注意要引用包:
调用的扩展方法来启动一个。
到这里你可以运行一下你的应用了:
按照之前的文章打开来访问一下地址,即可以看到对话框时如何运作的。
我们先看一个简单的例子,后面再详细的解释一下整个的代码架构和需要注意的点。
领取专属 10元无门槛券
私享最新 技术干货