A good way to learn how to build a bot in Watson Assistant (formerly Conversation) is to see an example of how a bot is built. So I thought it would be useful to walk through the details of an example bot. If you are not familiar with the basics then it may be worth reading Getting Chatty with IBM Watson first.
The example we will be using is a restaurant bot. It answers various questions about a restaurant and can book a table. We’ll be making use of many of the features of Watson Assistant, including slots, conditional responses, folders, digressions, and cloud function calls.
When you create a new dialog, you get two nodes generated for you — a Welcome node and an Anything else node.
Generally bots need a way to start the conversation and introduce the user to their capabilities.
In this case our Welcome node is pretty much the same as the generated one. The only things I changed here were the response to reflect what this bot can do, and to set up some initial context values.
With the Anything else node, I wanted it to not only be the overall fallback node, but to escalate if it gets hit several times in a row. To do this I enabled multiple conditioned responses, and added a new response that is triggered when a counter is over a certain value. This new response says it will handoff the user to a human agent and sets a context variable to indicate this. It would be up to the client app to do something based on that variable being set.
That counter is set to zero in the Welcome node, and incremented in the second response of the Anything else node.
Since we only want this to trigger with consecutive hits, we need to reset the counter when we do understand. Rather than resetting this in every other root node, I added a single node just below the Welcome node that checks the confidence and resets if the confidence is above a certain threshold.
This node sets
$unanswered_counter to zero and then jumps to the next node to carry on processing.
Frequently Asked Questions (FAQ)
Now we have our greeting and fallback, we can start actually trying to help the user.
Adding FAQ enables your assistant to answer a broad range of questions. Initially FAQ nodes can act like a router, directing users to a website or phone number, until specific responses can be added. In this example bot we only have a few FAQs so we can just immediately add the responses.
A combination of Folders and Multiple Condition Responses allows you to build FAQs in a manageable way. You can group related FAQs into a Folder. In this restaurant example, we only have small set of FAQs so there is just a single folder but it demonstrates the structure.
Within each FAQ node you can use multiple condition responses to differentiate between different entities on the same intent, for example “do you cater for vegans?” and “do you have anything gluten-free?” are the same intent, but with different entities.
Chit chat is similar to the FAQs in its pattern, but in this case the bot is handling the chit chat part of conversations, e.g. “Hello”, “How are you?”. You can group your chit chat into one or more folders.
In addition to initiating a handoff when the bot is struggling to understand the user, we can also allow the user to ask for a handoff. So here we have a root node that checks for the user asking to speak to a human, and then we respond appropriately and set the handoff context variable to notify the client application.
Booking tables is the main use case of this bot. For this task we can make use of slots which makes it easy to gather information in a conversational way.
I added a slot for each piece of information I wanted to gather: date, time, number of people, and a name for the booking. I also have a final slot which allows the user to confirm all the booking details.
For the date, the things to point out are that it’s using the @sys-date system entity (which captures dates like tomorrow as well as April 1st), and we do some formatting on the date when we store it:
For the time, we have a different Check for condition:
@sys-time || (@sys-number && slot_in_focus)
Here we are using a special condition
slot_in_focus to handle the situation where when prompted for the time, the user may simply type in a number that is not obviously a time, e.g.
7pm. So the slot can be filled by a time or by a number when the slot has prompted the user for the time.
The other thing we are doing in this slot is formatting the time when we store it:
Number of people and name
For number of people and the name, there is nothing special happening other than using the system entities @sys-number and @sys-person.
For the confirmation slot, we want to make sure this can only be filled when
slot_in_focus is true (i.e. we have prompted for the slot). We also want to make sure that we don’t fill the slot if the user was trying to change one of the values for the previous slots.
To handle the case where the user says “no” to the confirmation, we have a Found response which clears all the slot variables and causes the process to begin again.
Changed your mind?
One thing that is useful to add to your slots is confirmation when the user changes one of the values. You can do this by adding Found responses which check for the previous and current values being different:
You can also add some handlers to deal with the user asking to change something (but without them providing the new value). For this you need a
#change intent and an entity that captures the different information your slots are gathering, so if the user says “Can I change the time?”, this handler below will trigger, clearing the time slot, which will then re-prompt.
You may also want to use a handler to deal with the user asking to cancel the booking.
The other thing is consider is how do you clear the context variables set by the slots in order to take another booking? A simple way to do this is add a parent node to the node with the slots. The parent node clears all the variables and then skips to the node with the slots. So every time a user asks to book the slot variables are cleared.
Help me order
Another useful pattern is a process flow. For example, in a banking bot, you could have a flow that takes users through the process of reporting a lost credit card. It’s perhaps not quite so useful in a restaurant bot, but you could get the bot to help customers choose what they want to eat.
In the flow below, the bot helps the customer decide what to eat by asking what cuisine, and then offering choices based on that. Within the flow, there will likely be some nodes with slots to gather information needed.
Recently Watson Assistant introduced Digressions. This allowed users to digress out of a flow and then to return back into the flow where they were. In general you will want to enable digressions and allow them to return. So in our restaurant bot, we will enable digressions in the booking node with the slots:
Then on most root nodes and folders we want to allow the digressions to return:
There are a couple of exceptions to this. I don’t allow digressions into the Welcome or Anything else nodes. Additionally I don’t allow returning from the handoff node (as once you have transferred to a human agent you don’t want to return back to the same flow).
It is now possible to call out to IBM Cloud Functions from within the dialog. For our restaurant bot this means we could call a cloud function to find the nearest restaurant.
In the JSON editor for a node you can add an
This provides the name of the Cloud Function to call, parameters to the function, credentials (passed in by the client application), and a context variable to store the result in.
The result variable will be available to use in later nodes, so to add a response, you can skip to a child node and use the result there. The
@location node contains the call to the Cloud Function, and the
$locator_result node uses the result in its response.
Hopefully this has help to explain how to build bots with Watson Assistant.
If you want to learn more about building with Watson, check out some of my other articles in the Conversational Directory.