Qna 和 LUIS 在下一步可以处理输入之前中断对话
Qna and LUIS interrupts dialog before next step can process the input
我已将 QnaMaker 和 LUIS 集成到我的机器人中。我希望用户能够在对话之间提问。我已经发现问题是,在处理用户的输入之前,机器人总是先查看 luis 和 qna。
例如,如果我有 "Start now" 和 "Stop now" 的选择提示,
Luis 或 qna 将中断并处理输入,再次重新提示对话框,导致无限循环,永远不会到达下一步。
我认为这是我的糟糕设计。有没有办法让下一步先处理结果?如果它没有识别出结果,luis 和 qna 应该处理输入。
private async Task<bool> IsTurnInterruptedDispatchToQnAMakerAsync(ITurnContext turnContext, string topDispatch, string appName, CancellationToken cancellationToken = default(CancellationToken))
{
var dc = await _dialogs.CreateContextAsync(turnContext);
const string qnaDispatchKey = "q_xxxxxxxx";
if (topDispatch.Equals(qnaDispatchKey))
{
var results = await _services.QnAServices[appName].GetAnswersAsync(turnContext);
if (results.Any())
{
await turnContext.SendActivityAsync(results.First().Answer, cancellationToken: cancellationToken);
}
if (dc.ActiveDialog != null)
{
await dc.RepromptDialogAsync();
}
return true;
}
return false;
}
return false;
}
于 OnTurnAsync()
var interruptedQnaMaker = await IsTurnInterruptedDispatchToQnAMakerAsync(turnContext, topDispatch, QnaConfiguration, cancellationToken);
if (interruptedQnaMaker)
{
await _basicAccessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
await _basicAccessors.UserState.SaveChangesAsync(turnContext, false, cancellationToken);
return;
}
你有两个问题,我会一一回答。我不知道是否有执行此操作的“最佳”方法——这实际上取决于您的代码。您可能还需要结合执行以下两项操作。
在选择提示中使用 LUIS 和 QnA
我的示例展示了如何使用 LUIS 执行此操作,但您可以很容易地在此处替换 QnAMaker。
将您的 BotServices
传递给您的对话框(在 MyBot.cs
的构造函数中):
Dialogs.Add(new MyDialog(services));
注意:根据您执行此操作的位置,您可能可以传递 LuisRecognizer
而不是所有服务。
在MyDialog
的构造函数中使用BotServices
:
public class MyDialog : ComponentDialog
{
private readonly BotServices _services;
public MyDialog(BotServices services) : base(nameof(QuickDialog))
{
[...]
_services = services;
}
在您的选择提示中创建一个验证器:
AddDialog(new ChoicePrompt(nameof(ChoicePrompt), luisValidation));
创建您的验证器,它允许您调整用户的输入并将其设置为其他内容(如 LUIS 意图):
private async Task<bool> LuisValidationAsync(PromptValidatorContext<FoundChoice> promptContext, CancellationToken cancellationToken)
{
// ...Succeeded will only be true for a ChoicePrompt if user input matches a Choice
if (!promptContext.Recognized.Succeeded)
{
// User input doesn't match a choice, so get the LUIS result
var luisResults = await _services.LuisServices["nameOfLuisServiceInBotFile"].RecognizeAsync(promptContext.Context, cancellationToken);
var topScoringIntent = luisResults?.GetTopScoringIntent();
var topIntent = topScoringIntent.Value.intent;
// Save the results and pass them onto the next waterfall step
promptContext.Recognized.Succeeded = true;
promptContext.Recognized.Value = new FoundChoice()
{
Index = 0,
Score = 1,
Value = topIntent
};
// We converted to a valid LUIS result, so return true
return true;
}
// ...Succeeded was true, so return true
return true;
}
处理结果
您可以在几个不同的地方对结果进行操作,而不仅仅是更改用户的输入。例如,在下一步中,您可以:
switch ((stepContext.Result as FoundChoice).Value)
{
case "Reply":
await stepContext.Context.SendActivityAsync("Reply");
break;
case "Cancel":
return await stepContext.EndDialogAsync("Cancel Me");
}
return await stepContext.NextAsync();
如果用户调用“取消”意图,这将冒泡到 MyBot.cs
并且 dialogResult.Result
等于“取消我”。
跳过LUIS/QnA识别
您可以通过两种方式跳过 LUIS 识别:
1。绕过 LUIS 和 QnA 调用
如果您不想检查中断,请设置您希望跳过的条件。你可以使用类似的东西:
var interruptedQnaMaker = false;
if (!<yourCondition>)
{
var interruptedQnaMaker = await IsTurnInterruptedDispatchToQnAMakerAsync(turnContext, topDispatch, QnaConfiguration, cancellationToken);
}
我在 a Node bot 中做了一些非常相似的事情,我在其中完全跳过了某些对话框的 luisRecognizer。对你来说,它可能或多或少是这样的:
var dc = await _dialogs.CreateContextAsync(turnContext);
if (dc.ActiveDialog != null && dc.ActiveDialog.id == "SkipLuisDialog")
{
var interruptedQnaMaker = await IsTurnInterruptedDispatchToQnAMakerAsync(turnContext, topDispatch, QnaConfiguration, cancellationToken);
}
2。调整您的 LUIS 应用
看起来你已经设置好了,当 LUIS returns 一个与 qnaDispatchKey
匹配的意图 (topDispatch
) 时,这就是你触发中断的时间。如果“立即开始”和“立即停止”作为意图返回 qnaDispatchKey
,您可以调整您的 LUIS 应用以防止出现这种情况。strong text
我已将 QnaMaker 和 LUIS 集成到我的机器人中。我希望用户能够在对话之间提问。我已经发现问题是,在处理用户的输入之前,机器人总是先查看 luis 和 qna。
例如,如果我有 "Start now" 和 "Stop now" 的选择提示, Luis 或 qna 将中断并处理输入,再次重新提示对话框,导致无限循环,永远不会到达下一步。
我认为这是我的糟糕设计。有没有办法让下一步先处理结果?如果它没有识别出结果,luis 和 qna 应该处理输入。
private async Task<bool> IsTurnInterruptedDispatchToQnAMakerAsync(ITurnContext turnContext, string topDispatch, string appName, CancellationToken cancellationToken = default(CancellationToken))
{
var dc = await _dialogs.CreateContextAsync(turnContext);
const string qnaDispatchKey = "q_xxxxxxxx";
if (topDispatch.Equals(qnaDispatchKey))
{
var results = await _services.QnAServices[appName].GetAnswersAsync(turnContext);
if (results.Any())
{
await turnContext.SendActivityAsync(results.First().Answer, cancellationToken: cancellationToken);
}
if (dc.ActiveDialog != null)
{
await dc.RepromptDialogAsync();
}
return true;
}
return false;
}
return false;
}
于 OnTurnAsync()
var interruptedQnaMaker = await IsTurnInterruptedDispatchToQnAMakerAsync(turnContext, topDispatch, QnaConfiguration, cancellationToken);
if (interruptedQnaMaker)
{
await _basicAccessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
await _basicAccessors.UserState.SaveChangesAsync(turnContext, false, cancellationToken);
return;
}
你有两个问题,我会一一回答。我不知道是否有执行此操作的“最佳”方法——这实际上取决于您的代码。您可能还需要结合执行以下两项操作。
在选择提示中使用 LUIS 和 QnA
我的示例展示了如何使用 LUIS 执行此操作,但您可以很容易地在此处替换 QnAMaker。
将您的 BotServices
传递给您的对话框(在 MyBot.cs
的构造函数中):
Dialogs.Add(new MyDialog(services));
注意:根据您执行此操作的位置,您可能可以传递 LuisRecognizer
而不是所有服务。
在MyDialog
的构造函数中使用BotServices
:
public class MyDialog : ComponentDialog
{
private readonly BotServices _services;
public MyDialog(BotServices services) : base(nameof(QuickDialog))
{
[...]
_services = services;
}
在您的选择提示中创建一个验证器:
AddDialog(new ChoicePrompt(nameof(ChoicePrompt), luisValidation));
创建您的验证器,它允许您调整用户的输入并将其设置为其他内容(如 LUIS 意图):
private async Task<bool> LuisValidationAsync(PromptValidatorContext<FoundChoice> promptContext, CancellationToken cancellationToken)
{
// ...Succeeded will only be true for a ChoicePrompt if user input matches a Choice
if (!promptContext.Recognized.Succeeded)
{
// User input doesn't match a choice, so get the LUIS result
var luisResults = await _services.LuisServices["nameOfLuisServiceInBotFile"].RecognizeAsync(promptContext.Context, cancellationToken);
var topScoringIntent = luisResults?.GetTopScoringIntent();
var topIntent = topScoringIntent.Value.intent;
// Save the results and pass them onto the next waterfall step
promptContext.Recognized.Succeeded = true;
promptContext.Recognized.Value = new FoundChoice()
{
Index = 0,
Score = 1,
Value = topIntent
};
// We converted to a valid LUIS result, so return true
return true;
}
// ...Succeeded was true, so return true
return true;
}
处理结果
您可以在几个不同的地方对结果进行操作,而不仅仅是更改用户的输入。例如,在下一步中,您可以:
switch ((stepContext.Result as FoundChoice).Value)
{
case "Reply":
await stepContext.Context.SendActivityAsync("Reply");
break;
case "Cancel":
return await stepContext.EndDialogAsync("Cancel Me");
}
return await stepContext.NextAsync();
如果用户调用“取消”意图,这将冒泡到 MyBot.cs
并且 dialogResult.Result
等于“取消我”。
跳过LUIS/QnA识别
您可以通过两种方式跳过 LUIS 识别:
1。绕过 LUIS 和 QnA 调用
如果您不想检查中断,请设置您希望跳过的条件。你可以使用类似的东西:
var interruptedQnaMaker = false;
if (!<yourCondition>)
{
var interruptedQnaMaker = await IsTurnInterruptedDispatchToQnAMakerAsync(turnContext, topDispatch, QnaConfiguration, cancellationToken);
}
我在 a Node bot 中做了一些非常相似的事情,我在其中完全跳过了某些对话框的 luisRecognizer。对你来说,它可能或多或少是这样的:
var dc = await _dialogs.CreateContextAsync(turnContext);
if (dc.ActiveDialog != null && dc.ActiveDialog.id == "SkipLuisDialog")
{
var interruptedQnaMaker = await IsTurnInterruptedDispatchToQnAMakerAsync(turnContext, topDispatch, QnaConfiguration, cancellationToken);
}
2。调整您的 LUIS 应用
看起来你已经设置好了,当 LUIS returns 一个与 qnaDispatchKey
匹配的意图 (topDispatch
) 时,这就是你触发中断的时间。如果“立即开始”和“立即停止”作为意图返回 qnaDispatchKey
,您可以调整您的 LUIS 应用以防止出现这种情况。strong text