Aks*_*ony 6 c# azure-ad-graph-api botframework azure-language-understanding azure-qna-maker
我使用Microsoft bot框架制作了一个Bot,并使用Luis来匹配意图.一些意图将它引导到QNA,并且一些其他意图将它指向图形api.
我的问题是确定是否应该去qna搜索qna中的相关意图或者是否应该使用图形api来获取结果的最佳方法.
截至目前,我使用多个Luis Intents来匹配正确的意图,然后根据所需的意图功能(无论是将其引导到qna对话框还是图形api对话框)重定向它.
`[LuisModel("模型ID","密钥")]
[Serializable]
public class RootDialog : DispatchDialog
{
//this intent directs to graph api dialog
[LuisIntent(DialogMatches.GraphApiIntent)]
public async Task RunGraphapiIntent(IDialogContext context, IActivity activity)
{
UserMessage = (activity as IMessageActivity).Text;
await context.Forward(new GraphApiDailog(), EndDialog, context.Activity, CancellationToken.None);
}
//This intent directs to qna dialog
[LuisIntent(DialogMatches.BlogMatch)]
public async Task RunBlogDialogQna(IDialogContext context, LuisResult result)
{
var userQuestion = (context.Activity as Activity).Text;
(context.Activity as Activity).Text = DialogMatches.BlogMatch;
await context.Forward(new BasicQnAMakerDialog(), this.EndDialog, context.Activity, CancellationToken.None);
}
`
Run Code Online (Sandbox Code Playgroud)
但是这种方法要求我匹配每个意图使用 [LuisIntent("intentstring")]
..因为我可以有50或100的意图,这对50个意图编写50个函数是不实际的.
我找到了一种方法来调用api来从Quickstart中的语句中获取意图:使用C#分析文本
它利用" https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/df67dcdb-c37d-46af-88e1-8b97951ca1c2?subscription-key=&q =打开卧室灯"api用于获取意图.
再次,我的问题是我将如何知道我是否应该将其重定向到QnaDialog或Graph Api Dialog以使用我得到的意图结果来获取数据?
提前致谢
如果您希望进行扩展,您最好编写自己的 Nlp 服务,调用 Luis API 来检测意图。我认为按意图处理对话框重定向的最佳方法是制作类似 IntentDetectorDialog 的东西,其唯一的工作是分析用户话语并转发到与检测到的意图相对应的对话框。
这是我已经使用了一段时间的一个巧妙的方法:
public abstract class BaseDialog : IDialog<BaseResult>
{
public bool DialogForwarded { get; protected set; }
public async Task StartAsync(IDialogContext context)
{
context.Wait(OnMessageReceivedAsync);
}
public async Task OnMessageReceivedAsync(
IDialogContext context,
IAwaitable<IMessageActivity> result)
{
var message = await result;
var dialogFinished = await HandleMessageAsync(context, message);
if (DialogForwarded) return;
if (!dialogFinished)
{
context.Wait(OnMessageReceivedAsync);
}
else
{
context.Done(new DefaultDialogResult());
}
}
protected abstract Task<bool> HandleMessageAsync(IDialogContext context, IMessageActivity message);
protected async Task ForwardToDialog(IDialogContext context,
IMessageActivity message, BaseDialog dialog)
{
DialogForwarded = true;
await context.Forward(dialog, (dialogContext, result) =>
{
// Dialog resume callback
// this method gets called when the child dialog calls context.Done()
DialogForwarded = false;
return Task.CompletedTask;
}, message);
}
}
Run Code Online (Sandbox Code Playgroud)
基本对话框是所有其他对话框的父级,将处理对话框的一般流程。如果对话尚未完成,它将通过调用通知机器人框架context.Wait
,否则将以 结束对话context.Done
。它还将强制所有子对话框实现HandleMessageAsync
返回bool
指示对话框是否已完成的方法。并且还公开了一个可重用的方法ForwardToDialog
,我们IntentDetectorDialog
将用它来处理意图重定向。
public class IntentDetectorDialog : BaseDialog
{
private readonly INlpService _nlpService;
public IntentDetectorDialog(INlpService nlpService)
{
_nlpService = nlpService;
}
protected override async Task<bool> HandleMessageAsync(IDialogContext context, IMessageActivity message)
{
var intentName = await _nlpService.AnalyzeAsync(message.Text);
switch (intentName)
{
case "GoToQnaDialog":
await ForwardToDialog(context, message, new QnaDialog());
break;
case "GoToGraphDialog":
await ForwardToDialog(context, message, new GraphDialog());
break;
}
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
这是IntentRedetectorDialog
: 的儿子,BaseDialog
其唯一的工作是检测意图并转发到相应的对话框。为了使事情更具可扩展性,您可以实现一个 IntentDialogFactory,它可以根据检测到的意图构建对话框。
public class QnaDialog : BaseDialog
{
protected override async Task<bool> HandleMessageAsync(IDialogContext context, IMessageActivity message)
{
if (message.Text == "My name is Javier")
{
await context.PostAsync("What a cool name!");
// question was answered -> end the dialog
return true;
}
else
{
await context.PostAsync("What is your name?");
// wait for the user response
return false;
}
}
}
Run Code Online (Sandbox Code Playgroud)
最后我们还有我们的QnaDialog
: 儿子,BaseDialog
他唯一的工作就是询问用户名并等待响应。
编辑
根据您的评论,在您的 NlpService 中您可以:
public class NlpServiceDispatcher : INlpService
{
public async Task<NlpResult> AnalyzeAsync(string utterance)
{
var qnaResult = await _qnaMakerService.AnalyzeAsync(utterance);
var luisResult = await _luisService.AnalyzeAsync(utterance);
if (qnaResult.ConfidenceThreshold > luisResult.ConfidenceThreshold)
{
return qnaResult;
}
else
{
return luisResult;
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后将其更改IntentDetectorDialog
为:
public class UtteranceAnalyzerDialog : BaseDialog
{
private readonly INlpService _nlpService;
public UtteranceAnalyzerDialog(INlpService nlpService)
{
_nlpService = nlpService;
}
protected override async Task<bool> HandleMessageAsync(IDialogContext context, IMessageActivity message)
{
var nlpResult = await _nlpService.AnalyzeAsync(message.Text);
switch (nlpResult)
{
case QnaMakerResult qnaResult:
await context.PostAsync(qnaResult.Answer);
return true;
case LuisResult luisResult:
var dialog = _dialogFactory.BuildDialogByIntentName(luisResult.IntentName);
await ForwardToDialog(context, message, dialog);
break;
}
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
现在你就拥有了!您不需要在 Luis 和 QnaMaker 中重复话语,您可以使用两者并根据更自信的结果设置您的策略!