具有Luis结果的C#Microsoft Bot Framework定向到QNA Maker和graph API

时间:2018-09-14 18:03:05

标签: c# botframework azure-ad-graph-api luis qnamaker

我使用Microsoft bot框架制作了Bot,并使用Luis进行了意图匹配。一些意图将其定向到QNA,另一些意图将其定向到图形api。

我的问题是识别它应该转到qna来搜索qna中的相关意图的最佳方法,还是应该转到图形api来获取结果的最佳方法。

到目前为止,我已经使用多个Luis Intent进行了匹配以匹配正确的Intent,然后根据所需的Intent功能(将其定向到qna对话框或graph api对话框)进行重定向。

` [LuisModel(“ model id”,“ key”)]

[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);
      }
      `

但是这种方法要求我使用[LuisIntent("intentstring")]来匹配每个意图。由于我可以拥有50或100个意图,因此为50个意图编写50个函数并不现实。

我找到了一种方法来调用api以从Quickstart: Analyze text using C#的话语中提取意图

它利用“ https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/df67dcdb-c37d-46af-88e1-8b97951ca1c2?subscription-key=&q =打开卧室灯” 用于获取意图的api。

我的问题又是什么,我如何知道应该将其重定向到QnaDialog还是Graph Api Dialog,以便使用获得的意图结果来获取数据?

预先感谢

1 个答案:

答案 0 :(得分:2)

如果您希望事情能够扩展,那么编写自己的调用Luis API的Nlp服务来检测意图会更好。我认为通过意图处理对话框重定向的最佳方法是制作类似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);
    }
}

基本对话框是所有其他对话框的父级,将处理该对话框的一般流程。如果对话框尚未完成,它将通过调用context.Wait通知bot框架,否则将以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;
    }
}

这是IntentRedetectorDialog的{​​{1}}:儿子,其唯一的工作就是检测意图并转发到相应的对话框。为了使事情更具可伸缩性,您可以实现一个IntentDialogFactory,它可以根据检测到的意图来构建对话框。

BaseDialog

最后,我们有了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; } } } :也是QnaDialog的儿子,其唯一的工作就是询问用户名并等待响应。

修改

根据您的评论,在NlpService中,您可以:

BaseDialog

然后将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; } } } 更改为:

IntentDetectorDialog

就在那里!您无需在Luis和QnaMaker中重复说话,只需使用两者并根据更加自信的结果来设置策略!