Reputation: 478
I want to make a simple quote bot which needs to know about addresses and dimensions. Currently I have hacked one together with a python state machine and rasa NLU for the intent stuff, though the nature of the data means most of the entities are better extracted by hand.
For example, an opening sentence might be "i want to send 4 boxes from A postcodeA to B postcodeB they're 3 by 3 by 3m each". These addresses need to be validated, which may involve a back and forth (did you mean this postcode, or maybe that state? This isn't a valid match, please choose from this list, etc...).
Additionally, the order of the validation might be weird. For example, one could have a suburb, postcode, and is_valid slot. There are several possibilities: they could enter a valid S + P, just S, an invalid S alone, a valid S and P which are individually valid but not a match, etc. In some cases I want to defer validation to make use of other information, for example if an invalid suburb was given but a valid postcode, i would use the postcode to inform suggestions for the correct suburb. However, if an invalid suburb was given but no postcode, there is no point asking for a postcode because i would want to get a valid suburb first. In this way having a slot ordering of 'suburb', 'postcode', 'is_valid' doesn't quite cut it as far as i can tell.
I suppose the validation call for suburb and postcode can just have their own set of switch statements which look at the other slots which may have been filled at the same time? Seems a bit chicken and egg, as would need to wait for validation of those as well, and may end up requiring calling Lambda's from within Lambda's. For example, if the validation fails, the bot asks for more info, but the validation of that info may require a different process/lambda than the original input
It could also be they don't include any details about the object, in which case it needs to be prompted for later after the address stuff is all sorted out. For example, if they fail to include info about dimensions i want to ask 'what're the dimensions' and allow them to either include just measurements or weights and quantities as well - this i understand as standard slot filling.
So my question is: how difficult/reasonable is it to have validation calls in Lambdas actually lead to side-paths in the conversation? Previously i had done something like this in a slot-filling setting by having 'is_valid' slots all over the place (especially if I don't want to simply throw an 'isn't valid' error and robotically re-ask the original question'). Is there a better way?
Also, how would one manage 'interrupt' intents? That is, a set of intents which would trigger 'do you want to go restart?' kind of questions, which will return to the original state if the user replies 'no', and, ideally, if they say yes can return to a specific point in the conversation (which i imagine would be achieved by just resetting appropriate slots to empty)
Also, not wedded to the idea of Amazon Lex, any of the pre-canned cases which reduce amount of boiler plate code are good too.
Apologies for word vomit.
Upvotes: 2
Views: 548
Reputation: 3277
Wow, ok here's what I can offer:
how difficult/reasonable is it to have validation calls in Lambdas actually lead to side-paths in the conversation?
Building a complex validation and conversation algorithm is standard practice for Lex Developers of service bots. So it is very reasonable to expect to have to do that yourself either in Lambda, or somewhere else and just use Lambda as a go-between. So the difficulty lies in your hands, and maybe you can find APIs that you can use to validate addresses and postal codes like Google Maps to make that part easier.
Previously i had done something like this in a slot-filling setting by having 'is_valid' slots all over the place (especially if I don't want to simply throw an 'isn't valid' error and robotically re-ask the original question'). Is there a better way?
Lex does have a better way: sessionAttributes
! A good practice is to only create slots for holding the values you need to fulfill each intent. For anything else, you can happily rely on sessionAttributes
to keep track of the conversation path, slot validity, slot history, intent history, interruption intents, etc, etc, etc, as much as you can imagine. It's completely up to you how to organize your bot logic and keep track of current and past states of the convo there.
For example: You could have slot: postalCodeA
And in sessionAttributes
also have: postalCodeA_valid
, postalCodeA_confirmed
, postalCodeA_attempts
etc.
And use those sessionAttributes
values to determine the conversation path in your logic. When you find a slot is invalid, you could save that value in an ..._attempts
or ..._history
list in sessionAttributes
, then set ..._valid
to false
, and reset the slot to null
, and re-elicit that slot with a message explaining why it was invalid, or try to elicit an address slot instead of a postal code slot.
Also, how would one manage 'interrupt' intents? That is, a set of intents which would trigger 'do you want to go restart?' kind of questions
As I hinted at earlier, the answer to this is also sessionAttributes
! When your user is inside of one intent (intentA), Lex will first attempt to fill the current elicit slot with their input, but if it doesn't match, Lex will also check if the input matches a different intent's utterances. So you could have an interrupt intent (intentB) with utterances like "let's start over", "nevermind", "back up", etc. Then in all of your normal intents, you keep a backup of that intent's slot values in sessionAttribtues
, as well as something like last_intent
to know where a user was previously in case it changes.
This would allow you to handle interrupt intents like this:
sessionAttributes
(Yes) intentB fulfills the intent after erasing intentA values from sessionAttributes
and returns user to start with elicitIntent
and asks "how else may I help you?"
(No) intentB passes the user back to intentA (which you know because you kept track of sessionAttributes.last_intent
) and send a confirmation of continuing with intentA with confirmIntent
: "Alright, I still remember where we left off, would you like to continue {intentA action}?" (the response will be sent to intentA, where you can handle that).
sessionAttributes
and uses other sessionAttributes
values to continue through your algorithm to the point where it left off, delivering the same elicit slot that it was last on, and the user is impressed with your bot's intelligence. =)Upvotes: 2