Use QnA Maker to answer questions

Note

This topic is for the latest release of the SDK (v4). You can find content for the older version of the SDK (v3) here.

You can use QnA Maker service to add question and answer support to your bot. One of the basic requirements in creating your own QnA Maker service is to seed it with questions and answers. In many cases, the questions and answers already exist in content like FAQs or other documentation. Other times you would like to customize your answers to questions in a more natural, conversational way.

In this topic we will create a knowledge base and use it in a bot.

Prerequisites

Create a QnA Maker service and publish a knowledge base

  1. First, you'll need to create a QnA Maker service.
  2. Next, you'll create a knowledge base using the smartLightFAQ.tsv file located in the CognitiveModels folder of the project. The steps to create, train, and publish your QnA Maker knowledge base are listed in the QnA Maker documentation. As you follow these steps, name your KB qna, and use the smartLightFAQ.tsv file to populate your KB.

Obtain values to connect to your connect your bot to the knowledge base

  1. In the QnA Maker site, select your knowledge base.
  2. With your knowledge base open, select the Settings. Record the value shown for service name as <your_kb_name>
  3. Scroll down to find Deployment details and record the following values:
    • POST /knowledgebases/<your_knowledge_base_id>/generateAnswer
    • Host: <your_hostname>/qnamaker
    • Authorization: EndpointKey <your_endpoint_key>

Update the .bot file

First, add the information required to access your knowledge base including hostname, endpoint key and knowledge base Id (KbId) into the qnamaker.bot. These are the values you saved from the Settings of your knowledge base in QnA Maker.

{
  "name": "qnamaker",
  "services": [
    {
      "type": "endpoint",
      "name": "development",
      "endpoint": "http://localhost:3978/api/messages",
      "appId": "",
      "appPassword": ""
      "id": "25",
    
    },
    {
      "type": "qna",
      "name": "QnABot",
      "KbId": "<YOUR_KNOWLEDGE_BASE_ID>",
      "subscriptionKey": "<Your_Azure_Subscription_Key>", // Used when creating your QnA service.
      "endpointKey": "<Your_Recorded_Endpoint_Key>",
      "hostname": "<Your_Recorded_Hostname>",
      "id": "117"
    }
  ],
  "padlock": "",
   "version": "2.0"
}

Next, we initialize a new instance of the BotService class in BotServices.cs, which grabs the above information from your .bot file. The external service is configured using the BotConfiguration class.

private static BotServices InitBotServices(BotConfiguration config)
{
    var qnaServices = new Dictionary<string, QnAMaker>();
    foreach (var service in config.Services)
    {
        switch (service.Type)
        {
            case ServiceTypes.QnA:
            {
                // Create a QnA Maker that is initialized and suitable for passing
                // into the IBot-derived class (QnABot).
                var qna = (QnAMakerService)service;
                if (qna == null)
                {
                    throw new InvalidOperationException("The QnA service is not configured correctly in your '.bot' file.");
                }

                if (string.IsNullOrWhiteSpace(qna.KbId))
                {
                    throw new InvalidOperationException("The QnA KnowledgeBaseId ('kbId') is required to run this sample. Please update your '.bot' file.");
                }

                if (string.IsNullOrWhiteSpace(qna.EndpointKey))
                {
                    throw new InvalidOperationException("The QnA EndpointKey ('endpointKey') is required to run this sample. Please update your '.bot' file.");
                }

                if (string.IsNullOrWhiteSpace(qna.Hostname))
                {
                    throw new InvalidOperationException("The QnA Host ('hostname') is required to run this sample. Please update your '.bot' file.");
                }

                var qnaEndpoint = new QnAMakerEndpoint()
                {
                    KnowledgeBaseId = qna.KbId,
                    EndpointKey = qna.EndpointKey,
                    Host = qna.Hostname,
                };

                var qnaMaker = new QnAMaker(qnaEndpoint);
                qnaServices.Add(qna.Name, qnaMaker);
                break;
            }
        }
    }
    var connectedServices = new BotServices(qnaServices);
    return connectedServices;
}

Then in `QnABot.cs, we give the bot this QnAMaker instance. If you are accessing your own knowledge base, change the welcome message shown below to provide useful initial instructions for your users.

public class QnABot : IBot
{
    public static readonly string QnAMakerKey = "QnABot";
    private const string WelcomeText = @"This bot will introduce you to QnA Maker.
                                         Ask a question to get started.";
    private readonly BotServices _services;
    public QnABot(BotServices services)
    {
        _services = services ?? throw new System.ArgumentNullException(nameof(services));
        Console.WriteLine($"{_services}");
        if (!_services.QnAServices.ContainsKey(QnAMakerKey))
        {
            throw new System.ArgumentException($"Invalid configuration. Please check your '.bot' file for a QnA service named '{QnAMakerKey}'.");
        }
    }
}

Calling QnA Maker from your bot

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.

// Check QnA Maker model
var response = await _services.QnAServices[QnAMakerKey].GetAnswersAsync(turnContext);
if (response != null && response.Length > 0)
{
    await turnContext.SendActivityAsync(response[0].Answer, cancellationToken: cancellationToken);
}
else
{
    var msg = @"No QnA Maker answers were found. This example uses a QnA Maker Knowledge Base that focuses on smart light bulbs.
                To see QnA Maker in action, ask the bot questions like 'Why won't it turn on?' or 'I need help'.";
    await turnContext.SendActivityAsync(msg, cancellationToken: cancellationToken);
}

    /// ...

Test the bot

Run the sample locally on your machine. If you need instructions, refer to the readme file for C# or JS sample.

In the emulator, send message to the bot as shown below.

test qna sample

Next steps

QnA Maker can be combined with other Cognitive Services, to make your bot even more powerful. The Dispatch tool provides a way to combine QnA with Language Understanding (LUIS) in your bot.