Hi, one possible way to accomplish that would be the following:
So this means you
have one action action_human_handoff like you suggest above. In addition to what it does already, have it set a slot like handoff_active.
add a policy like described in the post I linked
And then for sending messages back and forth between the user and the human support, you could implement another custom action like action_talk_to_human which your policy always predicts while the handoff_active slot is set.
The action action_talk_to_human could e.g. use the Slack API for sending messages to send the last message from the user as a reply to the thread that was started by action_human_handoff, use the Slack API for retrieving messages to get the answer that is sent by the human support, and then forward this answer to the user.
Once the hand-off is no longer required, the human support should send a specific message, e.g. /handback. The action action_talk_to_human needs to recognise this and unset the slot handoff_active.
Hope that helps, let me know if you have more questions.
Thanks for the detailed instructions, this is the best approach to handle the human hand-off so far. I was exploring the looped FollowupAction path and quickly realized it would be overridden with new user input.
I will work on this too and will share my implementation once done.
My case: I have connected my bot with MS Teams and when the user request for human agents, the chat will be queued up in service now chat dashboard for the agents to pick it up.
For future readers, this is the path I have taken so far:
User types ‘talk to live agent’ or something similar.
The custom action action_live_agent creates a live support chat in service now and sets the handoff_active to true. It also sets slots like live_chat_id (live chat id), live_chat_user (user_id to differentiate messages between agent and user), and live_chat_last_updated (timestamp of the last sent message to compare and only get the new messages later).
The custom handoff policy HandoffPolicy with the highest priority checks handoff_active slot and predicts action action_live_agent_chat until handoff_active slot is set to false.
action_live_agent_chat will post user messages to the live chat using live_chat_id. It will then do the following in order:
Check user message if message == "/restart" or message == '/end_chat'. If true, it will end the live chat by calling leave chat API and set slots handoff_active, live_chat_id, and live_chat_last_updated to None. HandoffPolicy will then stop predicting the custom action and bot will start handling responses. Ref. Screenshot 1.
If user message is not ‘/restart’ or ‘/end_chat’, the custom action will post the latest message to live agent chat thread and will retrieve the message thread.
It will loop through the message thread. If the message creator is not live_chat_user and message timestamp is greater than live_chat_last_updated, it will utter the messages to the end-user. After uttering the messages to the end-user, it will set live_chat_last_updated to the timestamp of the latest message in the thread. Ref. Screenshot 2.
It will then check if the received message contains the text has closed the support session (this is a part of the message that is sent once the live agent ends the chat session). If true, it will end the live chat by calling leave chat API and set slots handoff_active, live_chat_id, and live_chat_last_updated to None. Ref. Screenshot 3.
If any of the API calls (posting/retrieving messages) throws an error, it will end the live chat by calling leave chat API and set slots handoff_active, live_chat_id, and live_chat_last_updated to None. It will utter message with details like (chat summary, chat id, last updated). If there is an error in calling leave chat API, it will set slots handoff_active, live_chat_id, and live_chat_last_updated to None and utter generic message like “The chat session is closed/could not be located. Please try reconnecting to live agent if you still need help!”
First, I just want to say thank you for posting a detailed description of your implementation. It was a great reference for the development of my own solution.
As far as your API Polling question. I’m currently using Slack for my implementation, which offers an Events API with a configurable Callback URL.
I set that endpoint up in the Rasa Server, which is essentially a modified version of the execute_action() function associated with the “/conversations/<conversation_id>/execute” endpoint.
It checks to make sure that the message isn’t from the bot, then parses the sender_id (associated with the parent message of the Slack thread), and fetches the tracker. It then calls for a custom action to execute, that I setup to retrieve the most recent message and emit it to the tracker’s output channel.
This way, there is no polling. The endpoint receives a request when a new message is posted in the Slack channel, and then the action executes.
I’m not familiar with the Teams APIs, but it looks like this might offer some similar functionality:
I think it’s not a good approach to use Rasa as the centralized messaging router. It’s not designed to play this role. Even if you implement the suggested solution, your tracker store will contain conversations that are unrelated to the domain of the bot.
Instead, there should be a client UI that switches between Rasa and other services (Slack, another Rasa bot, etc). The action would send a message that the client UI recognizes as a transfer (via slot metadata) and pauses the conversation. The UI then connects to Slack or some other service.
Hey Niraj, thanks for this post. It’s very helpful. Could you share the code for your policy? I’ve been trying to implement a policy that predicts an action when a slot is set but haven’t been having much luck
In your custom policy __init__ method, set the priority to highest int value (depends on your config and the priority for other policies). e.g. priority: int = <set to highest int value> and handoff_action_name: Text = "action_live_agent_chat".
In predict_action_probabilities method, predict the handoff_action if tracker.get_slot('handoff_active') is True.
We recently added an enhancement to the chatroom Rasa widget here and we documented it’s use in the example helpdesk-assistant here.
It is an example of what you show above without the use of a Router or Handoff DB. When the user requests a transfer, the Rasa response can include slots or metadata that is passed to the UI component. In the example implementation, it passes the URL to another Rasa chatbot but you could add your own metadata.
I ended up creating Webhook to push human messages to the bot using MS Teams API directly (as MS Teams is the front end for me). The messages from the user are pushed out to the human agent using rasa custom action & handoff policy and the human agent reply triggers webhook response directly to the front end.
I followed this route to record the user messages as to why the human agent was requested and we do a weekly review to include those use-cases in the bot itself. This has helped us with the CDD tremendously.