Tutorial: Use QnA Maker in your bot to answer questions

You can use the QnA Maker service and a knowledge base to add question-and-answer support to your bot. When you create your knowledge base, you seed it with questions and answers.

In this tutorial, you learn how to:

  • Create a QnA Maker service and knowledge base
  • Add knowledge base information to your .bot file
  • Update your bot to query the knowledge base
  • Re-publish your bot

If you don’t have an Azure subscription, create a free account before you begin.

Prerequisites

  • The bot created in the previous tutorial. We will add a question-and-answer feature to the bot.
  • Some familiarity with QnA Maker is helpful. We will use the QnA Maker portal to create, train, and publish the knowledge base to use with the bot.

You should already have the prerequisites for the previous tutorial:

With msbot 4.3.2 and later, you need Azure CLI version 2.0.54 or later. If you installed the botservice extension, remove it with this command.

az extension remove --name botservice

Sign in to QnA Maker portal

Sign into to the QnA Maker portal with your Azure credentials.

Create a QnA Maker service and knowledge base

We will import an existing knowledge base definition from the QnA Maker sample in the Microsoft/BotBuilder-Samples repo.

  1. Clone or copy the samples repo to your computer.

  2. In the QnA Maker portal, Create a knowledge base.

    1. If necessary, create a QnA service. (You can use an existing QnA Maker service or create a new one for this tutorial.) For more detailed QnA Maker instructions, see Create a QnA Maker service and Create, train, and publish your QnA Maker knowledge base.
    2. Connect your QnA service to your knowledge base.
    3. Name your knowledge base.
    4. To populate your knowledge base, use the BotBuilder-Samples\samples\csharp_dotnetcore\11.qnamaker\CognitiveModels\smartLightFAQ.tsv file from the samples repo.
    5. Click Create your kb to create the knowledge base.
  3. Save and train your knowledge base.

  4. Publish your knowledge base.

    The knowledge base is now ready for your bot to use. Record the knowledge base ID, endpoint key, and hostname. You'll need these for the next step.

Add knowledge base information to your .bot file

Add to your .bot file the information required to access your knowledge base.

  1. Open the .bot file in an editor.

  2. Add a qna element to the services array.

    {
        "type": "qna",
        "name": "<your-knowledge-base-name>",
        "kbId": "<your-knowledge-base-id>",
        "hostname": "<your-qna-service-hostname>",
        "endpointKey": "<your-knowledge-base-endpoint-key>",
        "subscriptionKey": "<your-azure-subscription-key>",
        "id": "<a-unique-id>"
    }
    
    Field Value
    type Must be qna. This indicates that this service entry describes a QnA knowledge base.
    name The name you assigned to your knowledge base.
    kbId The knowledge base ID that the QnA Maker portal generated for you.
    hostname The host URL that the QnA Maker portal generated. Use the complete URL, starting with https:// and ending with /qnamaker.
    endpointKey The endpoint key that the QnA Maker portal generated for you.
    subscriptionKey The ID for the subscription that you used when you created the QnA Maker service in Azure.
    id A unique ID not already used for one of the other services listed in your .bot file, such as "201".
  3. Save your edits.

Update your bot to query the knowledge base

Update your initialization code to load the service information for your knowledge base.

  1. Add the Microsoft.Bot.Builder.AI.QnA NuGet package to your project.
  2. Rename your class that implements IBot to QnaBot.
  3. Rename the class that contains the accessors for your bot to QnaBotAccessors.
  4. In your Startup.cs file, add these namespace references.
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.Bot.Builder.AI.QnA;
    using Microsoft.Bot.Builder.Integration;
    
  5. And, modify the ConfigureServices method to initialize and register the knowledge bases defined in the .bot file. Note that these first few lines were moved from the body of the services.AddBot<QnaBot>(options => call come to before it.
    public void ConfigureServices(IServiceCollection services)
    {
        var secretKey = Configuration.GetSection("botFileSecret")?.Value;
        var botFilePath = Configuration.GetSection("botFilePath")?.Value;
    
        // Loads .bot configuration file and adds a singleton that your Bot can access through dependency injection.
        var botConfig = BotConfiguration.Load(botFilePath ?? @".\jfEchoBot.bot", secretKey);
        services.AddSingleton(sp => botConfig ?? throw new InvalidOperationException($"The .bot config file could not be loaded. ({botConfig})"));
    
        // Initialize the QnA knowledge bases for the bot.
        services.AddSingleton(sp => {
            var qnaServices = new List<QnAMaker>();
            foreach (var qnaService in botConfig.Services.OfType<QnAMakerService>())
            {
                qnaServices.Add(new QnAMaker(qnaService));
            }
            return qnaServices;
        });
    
        services.AddBot<QnaBot>(options =>
        {
            // Retrieve current endpoint.
            // ...
        });
    
        // Create and register state accessors.
        // ...
    }
    
  6. In your QnaBot.cs file, add these namespace references.
    using System.Collections.Generic;
    using Microsoft.Bot.Builder.AI.QnA;
    
  7. Add a _qnaServices property and initialize it in the bot's constructor.
    private readonly List<QnAMaker> _qnaServices;
    
    /// ...
    public QnaBot(QnaBotAccessors accessors, List<QnAMaker> qnaServices, ILoggerFactory loggerFactory)
    {
        // ...
        _qnaServices = qnaServices;
    }
    
  8. Modify the turn handler to query any registered knowledge bases against the user's input. When your bot needs an answer from QnAMaker, call GetAnswersAsync from your bot code to get the appropriate answer based on the current context. If you are accessing your own knowledge base, change the no answers message below to provide useful instructions for your users.
    public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
    {
        if (turnContext.Activity.Type == ActivityTypes.Message)
        {
            foreach(var qnaService in _qnaServices)
            {
                var response = await qnaService.GetAnswersAsync(turnContext);
                if (response != null && response.Length > 0)
                {
                    await turnContext.SendActivityAsync(
                        response[0].Answer,
                        cancellationToken: cancellationToken);
                    return;
                }
            }
    
            var msg = "No QnA Maker answers were found. This example uses a QnA Maker knowledge base that " +
                "focuses on smart light bulbs. Ask the bot questions like 'Why won't it turn on?' or 'I need help'.";
    
            await turnContext.SendActivityAsync(msg, cancellationToken: cancellationToken);
        }
        else
        {
            await turnContext.SendActivityAsync($"{turnContext.Activity.Type} event detected");
        }
    }
    

Test the bot locally

At this point your bot should be able to answer some questions. Run the bot locally and open it in the Emulator.

test qna sample

Re-publish your bot

We can now republish your bot.

Publish your local bot to Azure. This step might take a while.

az bot publish --name <bot-resource-name> --proj-name "<project-file-name>" --resource-group <resource-group-name> --code-dir <directory-path> --verbose --version v4
Option Description
--name The resource name of the bot in Azure.
--proj-name For C#, use the startup project file name (without the .csproj) that needs to be published. For example: EnterpriseBot. For Node.js, use the main entry point for the bot. For example, index.js.
--resource-group Name of resource group.
--code-dir The directory to upload bot code from.

Once this completes with a "Deployment successful!" message, your bot is deployed in Azure.

Test the published bot

After you publish the bot, give Azure a minute or two to update and start the bot.

  1. Use the Emulator to test the production endpoint for your bot, or use the Azure portal to test the bot in Web Chat.

    In either case, you should see the same behavior as you did when you tested it locally.

Clean up resources

If you're not going to continue to use this application, delete the associated resources with the following steps:

  1. In the Azure portal, open the resource group for your bot.
  2. Click Delete resource group to delete the group and all the resources it contains.
  3. In the confirmation pane, enter the resource group name, and click Delete.

Next steps

For information on how to add features to your bot, see the articles in the how-to develop section.