【问题标题】:Is it possible to use Luis and multiple QnA Maker Knowledgebases in multiprompt dialog?是否可以在多提示对话框中使用 Luis 和多个 QnA Maker 知识库?
【发布时间】:2019-07-30 07:21:29
【问题描述】:

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

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

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

BotBuilder-Samples-master\BotBuilder-Samples-master\experimental\qnamaker-prompting\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-Samples-master\BotBuilder-Samples-master\experimental\qnamaker-prompting\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 方法中提供了端点,则对话框正确启动并且多提示可以工作 - 但我无法弄清楚如何在此设置中使用多个知识库。

【问题讨论】:

  • 是什么阻止您将“QnAKnowledgebaseId1”等放入您的 appsettings 并在新变量名下使用它们构建新的 QnAMakerEndpoint?
  • @JJ_Wailes - 添加其他变量来处理多个 QnAMakerEndpoints 时,我不知道如何在端点变量之间切换。所以说一个意图命中 QnAKnowledgebaseId2,当调用 QueryQnAServiceAsync 方法时,requestUrl 仅基于一个端点变量进行硬编码。我正在努力将端点的标识从 MainDialog 传递到 BeginDialogAsync 方法调用中的 QnADialog。

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


【解决方案1】:

在开始之前阅读整个答案,因为我在中途改变了想法。

不如将QnADialog 传递给IQnAService,而不是IBotServices 的修改版本——其实现是here

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

大致的轮廓是:

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

OP 的一个练习是添加将状态传递到请求的逻辑,以便保持提示状态。我的代码基于不使用提示的this sample。在您使用的示例中,使用了自定义 QnAService,它根据 this code 手动构建请求并传入 QnABotState 以跟踪即时进度。

这应该会让你走上正确的道路。

编辑

使用我上面提供的知识,您可能只需修改QnAService 类(和IQnaService 接口)以将QnAMakerEndpoint 属性更改为集合并处理QueryQnAServiceAsync 内的循环。

【讨论】:

    猜你喜欢
    • 2017-11-24
    • 1970-01-01
    • 2019-12-13
    • 2018-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多