Creating “ZoneBot” using the Microsoft Bot Framework and LUIS
Looking to create your first chatbot? Or for the location of our head of .net Andy Butland? In his latest piece, the man himself explains how you can kill both birds with one stone…
A couple of months back I wrote a piece on Slack “slash commands” and ASP.Net web hooks describing how they were used to set up some features on our agency Slack channel.
Specifically we allowed people to type something like /zonebot where-is Andy Butland that would then query the web services made available by our agency platform Timezone to let the requester know where someone is based, what they are working on and whether or not they are on holiday.
This worked quite nicely but in terms of a “chatbot” experience was rather limited. The user would have to stick very closely to the required syntax or otherwise the request simply wouldn’t be understood.
Developers may well be reasonably comfortable with this type of precise language but expecting the whole agency to effectively learn a command line syntax was a bit of an ask! Particularly if we started to add more features to it.
To improve it we wanted something that could be treated as a true bot; set up in Slack as a bot user whom real users could ask questions, with natural language via direct messages and receive responses. And of course it gave a nice excuse to play with some interesting new technology…
The Bot Framework is a new release from Microsoft, currently in preview, that helps developers to create bots and make them available on platforms such as Slack, Skype and others. It has three main components.
Firstly the bot connector is a service acting as a middle layer between your bot code and the service it’s running on. The idea of this is as a developer of a bot: you can abstract the service that it runs on, ideally allowing you to “write once, run anywhere”. In practice there may well be platform-specific features you need to take account of but given most platforms have many features in common this is a nice way to allow for one installation of bot logic to be exposed in multiple places.
Then there’s the bot builder, a set of code libraries for C# and nodejs to help with the actual building of the bot. In particular of interest for us with the integration with LUIS (the “Language Understanding Intelligent Service”) which gives support for natural language interaction.
Finally there’s the bot directory, of less use for us at the moment given the bot being built is intended for use within the agency, but were we building something of more general use, it could be published and made available here.
To get started with building a bot in C#, using VS.Net 2015, with the support of the bot builder, it’s first necessary create a new project using the bot application template and to to pull in a NuGet package:
PM> Install-Package Microsoft.Bot.Builder
Incoming messages are first handled by a method in MessagesController that hands-off to another class you create with the responsibility of parsing the the message and returning a response:
A really simple instance of this class would like like this. It simply repeats back what the user has provided parrot fashion:
Not very exciting yet but the possibilities start to open up here. This class can of course be created with dependencies on other services and have its own logic to handle the input that comes in and return an appropriate response.
One way to do this would be to start parsing the input in order to determine what the user is looking to do or discover. To build up any level of sophistication though it would seem that a world of pain (i.e. regular expressions) might await.
What’s much nicer though is to leverage LUIS and the natural language parsing and learning abilities it has, which can be done using a different base class: LuisDialog.
Before we get to that though we need to create our LUIS application — one where we define the things the user wants to do, known as intents, along with the things they want to act on or find out about, known as entities.
In our case our entity is “Person” and we have a number of intents including “Who is”, “Where is”, “Contact details” etc.
With those defined we can then start to train the model — entering phrases that we think users might use, picking out which parts of the phrase relates to entities and associating the phrase with the appropriate intent.
As well as custom defined entities, LUIS supports many common built-in ones, such as numbers or – as in the screenshot above – dates.
With a number of phrases provided and mapped the model is now trained and can be published. Even then though it can continue to be improved. Once hooked up with a bot the real phrases that users attempt can be viewed and suggestions for improvements are made.
Back to our code we decorate our class with details of the published application and can then apply further attributes to our methods. These attributes define which method is called in response to a given input.
Behind the scenes an REST API request is made to LUIS, passing the input phrased and this is best matched to an intent and entity. If a sufficient threshold score is reached then the method that is determined the best fit is called, for example:
With a bit of training this worked quite nicely to pick out the name of the person requested and the specific intention required, handling a number of variations such as:
Who is Andy Butland?
Where is Andy Butland?
What is Andy Butland working on?
What was Andy Butland's schedule last week?
How can I contact Andy Butland?
But the conversation is still a little stilted. Particularly having to repeat the name each time. What would improve it would be to allow questioning like this:
Who is Andy Butland?
What is he working on?
What about Neil Cumpstey?
What is his schedule?
In other words, for each request we need some knowledge of the previous one, so we can carry out either a new intent for the same person, or the same intent for a new person.
In terms of LUIS the first addition was to train it to allow it to recognise words such as “he, she, his, her and him” as requests for people. And secondly was to add a new intent called “Repeat action” that was trained with phrases like “And…,” “How about…”, “What about…” etc.
Within our code, for every matched intent we now record what it was in a private, static field, allowing the last intent to be retrieved if the “Repeat action” intent is matched. It can then respond appropriately for the new person.
Similarly we also track the last recognised person on each request. On the next request, if the new person requested matches one of the third person words such as “he” or “she” that we identified above, then the matched intent is carried out with the person recognised from the previous request.
With that in place the conversation becomes a lot more natural.
One last feature worth noting is the support for common concepts such as numbers and dates. In the case of the latter, LUIS is sophisticated enough to parse dates from lots of different inputs, whether it’s a specific date such as “27th May 2016” or a phrase such as “next week” or “last week”. It matches those to an entity and in the code we can pick out not just the provided phrase but also the actual date it has been matched to.
Working locally there’s a handy bot framework emulator that we can download and use, allowing for examination of the incoming and outgoing responses as well as setting breakpoints in our code to debug the bot logic.
To make available to use for others though the first step is to publish the bot as a web application to an external web server — in our case I’ve used an Azure web app.
Then via the bot framework site the bot can be registered, providing a URL to it’s end-point along with various other details. Once that’s done it can be hooked up with platforms — for Slack there are a few steps, but a very straightforward guide to follow.
And with that it’s set up. Users of our Slack channel can interact with it as if it’s another user. Initially that means direct messaging but with further development we could look at some channel specific functions (such as bring in project status details for the team).
Another feature we’re considering looking at is using the bot to carry out some of the functions and transactions staff at Zone need to complete. Things like booking rooms, server requests and submitting time sheets.
For now though, as the company grows and hires in different locations, Zonebot can help people keep up just a bit more on who everyone is and what they are doing.
Originally published at medium.com.