使用 C# 在一个机器人中使用多个 QnA 服务
Multiple QnA Service in one Bot using C#
我有 3 个 QnA 服务。我希望它们同时在单个 BOT 中使用。这如何使用 C# 实现。我最初的想法是将 KB ID 和 Sub Key 放入一个数组中(如何实现或者数组可以工作?)。我在 Node.JS 中看到了一些代码,但我不知道如何转换代码在 C# 中。
public class QnaDialog : QnAMakerDialog
{
public QnaDialog() : base(
new QnAMakerService(new QnAMakerAttribute(ConfigurationManager.AppSettings["QnaSubscriptionKey1"],
ConfigurationManager.AppSettings["QnaKnowledgebaseId1"], "Hmm, I wasn't able to find an article about that. Can you try asking in a different way?", 0.5)),
new QnAMakerService(new QnAMakerAttribute(ConfigurationManager.AppSettings["QnaSubscriptionKey2"],
ConfigurationManager.AppSettings["QnaKnowledgebaseId2"], "Hmm, I wasn't able to find an article about that. Can you try asking in a different way?", 0.5)),
new QnAMakerService(new QnAMakerAttribute(ConfigurationManager.AppSettings["QnaSubscriptionKey3"],
ConfigurationManager.AppSettings["QnaKnowledgebaseId4"], "Hmm, I wasn't able to find an article about that. Can you try asking in a different way?", 0.5))
)
{
}
}
通过在属性中提供多种服务,您可以在单个机器人中使用多个 QnAMaker
知识库。
使用来自 Nuget 包 BotBuilder.CognitiveServices
的 QnAMakerDialog
的基本实现是:
[Serializable]
[QnAMaker("QnaSubscriptionKey1", "QnaKnowledgebaseId1", "Hmm, I wasn't able to find an article about that. Can you try asking in a different way?", 0.50, 3)]
[QnAMaker("QnaSubscriptionKey2", "QnaKnowledgebaseId2", "Hmm, I wasn't able to find an article about that. Can you try asking in a different way?", 0.5, 3)]
[QnAMaker("QnaSubscriptionKey3", "QnaKnowledgebaseId3", "Hmm, I wasn't able to find an article about that. Can you try asking in a different way?", 0.5, 3)]
public class RootDialog : QnAMakerDialog
{
}
BUT(是的,有一个 "but")在某些情况下,您可能会在处理消息时遇到异常。由于 QnAMakerDialog
是开源的(来源是 here),您可以很容易地发现问题出在 return 服务调用的实现中,在 MessageReceivedAsync
中:
var sendDefaultMessageAndWait = true;
qnaMakerResults = tasks.FirstOrDefault(x => x.Result.ServiceCfg != null)?.Result;
if (tasks.Count(x => x.Result.Answers?.Count > 0) > 0)
{
var maxValue = tasks.Max(x => x.Result.Answers[0].Score);
qnaMakerResults = tasks.First(x => x.Result.Answers[0].Score == maxValue).Result;
if (qnaMakerResults != null && qnaMakerResults.Answers != null && qnaMakerResults.Answers.Count > 0)
{
if (this.IsConfidentAnswer(qnaMakerResults))
{
await this.RespondFromQnAMakerResultAsync(context, message, qnaMakerResults);
await this.DefaultWaitNextMessageAsync(context, message, qnaMakerResults);
}
else
{
feedbackRecord = new FeedbackRecord { UserId = message.From.Id, UserQuestion = message.Text };
await this.QnAFeedbackStepAsync(context, qnaMakerResults);
}
sendDefaultMessageAndWait = false;
}
}
if (sendDefaultMessageAndWait)
{
await context.PostAsync(qnaMakerResults.ServiceCfg.DefaultMessage);
await this.DefaultWaitNextMessageAsync(context, message, qnaMakerResults);
}
在此代码中,如果您的所有服务都无法回答您的问题(即:如果您的至少一个 QnAMaker KB 没有回答您的问题,则这行代码将会中断问题)
tasks.Max(x => x.Result.Answers[0].Score);
解决方法:您可以通过获取源代码并修复方法来实现自己的 QnAMakerDialog,例如:
public async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
var message = await argument;
if (message != null && !string.IsNullOrEmpty(message.Text))
{
var tasks = this.services.Select(s => s.QueryServiceAsync(message.Text)).ToArray();
await Task.WhenAll(tasks);
if (tasks.Any())
{
var sendDefaultMessageAndWait = true;
qnaMakerResults = tasks.FirstOrDefault(x => x.Result.ServiceCfg != null)?.Result;
var qnaMakerFoundResults = tasks.Where(x => x.Result.Answers.Any()).ToList();
if (qnaMakerFoundResults.Any())
{
var maxValue = qnaMakerFoundResults.Max(x => x.Result.Answers[0].Score);
qnaMakerResults = qnaMakerFoundResults.First(x => x.Result.Answers[0].Score == maxValue).Result;
if (qnaMakerResults?.Answers != null && qnaMakerResults.Answers.Count > 0)
{
if (this.IsConfidentAnswer(qnaMakerResults))
{
await this.RespondFromQnAMakerResultAsync(context, message, qnaMakerResults);
await this.DefaultWaitNextMessageAsync(context, message, qnaMakerResults);
}
else
{
feedbackRecord = new FeedbackRecord { UserId = message.From.Id, UserQuestion = message.Text };
await this.QnAFeedbackStepAsync(context, qnaMakerResults);
}
sendDefaultMessageAndWait = false;
}
}
if (sendDefaultMessageAndWait)
{
await context.PostAsync(qnaMakerResults.ServiceCfg.DefaultMessage);
await this.DefaultWaitNextMessageAsync(context, message, qnaMakerResults);
}
}
}
}
我有 3 个 QnA 服务。我希望它们同时在单个 BOT 中使用。这如何使用 C# 实现。我最初的想法是将 KB ID 和 Sub Key 放入一个数组中(如何实现或者数组可以工作?)。我在 Node.JS 中看到了一些代码,但我不知道如何转换代码在 C# 中。
public class QnaDialog : QnAMakerDialog
{
public QnaDialog() : base(
new QnAMakerService(new QnAMakerAttribute(ConfigurationManager.AppSettings["QnaSubscriptionKey1"],
ConfigurationManager.AppSettings["QnaKnowledgebaseId1"], "Hmm, I wasn't able to find an article about that. Can you try asking in a different way?", 0.5)),
new QnAMakerService(new QnAMakerAttribute(ConfigurationManager.AppSettings["QnaSubscriptionKey2"],
ConfigurationManager.AppSettings["QnaKnowledgebaseId2"], "Hmm, I wasn't able to find an article about that. Can you try asking in a different way?", 0.5)),
new QnAMakerService(new QnAMakerAttribute(ConfigurationManager.AppSettings["QnaSubscriptionKey3"],
ConfigurationManager.AppSettings["QnaKnowledgebaseId4"], "Hmm, I wasn't able to find an article about that. Can you try asking in a different way?", 0.5))
)
{
}
}
通过在属性中提供多种服务,您可以在单个机器人中使用多个 QnAMaker
知识库。
使用来自 Nuget 包 BotBuilder.CognitiveServices
的 QnAMakerDialog
的基本实现是:
[Serializable]
[QnAMaker("QnaSubscriptionKey1", "QnaKnowledgebaseId1", "Hmm, I wasn't able to find an article about that. Can you try asking in a different way?", 0.50, 3)]
[QnAMaker("QnaSubscriptionKey2", "QnaKnowledgebaseId2", "Hmm, I wasn't able to find an article about that. Can you try asking in a different way?", 0.5, 3)]
[QnAMaker("QnaSubscriptionKey3", "QnaKnowledgebaseId3", "Hmm, I wasn't able to find an article about that. Can you try asking in a different way?", 0.5, 3)]
public class RootDialog : QnAMakerDialog
{
}
BUT(是的,有一个 "but")在某些情况下,您可能会在处理消息时遇到异常。由于 QnAMakerDialog
是开源的(来源是 here),您可以很容易地发现问题出在 return 服务调用的实现中,在 MessageReceivedAsync
中:
var sendDefaultMessageAndWait = true;
qnaMakerResults = tasks.FirstOrDefault(x => x.Result.ServiceCfg != null)?.Result;
if (tasks.Count(x => x.Result.Answers?.Count > 0) > 0)
{
var maxValue = tasks.Max(x => x.Result.Answers[0].Score);
qnaMakerResults = tasks.First(x => x.Result.Answers[0].Score == maxValue).Result;
if (qnaMakerResults != null && qnaMakerResults.Answers != null && qnaMakerResults.Answers.Count > 0)
{
if (this.IsConfidentAnswer(qnaMakerResults))
{
await this.RespondFromQnAMakerResultAsync(context, message, qnaMakerResults);
await this.DefaultWaitNextMessageAsync(context, message, qnaMakerResults);
}
else
{
feedbackRecord = new FeedbackRecord { UserId = message.From.Id, UserQuestion = message.Text };
await this.QnAFeedbackStepAsync(context, qnaMakerResults);
}
sendDefaultMessageAndWait = false;
}
}
if (sendDefaultMessageAndWait)
{
await context.PostAsync(qnaMakerResults.ServiceCfg.DefaultMessage);
await this.DefaultWaitNextMessageAsync(context, message, qnaMakerResults);
}
在此代码中,如果您的所有服务都无法回答您的问题(即:如果您的至少一个 QnAMaker KB 没有回答您的问题,则这行代码将会中断问题)
tasks.Max(x => x.Result.Answers[0].Score);
解决方法:您可以通过获取源代码并修复方法来实现自己的 QnAMakerDialog,例如:
public async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
var message = await argument;
if (message != null && !string.IsNullOrEmpty(message.Text))
{
var tasks = this.services.Select(s => s.QueryServiceAsync(message.Text)).ToArray();
await Task.WhenAll(tasks);
if (tasks.Any())
{
var sendDefaultMessageAndWait = true;
qnaMakerResults = tasks.FirstOrDefault(x => x.Result.ServiceCfg != null)?.Result;
var qnaMakerFoundResults = tasks.Where(x => x.Result.Answers.Any()).ToList();
if (qnaMakerFoundResults.Any())
{
var maxValue = qnaMakerFoundResults.Max(x => x.Result.Answers[0].Score);
qnaMakerResults = qnaMakerFoundResults.First(x => x.Result.Answers[0].Score == maxValue).Result;
if (qnaMakerResults?.Answers != null && qnaMakerResults.Answers.Count > 0)
{
if (this.IsConfidentAnswer(qnaMakerResults))
{
await this.RespondFromQnAMakerResultAsync(context, message, qnaMakerResults);
await this.DefaultWaitNextMessageAsync(context, message, qnaMakerResults);
}
else
{
feedbackRecord = new FeedbackRecord { UserId = message.From.Id, UserQuestion = message.Text };
await this.QnAFeedbackStepAsync(context, qnaMakerResults);
}
sendDefaultMessageAndWait = false;
}
}
if (sendDefaultMessageAndWait)
{
await context.PostAsync(qnaMakerResults.ServiceCfg.DefaultMessage);
await this.DefaultWaitNextMessageAsync(context, message, qnaMakerResults);
}
}
}
}