Background: There are certain conversations where, at some point, we want to force the user to answer with a simple ‘yes’ or ‘no’. I know it is not ideal, but due to (unavoidable for now) latency, people already typed their next message when our answer to the previous one is still in flight. Or a simple ‘yes’ is accompanied by a lot of unnecessary information, leading to the wrong intent classification. This sends a lot of conversations unnecessarily off the rails.
We have found two methods of solving this. The first solution is in Rasa Core, the other in our action server.
The Rasa Core solution entails a form loop. At the point where the simple ‘yes’ or ‘no’ is required, we start an active loop and exit only when the ‘Yes’ or ‘no’ is given (obviously we also exit after x attempts, but that is not relevant).
What we need for that is the following rules/stories:
- rule: Actually cancel the order when the user says 'yes'
condition:
- active_loop: form_enforce_yes_or_no
steps:
- intent: confirm
- action: action_cancel_order
- active_loop: null
- story: Cancel order
steps:
- checkpoint: cancel_order_flow
- action: action_request_cancel_order
- active_loop: form_enforce_yes_or_no
- action: form_enforce_yes_or_no
- intent: confirm
- action: action_cancel_order
- active_loop: null
And an action to handle the yes/no loop, which will emit an action_execution_rejected event if the answer was not ‘yes’ or ‘no’.
This only handles the ‘yes’ part. Obviously for the ‘no’ a similar rule/story pair has to be created. And also for each instance where we want to enforce a yes/no. This gets quite verbose and it is very fragile, you have to do everything just right in terms of actions/loops/events/rules/conditions to make it work. It has taken me a lot of trial and error to get this working.
The second solution is to handle it purely in our action server. The mechanism is pretty simple. In the above example, the ‘action_request_cancel_order’ is what triggers the yes/no requirement. It does this by setting a slot with the two actions corresponding to the ‘yes’ and ‘no’ answer. When the user answers and Rasa Core executes the resolved action, we first check if the slot is set and if the action is in the list of allowed actions. If it is, we execute the action and reset the slot. If not, we emit a rewind event until the user gives one of the optional answers.
This second method has the advantage of having way less code and being more robust. We do not have to change any stories or code a custom solution for each instance where we want to enforce a general yes/no. But I find it less elegant because I feel it sort-of works against Rasa instead of with Rasa.
What do you feel? Is the second solution indeed the most optimal? Or is there maybe another that I overlooked?