c# - 如何不丢失聊天机器人 v4 的对话流?

标签 c# azure botframework chatbot

我使用 Microsoft Bot Framework 创建了一个聊天机器人 v4,它运行良好。我们有两个环境 QA 和 PROD。随着时间的推移,机器人拥有更多的功能和对话框。

我们发现在 PROD(与 QA 具有相同的代码)中它不能正常工作,有时它会从当前对话框退出并返回到 init。

我已经尝试将QnA QA base连接到PROD,看看是否是DB问题,但并没有解决问题。

这是我的代码的一部分

Bot.cs中 在OnTurnAsync

if (activity.Type == ActivityTypes.Message)
{
    // Continue the current dialog
    var dialogResult = await dc.ContinueDialogAsync();

    // examine results from active dialog
    switch (dialogResult.Status)
    {
        case DialogTurnStatus.Empty:
            await NewConversationFlow(turnContext, dc, conversationId, cancellationToken);
            break;

        case DialogTurnStatus.Waiting:
            // The active Dialog is waiting for a response from the user, so do nothing.
            break;

        case DialogTurnStatus.Complete:
            await dc.EndDialogAsync();
            // do things
            await NewConversationFlow(turnContext, dc, conversationId, cancellationToken);
            break;

        default:
            await dc.CancelAllDialogsAsync();
            break;
    }
}

Bot.cs中 在NewConversationFlow

var response = await _services.QnAServices["QnA"].GetAnswersAsync(turnContext, new QnAMakerOptions() { Top = 5, ScoreThreshold = 0.1F });
QueryResult qnaAnswer = GetQnaAnswer(response, 0.60);

await _flowService.ShortDelayWithTypingActionAsync(turnContext);
await turnContext.SendActivityAsync(response.Answer, cancellationToken: cancellationToken);

var flowValue = response.Metadata?.Where(metadata => metadata.Name == "flow").Select(metadata => metadata.Value).FirstOrDefault();
if (!string.IsNullOrEmpty(flowValue))
{
    switch (flowValue)
    {
        case ONE:
        ...
        default:
            await dc.BeginDialogAsync(nameof(OneAnswerDialog));
            break;
        case TWO:
        ...
            await dc.BeginDialogAsync(nameof(TwoAnswerDialog));
            break;
        case SEARCH:
            await dc.BeginDialogAsync(nameof(SearchDialog));
            break;
    }
}

OneAnswerDialog

// Dialog IDs
profileDialog = nameof(OneAnswerDialog);

// Add control flow dialogs
var firstCaseWaterfallSteps = new WaterfallStep[]
{
            GetAnswerAsync,
            SearchStepAsync,
};
AddDialog(new WaterfallDialog(profileDialog, firstCaseWaterfallSteps));
AddDialog(new TextPrompt(ResponsePrompt, ValidateResponseAsync));

通常,当用户在第一个问题(NewConversationFlow 中打印的问题)后插入答案后,它会失败。我不知道它是否在 GetAnswerAsync 中失败,或者在 ValidateResponseAsync 中失败,因为我无法调试 PRD 中的代码。

GetAnswerAsync

return await stepContext.PromptAsync(ResponsePrompt, new PromptOptions());

ValidateResponseAsync

PositiveResponse = false;
var value = promptContext?.Recognized?.Value?.Trim() ?? string.Empty;

if (value != string.Empty)
{
    promptContext.Recognized.Value = value;

    bool userSayYes = false;
    var response = await _services.QnAServices["QnA"].GetAnswersAsync(promptContext.Context, new QnAMakerOptions() { Top = 5, ScoreThreshold = 0.1F });
    if (response != null && response.Length > 0)
    {
        var responses = response.Where(resp => resp.Metadata?.Any(metadata => metadata.Name == "metadata") ?? false).Select(x => x.Metadata);

        PositiveResponse = responses.Any(metadatas => metadatas.Any(metadata => metadata.Value == "more" || metadata.Value == "no"));
        if (!PositiveResponse && responses.Any(metadatas => metadatas.Any(metadata => metadata.Value == "yes")))
        {
            userSayYes = true;
            await _flowService.DelayWithTypingActionAsync(promptContext.Context);
            await promptContext.Context.SendActivityAsync("Can I help you with anything else?", cancellationToken: cancellationToken);
        }
    }

    if (response == null || response.Length <= 0 || (!PositiveResponse && !userSayYes))
    {
        await _flowService.AddOrUpdateQuestion(promptContext.Context.Activity.Conversation.Id, value);
    }
    else if (userSayYes)
    {
        await _flowService.RemoveFlowTypeAndQuestion(promptContext.Context.Activity.Conversation.Id);
    }
}

return true;

(如果 PositiveResponse 为 false,则在后续传递中对话结束并在 Bot.cs 中返回)

出于某种原因,在 PROD 中,机器人会“感到困惑”,并从 GetAnswerAsyncValidateResponseAsync 中退出对话框,并调用 NewConversationFlow

我在另一篇文章中读到,点输入的延迟可能会导致此问题,我已删除它们,但问题仍然存在......

可能是什么问题? 什么会导致对话框过早退出?

提前致谢。

---------------------------------------- 编辑 ----------------- ---------

我已经使用 ngrok 隧道化 PRD 并使用 VS 对其进行调试,在本例中,它正在运行的机器人...

可以是什么?是否有任何 Azure 配置会导致此问题?我已经检查过计费计划,它不是免费的。

---------------------------------------- 编辑 2 ---------------- ----------

我已更新 GetAnswerAsync 以确保机器人进入对话框:

protected async Task<DialogTurnResult> GetAnswerAsync(
                                        WaterfallStepContext stepContext,
                                        CancellationToken cancellationToken)
{
    await stepContext.Context.SendActivityAsync("What do you think? Does it answer your question?");
    await stepContext.PromptAsync(ResponsePrompt, new PromptOptions());
    return new DialogTurnResult(DialogTurnStatus.Waiting);
}

在等待用户提示时,此时似乎退出对话框...

chat with the bot

(“哦,很抱歉听到这个消息!”只是闲聊,这不是瀑布的下一步)

有时,机器人会起作用。这似乎是“随机”的事情。

Working flow

---------------------------------------- 编辑 3 ---------------- ---------- 我仍然遇到这个问题...我尝试从 Azure 中删除所有设置以强制应用程序从文件中读取它。我在 PRD 和 QA 中使用了相同的设置,但什么都没有......有什么想法吗?

最佳答案

在“GetAnswerAsync”文件中,尝试将代码替换为以下代码片段。我通常在 Node 中工作,偶尔我会遇到如果我只返回等待的“发送”/“提示”事件,对话框将“重置”的情况。如果我显式发送 DialogTurnStatus,则流程将按预期移动(即进入以下步骤)。

await stepContext.PromptAsync(ResponsePrompt, new PromptOptions());
return new DialogTurnStatus(DialogTurnStatus.waiting);

如果不是这样,QnA 响应分数是否会太接近 GetQnaAnswer() 中的 0.60 阈值?由于结果是不确定的(意味着分数可能在不同实例之间波动),也许响应并不总是满足阈值?

希望得到帮助!

关于c# - 如何不丢失聊天机器人 v4 的对话流?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59756337/

相关文章:

Angular 客户端需要 Web API 的访问 token

botframework - 如何加载可变的 Microsoft Teams 机器人图标?

c# - AutoMapper 从子级获取属性

c# - Foreach 在 xslt 中带有嵌套字典

Azure Bicep - 其他 IP 限制

c# - 使用 Microsoft Bot Framework 将卡片附件添加到消息

node.js - 如何使用中间件拦截botbuilder sdk v4中的消息?

c# - 找不到与模式匹配的测试程序集 - Visual Studio 测试 - VSTS

c# - 通过描述属性查找枚举值

Azure Front Door Designer - 更新自定义域 - 新 SSL