In this episode of Cognigy Sessions we will dive deep into one particular component of Cognigy.AI: The Question Node. Question nodes are used to collect information from users but they are way more powerful than that. They can validate user input for a broad number of input types, auto-convert natural language to a machine-readable format, provide UI elements such as datepickers, and much more. They also allow to define granular escalation rules or make conversations flow naturally by dealing with overanswering and other enexpected input.
Join the Cognigy.AI User Community
Welcome to Cognigy Sessions, our Techinar series from Conversational AI experts for experts. Today's session is an entire episode dedicated to one seemingly simple feature: The Question Node. In fact, Question Nodes are a core piece of Cognigy.AI's natural language processing and probably way more powerful than most Flow developers would guess. So get ready for roughly 30 minutes of super-advanced Flow design. You will see how Question Nodes can systematically gather user input, how to work with input validation, escalations, and other advanced features, and how dynamic Slot Filling enables the most natural, convenient experiences for end-users. This recording is also available in our Help Center. Please follow the link below to access additional resources and go to our community for questions and discussions. Also, please be invited to start a free trial and try out Question Node yourself, if you're not already a Cognigy AI user. And with that, let's start today's session.
Hi, everyone, my name is Phil, and today I'm going to be talking to you about the Cognigy Question Node and some of the advanced features that this Node has. All you need to follow along is access to Cognigy.AI. So you need a Cognigy.AI trial account and if you don't have one, you can go to signup.cognigy.ai sign up for a trial and you'll be in the platform within seconds.
Now, what are Question Nodes? Question Nodes are Nodes in a Cognigy Flow that, when you hit them, they will ask you a question and then they will wait for your answer and check whether the answer is correct for the specific type of question that was asked or not.
So, for example, in the Flow that we see here on the right side, if we hit this question, it's going to say yes or no, and that's going to wait for a valid answer. And a valid answer in this case is something like, yes, yeah, no, no, something like that. But if I, for example, say Philip as the answer, then it's going to re-prompt me and it's going to say, well, sorry that wasn't a valid answer, yes or no, and if I then say yes or no, the question detects that this is a valid answer and then it continues further down in the Flow. So there's a stopping question that essentially pauses thereafter the question was asked and forces me to give the correct answer.
So there's various different Question Types. And what these Question Types define are what the valid answer has to be, when the user sends their input. And all of these essentially operate on the Cognigy Input Object. So, for example, the Text Type checks, whether input.text exist, so has the user send any type of text? A Yes/No question will check if the input.type is pAnswer, which means a positive answer, or nAnswer, which is something that is set by the NLU. An Intent Question Type checks, if input Intent is not null and a Slot question will check whether specified Slot would exist. So if you have attached a Lexicon, for example, and you need the user to select a product, you're waiting for a product Slot and this is something that you can do using the Slot type question. We then have some Question Types for each of the Slots that come with Cognigy, so for each of the System Slots: Date Question, Number, Temperature, Age, Duration, Email, Money, URL, and Percentage. So they are waiting for those specific types of Slots that are built into the Cognigy system. And then we have a Regex Question Type where you can specify a regular expression and only if that is matched the Flow continues. We have a Data Question Type, which, pretty much equivalent to the Text Question Type, is waiting for an input.data event, so did something come in input.data. And then we have the Custom Question Type and we're going to be talking about that one a little bit later.
In Cognigy, we have two different types of questions. We have the Regular Question Node and we have the Optional Question Node. The Regular Question Node will ask the question and then stop. It waits for a valid user input before continuing. So, for example, on the left side here, we can see, are you a customer? And we're expecting a yes or no answer. If I say Phil or one, two, or three, those will not be valid answers. I will be re-prompted until I give the correct answer and then it will go to question two. This one is ''what's your name?'' which is a text question and I say Phil, it goes to question three, it says "what is your date of birth?" I say "Phil", it says "That's not a valid answer. What's your date of birth?" "August 26" and then it continues on. So the Question Nodes are stopping Nodes and they require you to give the answer before they continue. The Optional questions, on the other hand, are questions where the question will be asked and then we continue down in the Flow immediately. The system will remember that this question exists at this point in time and when you give a correct answer, we will execute the On Answer path that is coming out of the question regardless of where you are on your path right now. So it is essentially being kept in the memory of the Node for x iterations. And you can define that x in the Node itself, and then it will go down on the unanswered path or it will forget the question if you're not answering the question quick enough.
What we're focusing on here today are the Regular Question Nodes, the one we're seeing on the left side, and with that, let's go take a look.
Alright, so here we are in Cognigy.AI and we've already set up a Flow and there is currently nothing in this Flow. And what we're going to do is we're going to show you how the Question Node works and some basic features of it. So let's add a question and questions by default are Yes/No questions and they are asking the question, yes or no. So let's see what happens when I execute this Flow. So I'm coming in, I'm saying anything it says yes or no. I give it an answer that is not yes or no. "Not sure I understood this correctly." Maybe I say "yeah" and then it continues further down. We didn't see this at all because there's nothing else here. So maybe here we add something else and we say, um, "your answer was", and then here we can use a token called the Last Question Result, and then let's see what happens if we play with this now. So "yes or no", given a wrong answer, I'd say "yes", and it says "your answer was true". Now, why does it say "true" and not "yes"? It's because the Yes/No question is essentially a boolean question, and we can see the result when we go into the Cognigy Input Object here and here we can see it says true. So the Last Question Result Token links to input.result. Now, of course, we can also operate on that, so we could say if the Last Question Result is yes. If the Last Question Result and then here we have the ''is yes'' operator, then we say this and otherwise we say that. So here we can say, "you said yes," and here we say, "you said no". Let's try it out. We're coming in, "Yes or no?" "Not sure I understood this correctly." Yep, "you said yes". So this is using the NLU in this case to detect whether it was a positive or a negative confirmation.
Now, there's, of course, different questions. So let's say if we say yes, we're going to ask another question. And here we are going to ask, for example, a Text question. So "what's your name?" And then we're going to ask another question. And that question is, for example, "what's your date of birth?" Let's try this out, we're coming in, "Yes or no?" Yes, "what's your name?" "Phil", "what's your date of birth?" Now, this is interesting, we're actually getting a date picker here so we can use the date picker or we can just type the answer as well, and now we're done.
Now, of course, when we look at the result object here, this is only the result of the Last Question, and if we want to remember the individual question answers, we can of course, we could add an Add to Context Node here. But the Question Nodes have that built-in actually under this result storage here where we can say Store the result in Context. Maybe I remember this as Yes/No, then the name I'm going to remember as name, and the date of birth, I'm going to remember in my Context as date of birth. You can see actually I can do the same thing in the Contact Profile now, so I could store the date of birth. Or actually let's take the name because there is a nice profile key for that. I could store that one in the Contact Profile and the profile key to use maybe first name.
Let's try that out, you can see I currently don't have a first name set, so we're coming in, "yes", what's your name? "Phil". What's your date of birth? Let's just say "tomorrow" and we're done. And now if we check in the profile, my first name is now Phil and if we check in the Context, we have all the information that we provided to the Question Nodes. So we have the Yes/No, the name, and the date of birth with the full object for the date object in this case. The Date question is a little bit special because if you activate the Date question, you're getting a lot of extra sections down here, which are the date picker options. And also you could, for example, manipulate the button texts if you want. So open the date picker, maybe I say OPEN DP, or you can say what are the date settings? Maybe the minimum date is Thursday, um, last Friday. Or you can say time settings where we want date and time and we want it in 24-hour format. Now, if we do that, we'll see the date picker both in the Interaction Panel and the Webchat will have changed. Now this has OPEN DP, and when I open it, you can see the date here was set, and I also have a time picker now. So that's what we can do with those date picker options. They only really impact the Interaction Panel and the Webchat. If you're using another channel then the date picker obviously won't work on that because it's a specific plug-in.
Now, what we've looked at so far are the basic features of the Question Node and how they're mostly used, but the Question Node has also several advanced features which we're going to look at now. We're going to look at Re-prompt. So what if the user gives the wrong answer? What options do we have? We're going to look at Escalations. What if the user keeps giving the wrong answer? Or what if something like "I don't know" is mentioned? How do we handle that? We're looking at Detailed Results Storage, where we don't just store a True or False, but actually also the user's full answer. Looking at additional validation options, where, for example, if we have an email address, we want to validate that the email is a cognigy.com email and add the result location. So let's get advanced and look at some of those extra things the Question Node can do.
So let's first look at what we call Re-prompts. Re-prompts are put when the user does not give the expected answer. So here we are asking a Yes/No question, as we can see up here in the Question Type. And if I don't give a valid answer, it's going to re-prompt me with a message in this case ''Not sure I understand this correctly'' and then it's going to ask the question again. This Re-prompt message can be changed here under the Re-prompt option, and it is a CognigyScript field so you can put in anything that you like. For example, you said text, but I expected an answer like yes or no. Here we can also set whether we want to repeat the question or not. So let's turn this off and then we will see that on the Re-prompt we are now only getting the Re-prompt text. We also have something called Re-prompt conditions where we can add a condition and only if this is true, or the Re-prompt condition is empty, the re-prompt will be shown. So, for example, here we could say if the input text includes the word Phil, then we will show the Re-prompt. Well, let's do it the other way around. If the input text does not include the word Phil, we will show the Re-prompt. So we go in, we give an incorrect answer and we're getting the Re-prompt. Now, if I say something with Phil, we're not getting the Re-prompt. So that's how the Re-prompt conditions work.
Now, the Re-prompts are nice to give the user some hints, but maybe we don't want to give always the same Re-prompt. For example, we want to give different messages depending on how often they've given an incorrect answer and maybe after a number of incorrect answers we want to escalate and do something completely different, like jump to a different point in the Flow, output a special message or something like that. That's where Escalations come in. Under the configuration here, we have an Escalation on Intents and an Escalation on wrong answers and we're going to start off with the Escalation on wrong answers. The Escalation on wrong answers triggers after a number of wrong answers and you need to define an action of what will then happen. So, for example, if we say Output Message, the wrong answer count trigger is here, so after three wrong answers, we're now outputting this extra text. So maybe we output "Escalated". This is a normal Say Node, you can use graphical outputs etc. As well. You can also say prevent the Re-prompt. So when the Escalation Text is output, the Re-prompt is not outputted and only escalate once, which means we are only sending this message on the third wrong answer, not on the second, not on the fifth, and going forward. Or if we turn this toggle off, it will send it from the third one on, so also on the fourth, on the fifth etc.
So let's take a look. So we're inputting something it's expecting a yes or no answer. First wrong answer, Re-prompt, second wrong answer, Re-prompt, third wrong answer, Escalation. Now here we can, of course, also do amazing things already with this special escalation message. But we cannot just output a message. We can also do different things. We can skip the question which would when the Escalation happens, skip the question and input something specific into the results object. So let's see this here. So, ok, after this question, we're done. So I'm going to send a message, yes or no, first wrong answer, second wrong answer, third one, we skipped the question, and if we look at the results object, we can now see skipped is true, and the reason is too many incorrect answers were given and question was skipped. So you can then after the question operate on that, you go like, Ok, was it skipped or not?
But the real power comes into play when we use the options to either go to or execute another Flow and return. So let's do that. But for that, let's create a new Flow first, which we call Escalation Handler. Now, in this Escalation handler, let's for now just add a Say Node where we'll just say "escalate it". Now we go back to our Main Flow and in here we are now going to say, ok, what shall we do when we put in too many wrong answers, execute Flow and return, and we are going to choose the Escalation Handler and the Start Node for that. So there we go, let's try this out. We come in, the question is asked, the Re-prompt, second Re-prompt, and now the Escalation. We can of course, not just output a message, but we can do much more advanced things now in the Escalation Handler, and let me show you that by executing this again. So question asked. This was input one, input two, we get a Re-prompt, input three, we add a second Re-prompt, input four, we get the Escalation. So now we've hit this Node.
We have a new object in the Input Object called Active question, and this one shows us is a Question currently active and yes it is, this is the Node ID of the Question Node. So you could do a Look Up on that, for example. This is the type of the question that's active. It was last executed on the fourth user input, the forget question threshold is 1. We saw two Re-prompts and we had one Escalation count already. So one thing we could, for example, do, we could put in a Look Up where we say, what active question is currently there? So we say, input.activequestion.type, for example, and we say, ok, if it is a Yes/No question, we're escalating in this way. If it is a Date question, we're escalating in a different way. So let's try that out. "And you need to provide an answer like yes or no, please." And here we could say "You need to provide a valid date like tomorrow, please." Let's try that out. We're executing the main Flow again, so we ask the question, Re-prompt one, Re-prompt two and now we get the special Escalation here and we could, of course, just use our regular stuff here ''Really, please say yes or no'', "YES OR NO", and then in the options, we say linear. So this should now automatically escalate the answers in this Say Node. First one, second one, third one, or you could, of course, do another Look Up and say, ok, which escalation is it? What do I want to do?
I'll go back to the main Flow. Actually, let's add a second one. So here we have a question, which could be a Date question. Which is "when?". And this when question, we also tell to go to a Flow and return, maybe already on the second input, but that also goes to the Escalation Handler, just so that you can see how it would work. So we get the question, yes or no, first time wrong, second time wrong, third time wrong, we go into the Escalation. Now we say yes, now we get the Date question, first time wrong, second time wrong, we go into the Escalation, and that's how this would then work.
Now, Escalations don't just work on the number of wrong answers, but we have the exact same functionality for Intents, so you could define a specific Intent, and then if that Intent is output, you do something like outputting a message, executing a Flow or something like that. So you could, for example, have a ''help'' Intent that that goes and does something, and you do that by specifying the Intent name here, or for example, a don't know Intent. So you could say if I'm in this question, but the user doesn't give a valid answer but says something that triggers the ''don't know'' Intent with a score of at least 0.8, then do something like for example, output a message or skip or something specific to that Intent. So on a help Intent I could on both of those do a ''Go-to'', so I could say on both of those go somewhere. On the help Intent I'll output a message and I come back to the Node which you can do because you know the Node ID in the active question field, in the Input Object, and on a ''don't know'' Intent I actually skip the Node and jump to the Node below tha. So you can get super advanced on those types of Escalations here as well.
Next off, we're going to look at storing Detailed Results. For that, we're first going to start and say, ok, we do want to store our answer in the Context object. So we're going to add this to the Results Storage here. So we're now storing a date and the Yes/No answer into the Context object. So I'm starting the Flow, I'm saying yeah, and I'm saying tomorrow, and we can now see that this is stored into the Context. Here we have the Yes/No answer and here we have the date, but we don't have a lot of information about the answer the user is actually given, and sometimes for compliance reasons, we have to keep that data as well. So what we can do here on the advanced, we can activate Store Detailed Results and that is going to store a more detailed object about what the users actually said when it was answered etc.
So let's try that out. We're coming in, I say, ''yes please'' and when? ''Tomorrow would be good''. Now, if we look into the Context again, yes / no is now an object. The value is true, that's what we previously saved in. This was the question that was asked and this is the timestamp when it was answered. And this was the full answer that was given. And for the date it's the same, we have the value, the question, the timestamp, and the answer so you can save detailed results and not just the standard results if that is required for your use case.
Now, the Question Types that we have define the validation for that question. Meaning that if it's a Yes/No question, we expect an answer that the NLU identifies as a pAnswer, so a positive answer or nAnswer, a negative answer. Or if we have a Date question, then we expect an answer that the NLU identifies as a date input. Now, sometimes we might want to have additional validation on this, for example, if we have an email question. So let's add one of those. Here we now have an Email question and we say ''Your email please?'' maybe I want an email that has to be a cognigy.com email. So if I come in, it asks me about an email. If I put something in that's not an email, I'll get the Re-prompt. But if I do put it in email, it continues on to the next question. Now, what if I only want cognigy.com email addresses? What I can do under advanced, I can add additional validation, so we know that the Email questions take the result from input.slots.EMAIL. So what I could say input.slots.EMAIL, and the first one that was found; ends with cognigy.com. Now, this would mean only emails where this condition is also true will go through the question. So let's see, I'm getting the re-prompt, which, of course, doesn't really make sense. There's still a Yes/No re-prompt, but now if I put in a Cognigy email address, it now goes straight through the second question. So the Additional Validation field under Advanced allows us to put in further validation on top of the validation that has already been put in by Cognigy.
Now, what if we want to completely custom define the validation and not rely on the types that Cognigy delivers that have validation built-in, so validation on Email, Slots, Duration, Slots etc. What we can do for that is we can use the Custom Question Type, which always evaluates to true and then checks only really on the Advanced Validation field here. So let's imagine we are sending a Webchat plugin here, which uses a React component on the Webchat to show some advanced controls that the user picks something from and that one sends a data object back. And maybe that data object is input.data and then it has a results field and that's an integer. Let's say this one has to be larger than three. Now, let's try this out. If you want to try data inputs in the Interaction Panel, you can turn them on here under ''Show data input'', and now you can see we have a data input as well. Let's try this out. So we're coming in, we're saying ''a'' and then we're sending text back, but we don't want to send text back. We actually want the user to pick something from the plugin. Let's do that. So we're sending a valid JSON object back and that is a result one. Now, this is a valid object, but we said result has to be larger than three. So if we send result 10 back, we are now going through.
Now, what do we store in the results object? The results object is true and that is not very helpful in this case because it's just true. But maybe we want exactly that number that was stored in the result. We can do that by specifying the result location. So here we could say ''input.data.result'' and that will then store that number into the result rather than just true. So let's try this out. We're saying ''a'' and now here we're saying result is five. And now if we look into the Input Object, we can now see that we've specified what is the validation and where do you find the result, and that's what you can use the custom type for.
Now, we've seen a lot of advanced features of the Question Node so far but what we've also seen is that we're handling each question on its own. What if the user comes in and gives us the answer to three Question Nodes in one go? Will it detect that or will it actually just accept the answer for the first question and then ask you for the second question again? In Cognigy, there is a couple of ways how you can handle that to make the conversation really smooth and really fluid, and that's what we're going to look at now. So let's go and do some Slot Fillers. So for that, we are going to actually delete most of this Flow and just build a new one, where we're going to say, ok, we have three questions that we're coming in with. We have an email question, for example, ''What's your email?'' then we're going to have a second question, which is, ''When would you like to come'' and we will have a third question, which could be a Duration question, ''For how long would you like to book?'' So it is a Duration question like 30 minutes. Now, let's take a look if we stop this Flow. What's your email? When would you like to come? Tomorrow and for how long would you like to book? 30 minutes. So that's our Flow. Here we maybe add, we simply say done.
Now, let's configure those questions to store the result also in the Context. So this is email, this one is date, and this one we will call duration. And now we're going to take a look at a couple of ways of how to more dynamically fill Slots. First, we're going to look at a way how to handle it. If the user says all the things in one go. What you can do, you have a toggle under advanced which says ''Skip if answer in Input'' this means we're going to not ask the question if the answer is already in the Input Object when the question is hit for the first time. If we activate this for all those questions here, we will see that we can give all answers in one go. So I could say my email is ... and I would like to come tomorrow for 30 minutes. None of the questions are asked because we're going through the questions that we find the answer in the Input Object already, and if we go into the Context, we can see all the answers are there. Now, that's, of course, fantastic, right? Because this gives a really good user experience.
Let's try to do something else here. We're going to clear this and we're going to leave one out. So we are going to leave the 30 minutes one out. It's now going to essentially skip the first, skip the second, and then it's going to end up at the third. And we can see in the Context, we already have email and date, but we don't have the third one yet. So now I would have to say ''30 minutes''. Also great, but what if I don't skip the last one? But I skip the second one. I skipped the second one in my input text, meaning I don't have the information for the second one. Now the first one is answered, the second one is not answered but what if I now answer the second one? It will ask me the third one and why is that? Because the third one hadn't been hit yet, so it has not been stored because it wasn't in the Input Object when this third question was hit.
So how do we handle that? We can handle that using the NLU and what we call Slot Fillers. But before we do that, we must activate another option in each of those Question Nodes which says ''Skip if answer already exist in Context'', so if the email key in the Context has already been said, this question is not going to be asked again. And here we're going to do the same. If a date has already been set in the Context, this question is skipped and if a duration has already been set in the Context, the date is skipped. Now, if we go into the NLU and we go to Slot Fillers, we can now create three Slot Fillers, which will fill those Slots dynamically throughout the whole conversation. So we're going to start with email. The email Slot Filler is of type email and the Context Key that we're going to fill is email. Here again, you have things like store also in Contact Profiles, ''Store Detailed Results'', etc but let's leave it at that for now. We create a second one, which was the date. So this name here is not what
it's what the key is. You know, the key is down here. In my example, they are coincidentally actually the same. But I could type anything in here, Date Slot Filler. And then here I would have the duration one that is Duration, and I'm going to save this under duration. Now, what these Slot Fillers do, they will fill those Slots whenever they are mentioned during the conversation. So if at any point during the conversation I'm mentioning a duration, then the duration key is written into the Context. If I say duration again later, it is overwritten. I can prevent that from happening by saying ''Skip if the result is already in Context'', then this Slot Fillers will not be triggered. A way to imagine this is if a user input comes in, we go through all the Slot Fillers first and then we go into the Flow. So we check, was a duration mentioned? Was a date mentioned? Was an email mentioned? And then we go into the Flow.
Now the behavior that we have created from this now - and let's actually turn off the Skip if already in Input to show that the effects don't come from that - is that we've now created a really comfortable way for the user to do this so we can come in and it asks for the email and we say ''I want to come for 30 minutes''. Now it is asking for when and if we look at the Context, we can see we have the duration and we have the email already that comes from the Slot Filler. Now, if I tell it when, I'm done. This answer now came actually also from the Slot Filler, but it could have also come from the question. And maybe to do this again, I could also say I want to come tomorrow for 30 minutes. It is going to ask me for my email address and then I pop in the email address and then I'm done. So we can really make Slot Filling extremely comfortable and convenient here for the customer by using a combination of Slot Fillers and Question Nodes.
And with that, I want to say thank you very much, I hope you learned a lot about our Question Nodes. Again, if you want to try it out for yourself, play around with the power of the Cognigy.AI Question Nodes, Slot Filling etc. Sign up for a trial account if you don't have one already and we're really looking forward to seeing what you are going to build with that. Thank you very much.
Thank you very much for watching our session on Question Nodes in Cognigy.AI. Please don't forget to visit our Help Center under support.cognigy.com for additional resources and information and a link to a community where you can ask questions or leave us feedback for this episode. Thank you very much for watching then see you next time.