是否可以在多提示对话框中使用Luis和多个QnA Maker知识库?

时间:2019-07-26 14:46:52

标签: c# botframework luis qnamaker

我目前正在使用带有Luis的Enterprise Bot模板将意图路由到正确的QnAMaker知识库。 QnAMaker知识库端点存储在bot文件中。我有一个启用多提示的请求:https://github.com/microsoft/BotBuilder-Samples/tree/master/experimental/qnamaker-prompting/csharp_dotnetcore

在提供的示例中,QnAMaker知识库端点位于appsettings.json中,我不知道如何将其他知识库端点添加到appsettings并将意图发送到适当的知识库或让多提示对话框从bot文件中提取端点信息。

在示例中,知识库是在启动时设置的

BotBuilder-样品主版\ BotBuilder-样品主版\实验\ qnamaker提示\ csharp_dotnetcore \ Helpers \ QnAService.cs:

private static (QnAMakerOptions options, QnAMakerEndpoint endpoint) InitQnAService(IConfiguration configuration)
    {
        var options = new QnAMakerOptions
        {
            Top = 3
        };

        var hostname = configuration["QnAEndpointHostName"];
        if (!hostname.StartsWith("https://"))
        {
            hostname = string.Concat("https://", hostname);
        }

        if (!hostname.EndsWith("/qnamaker"))
        {
            hostname = string.Concat(hostname, "/qnamaker");
        }

        var endpoint = new QnAMakerEndpoint
        {
            KnowledgeBaseId = configuration["QnAKnowledgebaseId"],
            EndpointKey = configuration["QnAEndpointKey"],
            Host = hostname
        };

        return (options, endpoint);
    }

BotBuilder-样品主版\ BotBuilder-样品主版\实验\ qnamaker提示\ csharp_dotnetcore \ Startup.cs:

// Helper code that makes the actual HTTP calls to QnA Maker. It is injectable for local unit testing.
        services.AddHttpClient<IQnAService, QnAService>();

这是我对示例代码未做任何修改的设置:

在主对话框中:

else if (intent == Dispatch.Intent.q_RJH_Test_multiprompt)
        {
            _services.QnAServices.TryGetValue("RJH_Test_multiprompt", out var qnaService);      

            if (qnaService == null)
            {
                throw new Exception("The specified QnA Maker Service could not be found in your Bot Services configuration.");
            }
            else
            {
                QnABotState newState = null;
                var query = dc.Context.Activity.Text;
                var qnaResult = await _qnaService.QueryQnAServiceAsync(query, newState);

                if (qnaResult != null && qnaResult.Count() > 0)
                {
                    // start QnAPrompt dialog
                    await dc.BeginDialogAsync(nameof(QnADialog));
                }
                else
                {
                    await _responder.ReplyWith(dc.Context, MainResponses.ResponseIds.Confused);
                }
            }
        }

如果InitQnAService方法中提供了端点,则对话框将正确启动,并且多提示有效-但我无法弄清楚如何在此设置中使用多个知识库。

1 个答案:

答案 0 :(得分:0)

在我半途改变想法之前,请先阅读整个答案。

向您传递IBotServices的修改版本,而不是QnADialog取得IQnAService,该实现的实现是here

您可以删除不需要的LuisRecognizer属性,并将QnAMaker属性设为集合,然后从appsettings读取所有QnA密钥以创建{{1 }}对象,然后将其插入集合中。然后,您需要在QnAMaker中包含something来遍历并查询各种KB,然后处理是否未找到答案。

一个粗略的轮廓是:

  • 创建具有单个属性的QnADialog接口(类似于IBotServices
  • 创建实现List<QnAMakerService> QnAMakerKbs接口的BotServices类。
  • IBotServices类的构造函数中,您应该:
    • 使用来自appSettings.json文件中的密钥,为每个KB创建BotServices对象。
    • QnaMakerService对象添加到QnAMakerService属性中。
  • QnAMakerKbs中替换:
    • Startup.cs
    • 使用
    • services.AddHttpClient<IQnAService, QnAService>();
  • services.AddHttpClient<IBotService, BotService>();的构造函数中,替换为:
    • QnABot
    • 使用
    • IQnAService qnaService
    • IBotService botService调用内的QnADialog的第一个参数替换为: base
  • botService中,将QnADialog.cs的使用替换为IQnAService,并适当地重命名变量。
  • IBotService方法中的逻辑更新为:
ProcessAsync

OP的一项工作是添加用于将状态传递给请求的逻辑,以便保持提示状态。我的代码基于this sample,它不使用提示。在您正在使用的自定义示例中,使用了自定义QnAService,该服务根据this code手动构建了请求,并传递了var query = inputActivity.Text; var index = 0; foreach (var qnaKb in _botServices.QnAMakerKbs) { // Passing in the state won't be supported var qnaResult = await qnaKb.GetAnswersAsync(query, (QnABotState)oldState); var qnaAnswer = qnaResult[0].Answer; // If no answer was found in the KB then go to the next KB, // unless it is the last KB in the collection, then we will // fall through to the default else handling below if (qnaAnswer == "Default no answer found string" && index < _botServices.QnAMakerKbs.Length - 1) { continue; } var prompts = qnaResult[0].Context?.Prompts; if (prompts == null || prompts.Length < 1) { outputActivity = MessageFactory.Text(qnaAnswer); } else { // Set bot state only if prompts are found in QnA result newState = new QnABotState { PreviousQnaId = qnaResult[0].Id, PreviousUserQuery = query }; outputActivity = CardHelper.GetHeroCard(qnaAnswer, prompts); } index++; } 来跟踪提示进度。

这应该使您走上正确的道路。

修改

使用我上面提供的知识,您可能只需修改QnAService类(和QnABotState接口),即可将QnAMakerEndpoint属性更改为一个集合并处理{ {1}}。