Integrating a LUIS natural language model with your bot using LUISDialog

The LUIS service, part of the Cognitive Services suite, aids you with the task of natural language processing.  In my last post I created a natural language model using Microsoft’s LUIS service and in this post I am going to show you how to hook up the model I created, into a bot created using the Bot Framework and a special type of dialog class, the LUIS Dialog.  If you haven’t got a LUIS model already, go back and work through the last post, it really doesn’t take long.

Update: I have now published a quick video overview of LUIS including how to create your first model.

Get your App and API Subscription keys

Before you can integrate your LUIS model with your bot, or any other app, you will need to get hold of 2 keys – one specific to your LUIS app and another for your LUIS API subscription.  Full details on how you can get your keys can be found at https://www.luis.ai/Help#CreatingKeys, but in essence the basic steps are as follows;

  1. Log into the Azure portal (if you don’t currently have an Azure subscription then you can create an account – the lowest levels of most of the APIs, including LUIS, are free) and create a new Cognitive Services API resource and sets it’s type to LUIS, as shown below.newapiresource
  2. Once you have created your new Cognitive API resource, browse to it and then to Settings -> Keys and you will be presented with your API Subscription keys.  Make a note of them.
  3. Finally, go back to the dashboard for your app on the LUIS.ai web site and click App Settings.  Here you can add the subscription keys you retrieved from the Azure portal in the last step and you can also make a note of your LUIS App Id, as shown below.luisappsettings

Add a LUISDialog class to your bot application

Now that you have your keys, you are ready to start integrating LUIS functionality into your bot.  For this example I am starting with a bot that has been created using the Bot Application template, with all of the default code in place (if you don’t have a bot application and want to following along, then see my 2 part series where I show  you how to create a simple bot).

Add a new folder to your project called Dialogs and create a new class inside of it called DefaultDialog.cs.  Then, with your new class we need to do three things;

  • Add a using statements for Microsoft.Bot.Builder.Dialogs and Microsoft.Bot.Builder.Luis
  • Make your class inherit from LUISDialog<object>
  • Add two attributes to your class, [LuisModel(“{luis_app_id}”, “{subscription_key}”)] and [Serializable], replacing {luis_app_id} and {subscription_key} you sourced earlier in this post.  It is the LuisModel attribute values that tell your new LUISDialog where to find the endpoint for you app.

luisdialog

Adding methods for each LUIS intent on your model

Now that we have our basic LUIS dialog in place and it is hooked up to our model, we now need to add code to handle our LUIS Intents.  Remember, Intents are essentially the endpoints or goals that LUIS will attempt to map incoming phrases from your users to.  For example, on the sample model I am using here, which I created in my last post, I have two Intents, Book Holiday and Cancel Holiday, the first of which might be reached by a user entering, “I would like to book a holiday”.

In your LUIS dialog, each of your Intents will be matched to a different method, using the LuisIntent attribute to identify the name of the intent you want to match and each method allows you to execute code depending on what your user’s wants.  For the sample model I now add three methods, as shown below, to the class to handle my two intents and also the occurrences when LUIS doesn’t find a match.

 

intentmethods

Getting access to your LUIS entities

As you know from building a model in LUIS, the service can intelligently parse user input and extract entities, either pre-built ones like dates and times or custom ones that we define.  One of the parameters that is available to us on each intent method is the LUIS result and through this object we can find details from the LUIS response, including those extracted entities.

In the code example below, I check the Entities property on the LuisResult object that is passed in and see if there are any entities of type “builtin.datetime.date” (the exact type that you should have seen in the raw LUIS response in the LUIS tutorial).  If I find at least one, I take the first and then take the resolution property, which should be a date string, and parse it into a DateTime object.  Finally, I add to the return message to be sent back to the user.

parseintents

Make your new LUIS dialog the root dialog for your bot

You should now have what should, in theory, be a fully working LUIS dialog which can handle your users input to your bot. Now we need to make sure that input to our bot is routed to the dialog.  To do this we change the code in the Post method MessagesController to create an instance of our LUIS dialog and send incoming messages to it.  The code below shows how we create a method called MakeRoot which creates the instance of our LUIS dialog and we call the Conversation.SendAsync method which processes the incoming message and passes it along to our dialog.

messagescontroller

Test your bot with natural language input

Everything should now be in place for you to test your bot with LUIS integration. Go ahead and run your start debugging your bot and send some messages to it using the Bot Framework Channel Emulator tool.  As you can see from my screenshot below, I sent several messages to my bot and got both the standard responses without a date entity and a holiday response where my date entity had been correctly recognised and fed back to me.

emulator

Summary

Let’s recap. If all went well, you should have;

  1. Retrieved / generated your LUIS app and subscription keys
  2. Added a LUIS Dialog to your app and tied it to your LUIS model using your keys
  3. Added a method for each LUIS intent in your model to your dialog, including adding code to parse entities sent in the LUIS response
  4. Modified the MessagesController to route incoming messages to your new dialog

This is just the beginning and now that you have the basics, of both bot development and the LUIS service, you should be able to put some more complex bots together now with relative ease.  Try experimenting with LUIS and bots and I would love to hear how you get on – as always feedback is welcome and appreciated.

16 thoughts on “Integrating a LUIS natural language model with your bot using LUISDialog

    1. Hi Vikram.

      I am out at Microsoft Ignite in Atlanta right now, but I will take a look at this as soon as I can and see if I can spot something to help you out.

      Gary

  1. Hi Gary
    Thank you very much for this article. We have built a chatbot using the qnamaker.ai, and was hoping to integrate LUIS, so that when when there is a good match, an answer from the Knowledge Base is returned. Not sure if this makes sense, and if so, would you have any advice on how we can approach this.

      1. Hi Gary
        Thanks for your guidance, we have been able to build a chatbot using the QnA maker service, see https://smu.sg/testbot based on our FAQs at our admissions site at http://admissions.smu.edu.sg/
        The bot returns an answer when there is a good match of the keywords, but in some cases, it does not answer that well. What we hope to do now, is to enhance its ‘naturalness’. Do you think it is better for us to (1) continue inside QnA maker, by providing alternatives in the knowledge base, and training it, or (2) integrate LUIS to make it work with the current bot? We can do (1) but is not sure how we can do (2). Would you have any advice for us?

        1. Nice test bot! Just tried it and it seems to work well. I would probably suggest that you continue on with the QnA Maker but use LUIS for very specific intents / actions that you would a lot of control over the training for. In fact you can use a LUIS dialog for a number of your top intents, such as “I want to apply” and then fallback to the QnA Dialog if no match is found with LUIS. Does that make sense?

  2. Hi Gary,
    Thanks for the tutorial, it is really helpful.
    I have a question.
    I have qnaDialog already and trying to integrate couple of LUIS intents to the BOT.

    After updating the code in MessageController.cs code, I could run the program and LUIS intents works perfectly fine. But how should I include my qnaDialog in None intent of LUIS?
    I am not sure how can I make qnaDialog to be active when there is none intent detected in LUIS.
    Could you please help me with it?

    What should I write in the None method?

    [LuisIntent(“None”)]
    public async Task None(IDialogContext context, LuisResult result)
    {
    — I would like to call my qnaDialog here
    }

    Thanks,
    Sathish

    1. Hi Gary,

      After making the changes in QnADialog and DefaultDialog.. I get below error message
      “Error CS1503 Argument 2: cannot convert from ‘method group’ to ‘ResumeAfter'”

      I get the error in None intent method in DefaultDialog context.Forward() –
      await context.Forward(qnadialog, AfterQnADialog, messageToForward, CancellationToken.None);

      Couldn’t figure out what am I missing here, could you help?

      private async Task AfterQnADialog(IDialogContext context, IAwaitable result)
      {
      var answerFound = await result;
      // we might want to send a message or take some action if no answer was found (false returned)
      if (!answerFound)
      {
      await context.PostAsync(“I’m not sure what you want.”);
      }
      context.Wait(MessageReceived);
      }

  3. Hi Gary,

    Just a minute after posting my comment above, I got to know about context.Call method() 🙂

    I could now integrate my qnaDialog and defaultdialog like below –

    public async Task None(IDialogContext context, LuisResult result)
    {
    context.Call(new QnADialog(), null);
    }

    Started playing on switching between the Dialogs..

    Cheers,
    Sathish

  4. Hello,

    we are trying to integrate LUIS and QNA maker services in our chatbot – basically asking luis to understand the intent of the user and then based on the response, route it to a appropriate QNA service – we have different types of QNA’s identified. I understand that we can route to the QNA service with a none intent, but we want to see if we can use the intent to identify which QNA service can it go to .
    e.g. LUIS will ask what type of questions you are looking to answer -> 1. Billing 2. Subscription, 3. Service cancellation.

    Based on the user response if the user chooses Billing questions, then we route to the Billing QNA service

    Is this possible? can you provide some guidance on how we would do this?

    1. Sure, you can specify a different knowledge base ID / subscription ID in the constructor of the QnAMakerDialog. Just route to whichever knowledge base you need.

Leave a Reply

Your email address will not be published. Required fields are marked *