Bot Framework triage between Luis and QnA Maker
No long applicable, use the Dispatcher Service instead
I've been involved in several bot projects recently where a common pattern has emerged so I decided to produce a sample and blog about it here.
The sample is on GitHub as a C# Azure Bot Service bot: https://github.com/martinkearn/Bot-Luis-QNA-Triage
I worked with Toby Bradshaw on this and he did most the clever stuff so kudos to Toby.
Problem Space
Most customer service bots have two main requirements:
- Answer common questions where everyone gets the same answer.
- Things like "what are your opening hours", "how do I do a return", "Id like to make a complaint".
- The Cognitive Services QnA Maker (QnA) is ideally suited to answer these kind of FAQ-style questions
- Answer more vague or customer-specific questions
- Where the answer is either personal to the customer ("Where is my order" etc) or requires some level of natural language understanding to determine the answer ("I'd like to make an order please").
- The Cognitive Services Language Understanding Service (Luis) is ideally suited to understand these broader, natural language queries.
The Bot Framework SDKs have built-in patterns and classes for working with Luis and there are also plenty of samples for working with QnA. However, in the scenario above, you need to use both services and make a determination as to which one will provide the best answer whilst maintaining access to the built-in capabilities for working with Luis responses.
The Triage Solution
The solution is actually very simple and basically follows this process:
Messages
controller send all message toRootDialog
(which is a standardIDialog
) via the standard boiler-plate code ofawait Conversation.SendAsync(activity, () => new RootDialog());
- The
RootDialog
sends the message to both Luis and QnA and then performs several logic gates on the responses- If Luis has a confidence of 70% or more (adjustable based on requirements), then send the message on to a standard
LuisDialog
to handle and process the intent and entities viaawait context.Forward(new BasicLuisDialog(), ResumeAfterSubDialog, message, CancellationToken.None);
- If the Luis score is less than 70% and QnA has an answer, then reply to the user with the answer from the QnA service
- If none of the above apply then ask the user for more details
- If Luis has a confidence of 70% or more (adjustable based on requirements), then send the message on to a standard
In building the solution, we found there were a few key learnings in terms of how the Bot Framework handles dialogs.
Initially we tried to do the service requests and logic gates as part of the messages controller but we were getting problems with the context 'falling through' the dialogs and getting out of sequence. We discovered that you must always be 'in' a dialog so moved all that code into the initial RootDialog
.
We experimented with both context.Forward
and context.Call
to find the best way to initiate the LuisDialog
. We found that context.Forward
was the best choice in this context because the LuisDialog
needed to original message to do what it needs to do internally.
Its Open Source
The solution is open source at https://github.com/martinkearn/Bot-Luis-QNA-Triage and I'm more than happy to accept pull requests.
Some interesting next steps are as follows:
- A Node version
- Find a way to avoid duplicating Luis calls between the RootDialog and LuisDialog