The course is part of this learning path
This course shows you the fundamentals of how to design, create, and test chatbots using the Azure Bot Framework SDK. You’ll learn about the Bot Framework SDK, the key components that form a chatbot, and how to use templates in Visual Studio to create chatbots.
We'll help you understand the importance of Turn Context and State Management and how these are used in chatbots with the Bot Framework SDK. We'll also cover the dialog library, different types of dialogs, and how you can use these to model conversational logic in your chatbots.
The course wraps up by showing you how to get your chatbot published in Azure and test your chatbot using the Azure Portal.
Learning Objectives
- Using the Bot Framework SDK to create a chatbot
- Implementing Dialogs and State Management
- Testing chatbots using the Bot Framework Emulator
- Deploying a chatbot to Azure
- Testing a chatbot in Azure
Intended Audience
This course is intended for developers and software architects who want to learn more about the Bot Framework SDK and how it can be used to create conversational AI solutions in Microsoft Azure.
Prerequisites
Intermediate knowledge of C# is required for this course. You’ll also need to be familiar with Azure concepts such as App Service and Azure Key Vault, and be comfortable using Microsoft Visual Studio Community edition.
Let's look at working with Turn Context and State with the Bot Framework SDK. In this lecture, you'll gain an understanding of Turn Context, you'll learn about the concept of state management, you'll learn how to use Turn Context to manage state data, and finally, we'll look at a demo that shows Turn Context and state management in action with a chat bot, are you ready, let's get stuck in.
So what is Turn Context? When the adapter receives an activity, a Turn Context object is automatically created. Some of the information the Turn Context object contains includes information about the incoming activity, the sender, and the receiver. When the adaptor generates the Turn Context object and associates the data, the Turn Context object is then sent over to the chat bot. One thing to call out here during this process, is that the Turn Context object only processed for the length of a turn.
Other important information is included within the Turn Context object. For an example, you can use the Turn Context object to help you identify information about the chat bot and user participating in the conversation. Your chat bot will probably have some custom code that contains information too unique to your use case. You can make this additional information available within the Turn Context as well. You can also use the Turn Context object to get a reference to the adapted object. The Turn Context is one of the fundamental concepts and objects within the Bot Framework SDK.
Let's learn more about Turn Context, state, and using Turn Context to manage data in chat bots. So what is state within the Bot Framework SDK? A chat bot is a stateless solution, this means that once your chat bot is deployed, it has not concept of saving data from one turn to the next. This is less than ideal, as you probably need your chat bot to track the context of a conversation so it can adjust its behavior, or to remember data supplied in previous questions. For example, if the user has already supplied an answer to a question, it can be frustrating for them to have to repeat an answer to that question.
Fortunately, the Bot Framework SDK ships with state management features that let you create a stable chat bot, state management features let you add data to state and load data from state. They make it simpler for you to create rich, conversational experiences for people who interact with your chat bot. State management features in the Bot Framework SDK, let you store state data into one of three categories. These include, use of state, conversation state, and private conversation state, user state is available in any turn the chat bot is involved with for the user on that channel, regardless of the conversation, conversation state is available to anyone within a specific conversation regardless of the user, private conversation state is scoped to the specific conversation and specific user, all data in each of the above categories is stored using a collection of key value pairs.
So with three different options to store your state data in which one should you pick? Conversation state is good for tracking the context of a conversation, you just have to to keep track if the bot has asked the user a question, or which question was asked, user state is good for tracking information about the user. Use this scope to track data such as the username or customer settings. Private conversation state is good for use cases that involve group conversations, for example, the chat bot could ask participants in the group conversation to vote on a particular topic. Each response could then be stored in private conversation state for followup processing or reporting.
One thing to know, is that both user and conversation state are scoped by the channel where the conversation is occurring, this means that the same person using different channels to access your chat bot will appear as a different user. One for each channel. Each user will also have their own distinct user state, after saving your data to the conversation, you as our private conversation state, you'll have to call the save operation within the Bot Framework SDK to save your data to the storage that you have configured, this maybe a memory Azure Blob Storage, or Cosmos DB, the OnTurnAsyn method, is a good place to store this logic. That's what we can see here.
One thing to call out here, is that state mechanisms in the Bot Framework implement what's known as the last rate wins behavior. This means that any updates for a value stored in state, will be overwritten by the new incoming value. This is probably okay for most chat bot solutions, but it's something to be aware of if your chat bot is deployed to an environment with a network that has latency issues. It's now time for a demo.
In this demo, we'll create a chat bot that asks a customer for it's order. We'll use the state mechanisms in the Bot Framework SDK to check if the bot has already asked the question or not, we'll also read the customer's previous order back from state, and display it back to the user. So we're back in Visual Studio, and what we're looking at here is the start-up CS file. And this is one of the first things that you have to change when you want to introduce state management capabilities into to your chat bot.
So what we can see here during that length 38, is that we are setting up the memory storage persistence layer for our chat bot, and this is ideal for development and testing purposes. The next thing that we see here is the conversation and user state registrations taking place. So at this point, we have set up the backend plumbing to handle the state management aspects for our chat bot. The next thing that we have to do is to create some classes to represent the data that we want our chat bot to store in state.
So if you look over to the right-hand side here in the solution explorer, we can see there's a folder called state data, and in here we have two classes, conversation state data, and user profile state data. So if we open conversation state data, we can see here this is just a simple class that has a boolean property, and this is a property that we'll use to indicate a chat bot in code if the chat bot has already asked for that order as part of this conversation, we can open the user profile state data, and the question that this chat bot will ask will be for a person's food order, and that information will be stored as part of the user's profile in this food order string.
So now that we've looked at the plumbing, and startup CS, and the objects that will store the state data, the next thing that we can do is to actually look at the chat bot itself and see how we can start to manipulate the information in state. So we opened the class state bot. So here we can see, we have a regular chat bot that inherits from our activity handle that we've seen in some of the previous lectures, but the new additions are down at lengths 12 and 13. And here we're setting up two private member variables to represent the conversation state and the user state.
And then at the constructor for this class, we can see that we pass these objects in the via dependency injection, which is set up as part of the start-up CS that we looked at, the values that get passed in via the constructor, are then set to the private member variables. We can see here that we have a welcome message, and the on membersAdded async, and if we scroll down a little bit further here, this is where our state management code lives.
So what we can see up here are the properties being created and the state management mechanisms, so we'll close the solution explorer, and we can see we're creating a property, and then we're trying to fetch that back using the state access, or, now if that property doesn't exist, what will happen will be, the new object of conversation state data gets created, and that's, we can see all of that happening here between lengths 39 and 40. And the same thing happens for the user profile data between lengths 42 and 43.
So this event on message activity async is part of the activity handle that we've looked at in another lecture, and it will fire when a new message comes in, here we can see where most of the state management access takes place. During the first interaction with the chat bot, the property food order will be null or empty, the boolean property, HasAskedForOrder, will also be false, this means the user will be asked what he would like to order, under the hood, the Bot Framework SDK will set this property to true. This means that when the user supplies their food order, the chat bot will not ask them this question again.
After the user supplies their food order, the on-message activity async method will fire again, this time however, the following code here will be run. In this code, we referenced the text that was supplied by the user via the Turn Context and assign this to the user profile object. This object is stored in the user state. We then send the message to the user to let them know their order has been received. We also set the boolean property to false, this lets the chat bot repeat the food order process again.
A subsequent interaction with the chat bot will result in this code being invoked here. This is because the user profile state object now contains a value that we've read from state. So that shows what happens in terms of the logic, and reading, and rating information to state. The final thing that we need to look up is the OnTurnAsync method, and that's what we can see here. So what we can see here are the actual rating to the state stores between lengths 79 and 81.
So when the on-message activity async method has ran through its process and validation, what happens is the OnTurnAsync method will be invoked and it will then save that information, which will be the food order, into the state store. So now that we've ran through the theory, all that's left to do now is to run the chat bot. So we will do that by clicking on the run arrow, and when it spins up, we will start the emulator. Well, here we can see the emulator running. We get the welcome message that we set. We can say hi. And we're asked what we would like to order.
We could say pizza, now what's happened here, and we can't see it, but under the hood, we've looked into the state store to check if we have already answered this question. What would you like to order, first statement is false, so we get, what would you like to order? We've now supplied a food order of pizza, so the bot now has information stored in state, so what we can now do is read this information back from the state store, here we can say something like, sure, my order, and press return, and here we get, you previously ordered pizza. And if we moved the emulator window to one side here, we can see here at length 69, that we get your previously ordered, and then we're concatenating the order that is stored in the user profile, and the user profile is stored in the user state.
So what we've seen here is how to set up user state and conversation state, and the startup.CS file, we've then created two classes to represent that information, and finally, we've seen how to use the OnTurnAsync method to write that information into the state store.
Jamie Maguire is a Software Architect, Developer, Microsoft MVP (AI), and lifelong tech enthusiast with over 20 years of professional experience.
Jamie is passionate about using AI technologies to help advance systems in a wide range of organizations.
He has collaborated on many projects including working with Twitter, National Geographic, and the University of Michigan. Jamie is a keen contributor to the technology community and has gained global recognition for articles he has written and software he has built.
He is a STEM Ambassador and Code Club volunteer, inspiring interest at grassroots level. Jamie shares his story and expertise at speaking events, on social media, and through podcast interviews.
He has co-authored a book with 16 fellow MVPs demonstrating how Microsoft AI can be used in the real world and regularly publishes material to encourage and promote the use of AI and .NET technologies.