C# 最佳会话流的Bot框架架构设计建议
我正在使用MicrosoftBotFrameworkV4构建一个更具会话性的聊天机器人 我可以在体系结构中实现什么形式的结构来实现能够处理以下复杂场景的bot 用户:我想在我的租客保险中加一台Mac电脑 {检测意图} 当然,你想买哪台笔记本电脑 用户:2018年的二手专业人士 {从用户话语中提取“pro”和“2018”} 机器人:好吧,添加MacBook Pro 2018每月需要5美元。这对你有用吗 用户:哦,对不起,实际上是2017年 {Bot检测意图并提取实体} 机器人:不用担心,添加你的MacBook Pro 2017仍然是每月5美元,对你有用吗 用户:顺便问一下,纽约的天气怎么样? {Bot检测中断} 机器人:纽约的天气是28摄氏度 机器人:你还想把你的MacBook加入你的租房吗 用户:听起来不错 机器人:太好了,你的MacBook没有保险 顺便说一句,生日快乐 我知道bot框架可以与LUIS集成,以从话语中检测用户意图,但是我如何将LUIS放置在chatbot项目中,以便它在对话框流动时处理所有用户话语 因此,在上述场景中,LUIS可以帮助继续从用户话语中提取实体。核心机器人将展示如何处理LUIS和中断 基本上,不是将LUIS作为中间件添加,而是将其作为“助手”类添加: LUIS helper类将跟踪意图:C# 最佳会话流的Bot框架架构设计建议,c#,botframework,chatbot,azure-language-understanding,C#,Botframework,Chatbot,Azure Language Understanding,我正在使用MicrosoftBotFrameworkV4构建一个更具会话性的聊天机器人 我可以在体系结构中实现什么形式的结构来实现能够处理以下复杂场景的bot 用户:我想在我的租客保险中加一台Mac电脑 {检测意图} 当然,你想买哪台笔记本电脑 用户:2018年的二手专业人士 {从用户话语中提取“pro”和“2018”} 机器人:好吧,添加MacBook Pro 2018每月需要5美元。这对你有用吗 用户:哦,对不起,实际上是2017年 {Bot检测意图并提取实体} 机器人:不用担心,添加你的M
public static class LuisHelper
{
public static async Task<BookingDetails> ExecuteLuisQuery(IConfiguration configuration, ILogger logger, ITurnContext turnContext, CancellationToken cancellationToken)
{
var bookingDetails = new BookingDetails();
try
{
// Create the LUIS settings from configuration.
var luisApplication = new LuisApplication(
configuration["LuisAppId"],
configuration["LuisAPIKey"],
"https://" + configuration["LuisAPIHostName"]
);
var recognizer = new LuisRecognizer(luisApplication);
// The actual call to LUIS
var recognizerResult = await recognizer.RecognizeAsync(turnContext, cancellationToken);
var (intent, score) = recognizerResult.GetTopScoringIntent();
if (intent == "Book_flight")
{
// We need to get the result from the LUIS JSON which at every level returns an array.
bookingDetails.Destination = recognizerResult.Entities["To"]?.FirstOrDefault()?["Airport"]?.FirstOrDefault()?.FirstOrDefault()?.ToString();
bookingDetails.Origin = recognizerResult.Entities["From"]?.FirstOrDefault()?["Airport"]?.FirstOrDefault()?.FirstOrDefault()?.ToString();
// This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop the Time part.
// TIMEX is a format that represents DateTime expressions that include some ambiguity. e.g. missing a Year.
bookingDetails.TravelDate = recognizerResult.Entities["datetime"]?.FirstOrDefault()?["timex"]?.FirstOrDefault()?.ToString().Split('T')[0];
}
}
catch (Exception e)
{
logger.LogWarning($"LUIS Exception: {e.Message} Check your LUIS configuration.");
}
return bookingDetails;
}
}
公共静态类
{
公共静态异步任务ExecuteLisQuery(IConfiguration配置、ILogger记录器、iTunesContext turnContext、CancellationToken CancellationToken)
{
var bookingDetails=新建bookingDetails();
尝试
{
//从配置创建LUIS设置。
var luisApplication=新的luisApplication(
配置[“LUISAPID”],
配置[“LuisAPIKey”],
“https://”+配置[“LuisAPIHostName”]
);
var识别器=新的LuisRecognizer(luisApplication);
//给路易斯的电话
var recognizerResult=等待识别器.RecognizeAsync(turnContext,cancellationToken);
var(intent,score)=recognizerResult.getTopScoringContent();
如果(意图=“预订航班”)
{
//我们需要从LUIS JSON获得结果,它在每一级都返回一个数组。
bookingDetails.Destination=recognizerResult.Entities[“到”]?.FirstOrDefault()?[“机场”]?.FirstOrDefault()?.FirstOrDefault()?.ToString();
bookingDetails.Origin=recognizerResult.Entities[“来自”]?.FirstOrDefault()?[“机场”]?.FirstOrDefault()?.FirstOrDefault()?.ToString();
//这个值将是一个TIMEX。我们只对一个日期感兴趣,所以抓取第一个结果并删除时间部分。
//TIMEX是一种表示日期时间表达式的格式,其中包含一些歧义。例如,缺少一年。
bookingDetails.TravelDate=recognizerResult.Entities[“datetime”]?.FirstOrDefault()?[“timex”]?.FirstOrDefault()?.ToString().Split('T')[0];
}
}
捕获(例外e)
{
LogWarning($“LUIS异常:{e.Message}检查您的LUIS配置。”);
}
退货预订详情;
}
}
在主对话框中,您将这样调用LUIS helper:
private async Task<DialogTurnResult> ActStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
// Call LUIS and gather any potential booking details. (Note the TurnContext has the response to the prompt.)
var bookingDetails = stepContext.Result != null
?
await LuisHelper.ExecuteLuisQuery(Configuration, Logger, stepContext.Context, cancellationToken)
:
new BookingDetails();
// In this sample we only have a single Intent we are concerned with. However, typically a scenario
// will have multiple different Intents each corresponding to starting a different child Dialog.
// Run the BookingDialog giving it whatever details we have from the LUIS call, it will fill out the remainder.
return await stepContext.BeginDialogAsync(nameof(BookingDialog), bookingDetails, cancellationToken);
}
专用异步任务ActStepAsync(WaterAllStepContext stepContext,CancellationToken CancellationToken)
{
//打电话给LUIS,收集任何可能的预订详细信息。(注意TurnContext对提示有响应。)
var bookingDetails=stepContext.Result!=null
?
等待LuisHelper.ExecuteLisQuery(配置、记录器、stepContext.Context、cancellationToken)
:
新预订详情();
//在这个示例中,我们只关注一个目的
//将具有多个不同的意图,每个意图对应于启动不同的子对话框。
//运行BookingDialog,给出我们从LUIS通话中获得的任何详细信息,它将填充剩余部分。
return wait stepContext.BeginDialogAsync(名称(BookingDialog)、bookingDetails、cancellationToken);
}
对于中断,处理这些中断的简单方法是将其创建为组件对话框,然后在所有其他对话框上扩展该对话框:
我建议您仔细查看一下核心机器人,因为它提供了您正在寻找的内容的基本轮廓。对于一个更复杂的例子,Bot框架也有虚拟助手。我对这个用例的方法是将luis作为中间件放在Bot中。在这种情况下,机器人将对话发送到相应的对话保险预订,但是我面临如何利用LUIS或框架在以后的对话中提取实体的挑战,因此当用户说“从2018年开始使用Pro”时,可以检测到并提取实体。我想到的一种方法是创建一个不同的LUIS应用程序,以便检测下一个用户的话语,但对于一个大型企业机器人来说,这并不干净。那么,还有什么其他的方法可以使用呢?请您发布一些代码,以便我们更好地了解问题所在?