Luis以天蓝色发布时仅能获得2种意图,但在机器人模拟器中运行得很好

时间:2019-08-23 11:16:18

标签: c# azure botframework luis

我有一个Bot模拟器,其所有LUIS,QnAMaker和Dispatch都可以在Bot模拟器中正常运行。我有很多意图,包括“帮助”,它们都可以在Bot Emulator中完美地工作,但是当在azure和Messenger上发布时,我输入的任何内容都只会返回两个意图,即“取消”和“无意图”。

Bot模拟器 enter image description here

在Azure中发布后在Messenger中 enter image description here

我的LUIS意图 enter image description here

MainDialog :(对话框A和Dialog B与maindialog相同,但是继承了ComponentDialog而不是InterruptDialog)

    public class MainDialog : InterruptDialog
    {
        private const string InitialId = nameof(MainDialog);
        public MainDialog()
            : base(nameof(MainDialog))
        {
            InitialDialogId = InitialId;
            WaterfallStep[] waterfallSteps = new WaterfallStep[]
             {
                 FirstStepAsync,
                 SecondStepAsync,
             };
            AddDialog(new WaterfallDialog(InitialId, waterfallSteps));
            AddDialog(new ChoicePrompt(nameof(ChoicePrompt)));
            AddDialog(new TextPrompt(nameof(TextPrompt)));
            AddDialog(new DialogA());
            AddDialog(new DialogB());
        }

        private async Task<DialogTurnResult> FirstStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            await stepContext.Context.SendActivityAsync("<Start of MainDialog>");
            return await stepContext.PromptAsync(
             nameof(ChoicePrompt),
             new PromptOptions
             {
                 Prompt = MessageFactory.Text($"What do you want to do next?"),
                 Choices = new List<Choice>
                 {
                        new Choice
                        {
                            Value = "Nothing",
                            Synonyms = new List<string>
                            {
                                "nothing",
                            },
                        },
                 },
                 RetryPrompt = MessageFactory.Text($"Please choose one of the options."),
             });
        }

        private static async Task<DialogTurnResult> SecondStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            await stepContext.Context.SendActivityAsync("End of Main");
            return await stepContext.EndDialogAsync();
        }

中断对话框:

    public class InterruptDialog : ComponentDialog
    {
        public InterruptDialog(string id)
            : base(id)
        {
        }

        protected override async Task<DialogTurnResult> OnBeginDialogAsync(DialogContext innerDc, object options, CancellationToken cancellationToken = default(CancellationToken))
        {
            var result = await IsTurnInterruptedAsyncHelpAndCancel(innerDc, cancellationToken);
            if (result != null)
            {
                return result;
            }

            return await base.OnBeginDialogAsync(innerDc, options, cancellationToken);
        }

        protected override async Task<DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default)
        {
            var result = await IsTurnInterruptedAsyncHelpAndCancel(innerDc, cancellationToken);
            if (result != null)
            {
                return result;
            }

            return await base.OnContinueDialogAsync(innerDc, cancellationToken);
        }

        private async Task<DialogTurnResult> IsTurnInterruptedAsyncHelpAndCancel(DialogContext innerDc, CancellationToken cancellationToken)
        {
            var recognizerResult = innerDc.Context.TurnState.Get<RecognizerResult>("recognizerResult");
            string topIntent = string.Empty;

            var luisResult = recognizerResult.Properties["luisResult"] as LuisResult;
            var result = luisResult.ConnectedServiceResult;
            if(result != null)
            {
                topIntent = result.TopScoringIntent.Intent;
            }

            if (topIntent.Equals("MainDialog"))
            {
                if (innerDc.ActiveDialog != null)
                {
                    await innerDc.CancelAllDialogsAsync();
                    await innerDc.BeginDialogAsync(nameof(MainDialog));
                }
                else
                {
                    await innerDc.BeginDialogAsync(nameof(MainDialog));
                }

                return new DialogTurnResult(DialogTurnStatus.Waiting);
            }

            if (topIntent.Equals("DialogB"))
            {
                if (innerDc.ActiveDialog != null)
                {
                    await innerDc.CancelAllDialogsAsync();
                    await innerDc.BeginDialogAsync(nameof(DialogB));
                }
                else
                {
                    await innerDc.BeginDialogAsync(nameof(DialogB));
                }

                return new DialogTurnResult(DialogTurnStatus.Waiting);
            }

            if (topIntent.Equals("DialogA"))
            {
                if (innerDc.ActiveDialog != null)
                {
                    await innerDc.CancelAllDialogsAsync();
                    await innerDc.BeginDialogAsync(nameof(DialogA));
                }
                else
                {
                    await innerDc.BeginDialogAsync(nameof(DialogA));
                }

                return new DialogTurnResult(DialogTurnStatus.Waiting);
            }

            if (topIntent.Equals("Cancel"))
            {
                if (innerDc.ActiveDialog != null)
                {
                    await innerDc.CancelAllDialogsAsync();
                    await innerDc.Context.SendActivityAsync("? Ok. I've cancelled our last activity.");
                }
                else
                {
                    await innerDc.Context.SendActivityAsync("I don't have anything to cancel.");
                }

                return new DialogTurnResult(DialogTurnStatus.Waiting);
            }

            if (topIntent.Equals("Help"))
            {
                await innerDc.Context.SendActivityAsync("Let me help you. ?");

                if (innerDc.ActiveDialog != null)
                {
                    await innerDc.RepromptDialogAsync();
                }

                return new DialogTurnResult(DialogTurnStatus.Waiting);
            }

            return null;
        }
    }
}

Botservice

  public class BotServices : IBotServices
  {
    public BotServices(IConfiguration configuration)
    {
        DispatchService = new LuisRecognizer(new LuisApplication(
        configuration["DispatchLuisAppId"],
        configuration["DispatchLuisAPIKey"],
        $"https://{configuration["DispatchLuisAPIHostName"]}"),
        new LuisPredictionOptions { IncludeAllIntents = true, IncludeInstanceData = true },
        true);

        LuisService = new LuisRecognizer(new LuisApplication(
        configuration["LuisAppId"],
        configuration["LuisAPIKey"],
        $"https://{configuration["LuisAPIHostName"]}"),
        new LuisPredictionOptions { IncludeAllIntents = true, IncludeInstanceData = true },
        true);

        QnaService = new QnAMaker(new QnAMakerEndpoint
        {
            KnowledgeBaseId = configuration["QnAKnowledgebaseId"],
            EndpointKey = configuration["QnAEndpointKey"],
            Host = configuration["QnAEndpointHostName"]
        });
    }

    public LuisRecognizer DispatchService { get; private set; }
    public LuisRecognizer LuisService { get; private set; }
    public QnAMaker QnaService { get; private set; }
}

DialogBot

 public class DialogBot<T> : ActivityHandler
    where T : Dialog
 {
    public readonly IStatePropertyAccessor<DialogState> _dialogAccessor;
    protected readonly Dialog Dialog;
    protected readonly BotState ConversationState;
    protected readonly BotState UserState;
    protected readonly ILogger Logger;
    private readonly IBotServices BotServices;

    private DialogSet Dialogs { get; set; }

    public DialogBot(IBotServices botServices, ConversationState conversationState, UserState userState, T dialog, ILogger<DialogBot<T>> logger)
    {
        ConversationState = conversationState;
        UserState = userState;
        Dialog = dialog;
        Logger = logger;
        BotServices = botServices;
        Dialogs = new DialogSet(conversationState.CreateProperty<DialogState>(nameof(DialogBot<T>)));
        RegisterDialogs(Dialogs);
    }

    public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
    { 
        await base.OnTurnAsync(turnContext, cancellationToken);

        var recognizerResult = turnContext.TurnState.Get<RecognizerResult>("recognizerResult");
        var topIntent = turnContext.TurnState.Get<string>("topIntent");

        var dc = await Dialogs.CreateContextAsync(turnContext, cancellationToken);
        var dialogResult = await dc.ContinueDialogAsync();

        if (!dc.Context.Responded)
        {
            switch (dialogResult.Status)
            {
                case DialogTurnStatus.Empty:
                    await DispatchToTopIntentAsync(turnContext, topIntent, recognizerResult, cancellationToken);
                    break;

                case DialogTurnStatus.Waiting:
                    break;

                case DialogTurnStatus.Complete:
                    await dc.EndDialogAsync();
                    break;

                default:
                    await dc.CancelAllDialogsAsync();
                    break;
            }
        }
    }

    protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
    {
        Logger.LogInformation("Running dialog with Message Activity.");

        string text = string.IsNullOrEmpty(turnContext.Activity.Text) ? string.Empty : turnContext.Activity.Text.ToLower();

        if (!string.IsNullOrEmpty(text))
        {
            var recognizerResult = await BotServices.DispatchService.RecognizeAsync(turnContext, cancellationToken);
            var topIntent = recognizerResult.GetTopScoringIntent();

            var luisResult = recognizerResult.Properties["luisResult"] as LuisResult;
            var result = luisResult.ConnectedServiceResult;
            var topLuisIntent = result.TopScoringIntent.Intent;

            turnContext.TurnState.Add("topIntent", topIntent.intent);
            turnContext.TurnState.Add("recognizerResult", recognizerResult);

        }

        await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>("DialogState"), cancellationToken);
    }

    private void RegisterDialogs(DialogSet dialogs)
    {
        dialogs.Add(new MainDialog());
        dialogs.Add(new DialogA());
        dialogs.Add(new DialogB());
    }

    private async Task DispatchToTopIntentAsync(ITurnContext turnContext, string intent, RecognizerResult recognizerResult, CancellationToken cancellationToken)
    {
        switch (dispatch)
        {
            case "q_thisAzureBotQna":
                await DispatchToQnAMakerAsync(turnContext, cancellationToken);
                break;

            case "l_thisAzureBot-953e":
                await DispatchToLuisModelAsync(turnContext, recognizerResult.Properties["luisResult"] as LuisResult, cancellationToken);
                break;
        }
    }

    private async Task DispatchToQnAMakerAsync(ITurnContext turnContext, CancellationToken cancellationToken)
    {
        if (!string.IsNullOrEmpty(turnContext.Activity.Text))
        {
            var results = await BotServices.QnaService.GetAnswersAsync(turnContext);
            if (results.Any())
            {
                await turnContext.SendActivityAsync(MessageFactory.Text(results.First().Answer), cancellationToken);
            }
            else
            {
                await turnContext.SendActivityAsync(MessageFactory.Text("Sorry, could not find an answer in the Q and A system."), cancellationToken);
            }
        }
    }

    private async Task DispatchToLuisModelAsync(ITurnContext turnContext, LuisResult luisResult, CancellationToken cancellationToken)
    {
        var result = luisResult.ConnectedServiceResult;
        var topIntent = result.TopScoringIntent.Intent;

        switch (topIntent)
        {
            case "Greeting":
                Random r = new Random();
                var x = r.Next(1, 3);

                switch (x)
                {
                    case 1:
                        await turnContext.SendActivityAsync(MessageFactory.Text($"Hi!"));
                        break;

                    case 2:
                        await turnContext.SendActivityAsync(MessageFactory.Text($"Hello!"));
                        break;

                    case 3:
                        await turnContext.SendActivityAsync(MessageFactory.Text($"Hey!"));
                        break;

                    default:
                        break;
                }

                break;

            default:
                break;
        }
    }

    }
 }

启动:

    public class Startup
    {
        public Startup()
        {

        }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<ICredentialProvider, ConfigurationCredentialProvider>();

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();

            services.AddSingleton<IStorage, MemoryStorage>();

            services.AddSingleton<UserState>();

            services.AddSingleton<ConversationState>();

            services.AddSingleton<IBotServices, BotServices>();

            services.AddTransient<MainDialog>();

            services.AddTransient<IBot, DialogBot<MainDialog>>();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }

            app.UseDefaultFiles();
            app.UseStaticFiles();

            app.UseMvc();
        }
    }
}

2 个答案:

答案 0 :(得分:2)

@ user10860492,您是我们最活跃的支持用户之一,我们很乐意为您提供帮助。但是,我觉得我们一直在为您提供问题的答案,这些问题太容易实现了,实际上并没有为您提供对Bot框架或编码的更好理解,这一直在给您带来伤害。 / p>

因此,此答案将与大多数答案有所不同。我将为您提供指导,而不仅仅是一个答案。我希望它不仅可以作为答案,而且可以反复使用。

我会让您开始,我们可以继续进行评论,最终打开StackOverflow聊天以完全解决此问题。


首先,我会回答

  

因此,我设法通过不使用注入的BotService来解决此问题,而只是直接在DialogBot的OnMessageActivityAsync中手动执行luisRecognizer代码

看看您的代码有何不同。您为BotService发布的代码与答案中发布的代码之间有一个非常关键区别。我不会直接给出答案,但是我暗示它与依赖注入或任何高级BotFramework或dotnet无关。

我还将暗示这与您的"No such host is known" error 直接有关。

您遇到的另一个问题是您认为分派错误。我看不到您的代码,但这可能与您的“取消是唯一意图”问题有关,尽管也可能是“未知此类主机”的一部分。

Read here about how Dispatch works

我还建议深入研究how this sample works。这是一个快速入门:

如果您已阅读完毕,应该会看到调度工作如下:

  1. 您的漫游器仅调用Parent Dispatch LUIS应用程序
  2. Parent Dispatch LUIS应用程序查看其意图,以查看是否与它连接的任何子应用程序(LUIS或QnAMaker)匹配
  3. 如果它与LUIS匹配,它将返回该子应用程序的最高意图。如果与QnAMaker匹配,则返回QnAMaker意图和your code should call QnAMaker

我暗中怀疑您的LUIS应用布局不正确。您的家长分派应用程序实际上应该只包含直接指向子级应用程序的意图。您的孩子应用程序应包含其他所有内容。您还应该只需要为LUIS调用“父调度”应用程序,并且仅在“父调度”应用返回QnA意图时才需要调用QnA。


我知道我们处于不同的时区,所以您可能要等到明天早上才能看到此消息-而且本周末我不在工作,但将在太平洋标准时间星期一凌晨8点恢复在线。


响应1:

  

谢谢你我会喜欢的。有时候,我只是通过反复试验而不是真正地学习如何以及为什么来使事情起作用。主要是因为我表现不佳,项目需要快速完成。

太好了!我们都去过那里!我认为整个团队都将采用这种方法。我相信这将为您提供更多帮助,但对于我们在其他人寻求帮助时也开始为他们提供更多概念性答案,这也将是一个很好的途径。

  

我想我现在也明白了(尽管我还没有测试过),我认为关键的区别在于我对代码进行了硬编码,而不是通过配置调用它们。那个botservice与它无关吗?

关闭!没错,botservice / DI与它无关。这不是因为硬编码还是非硬编码。如果您的appsettings.json具有:

"DispatchLuisAPIHostName": "https://southeastasia.api.cognitive.microsoft.com"

...为什么这对Botservice.cs不起作用?仔细查看Botservice.cs注意:我不知道为什么它不能在Emulator中工作并且不能正常运行...除非Emulator进行某种URL解析以防止出现此错误。真奇怪。但是,有时候,模拟器会缓存旧值,因此您需要重新启动它和/或重新启动IIS服务,以确保它使用正确的值。

  

我已更新问题中的代码。我现在只调用dispatch,将identifierrResult保存在turnState中,以供我在其他类的interruptDialog中使用它。先生,现在是正确的方法吗?这是否也意味着,每个用户的回复现在只有1个端点命中?因为我在某处阅读了Dispatt,所以每次Luis调用都会有2个端点命中。

我相信您的代码看起来应该是正确的。很难说,无需测试。它能达到您的期望吗?

您是正确的:使用分派意味着您只需要为每个分派调用支付一个终结点调用的费用(而不是为每个子应用程序分派调用额外的终结点调用,但是如果在获得QnA意图后必须调用QnA,则可以收取额外的QnA通话费用)。 编辑:已确认拥有LUIS团队

答案 1 :(得分:0)

好的,所以我认为问题/错误在配置/应用程序设置之内,而不是botservice。

现在在Messenger中正常检测到了意图 enter image description here

此修复程序对密钥进行了硬编码,而不使用配置:

    namespace SabikoBotV2.Services
{
    public class BotServices : IBotServices
    {
        public BotServices(IConfiguration configuration)
        {
            DispatchService = new LuisRecognizer(new LuisApplication(
            "f2833d51-b9d2-4420xxxxxx",
            "4e17f6cf0574497c85cxxxxxxx",
            $"https://southeastasia.api.cognitive.microsoft.com"),
            new LuisPredictionOptions { IncludeAllIntents = true, IncludeInstanceData = true },
            true);

            LuisService = new LuisRecognizer(new LuisApplication(
            "a17b5589-80a4-4245-bfdf-xxxxxx",
            "4e17f6cf0574497c85c260bxxxxxxx",
            $"https://southeastasia.api.cognitive.microsoft.com"),
            new LuisPredictionOptions { IncludeAllIntents = true, IncludeInstanceData = true },
            true);

            QnaService = new QnAMaker(new QnAMakerEndpoint
            {
                KnowledgeBaseId = configuration["QnAKnowledgebaseId"],
                EndpointKey = configuration["QnAEndpointKey"],
                Host = configuration["QnAEndpointHostName"]
            });
        }

        public LuisRecognizer DispatchService { get; private set; }
        public LuisRecognizer LuisService { get; private set; }
        public QnAMaker QnaService { get; private set; }
    }
}