【问题标题】:Qna and LUIS interrupts dialog before next step can process the inputQna 和 LUIS 在下一步处理输入之前中断对话框
【发布时间】:2019-04-08 10:52:34
【问题描述】:

我已将 QnaMaker 和 LUIS 集成到我的机器人中。我希望用户能够在对话之间提出问题。我已经发现问题在于,在处理用户的输入之前,机器人总是先查看 luis 和 qna。

例如,如果我有“立即开始”和“立即停止”的选择提示, 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;
            }

【问题讨论】:

    标签: c# botframework azure-language-understanding qnamaker


    【解决方案1】:

    你有两个问题,我都会回答。我不知道是否有“最好”的方法来做到这一点——这真的取决于你的代码。您可能还需要结合使用以下两件事。

    在选择提示中使用 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;
        }
    

    在您的 ChoicePrompt 中创建一个验证器:

    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();
    

    如果用户调用“取消”intent,这将冒泡到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 返回与 qnaDispatchKey 匹配的意图 (topDispatch) 时,这就是您触发中断的时候。如果“立即开始”和“立即停止”返回 qnaDispatchKey 作为意图,您可以调整 LUIS 应用以防止这种情况发生。强文本

    【讨论】:

    • 谢谢!这些给了我一些想法。通过调整 LUIS 应用程序,例如删除类似于“现在开始”和“现在停止”的话语?
    • 我的对话框的 ID 似乎没有改变,并且始终是“mainDialog”。我可以就此提出一个问题吗?如果对话 ID 匹配,我喜欢你跳过 LUIS 对话的想法
    • 这是我提出的关于 ID 的问题。谢谢stackoverflow.com/questions/55594028/…
    猜你喜欢
    • 2017-11-24
    • 1970-01-01
    • 1970-01-01
    • 2021-09-25
    • 2017-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多