This topic introduces how to implement human takeover to hand off a conversation from an AI agent to a human agent.
What is human takeover?
Human takeover is a process of handing off an end-user conversation from an AI agent (such as a chatbot) to a human agent, especially when the AI agent cannot satisfy the user needs or handle complex situations.
The transition can be initiated based on predefined rules, user requests, or large language model (LLM) analysis. This ensures a well-timed human intervention.
Limitations
To use this feature, submit a ticket and provide your workflow ID. Alibaba Cloud will configure the workflow to support human takeover.
After a human agent takes over, users cannot switch back to the AI agent.
How it works
The following figure shows how a conversation is handed off to a human agent:
Note the details of these three steps:
Trigger human takeover (Step 5):
Initiated by the user: If the user requests human takeover, a notification is sent to the human agents (Step 7).
Determined by LLM: To enable the LLM to analyze whether human takeover is needed, you must train your own LLM. This feature can be implemented through a custom plug-in in Alibaba Cloud Model Studio.
Notify human agents (Step 7): Implement a mechanism to notify human agents for a takeover. The mechanism involves communication between the LLM, app server, and web side. You must build it yourself.
Take over the AI agent (Step 8): After a human agent takes over the AI agent, they must receive transcripts of the previous communication from the AI agent. The following section shows how this works.
Human agent-side implementation
Detailed process
Join the channel
The human agent-side calls TakeoverAIAgentCall.
The RTC token and other information are returned for joining the channel.
The human agent joins the channel based on the returned information and starts to push and pull the streams. They receive transcripts of the previous communication from the AI agent.
For more information, see Get started with ARTC SDK for Web
Sample code for receiving transcripts from the AI agent:
Listen for the event.
aliRtcEngine.on('dataChannelMsg', (uid, msg) => { try { const dataChannelMsg = JSON.parse(new TextDecoder().decode(msg.data)); if (dataChannelMsg.type === 1002) { // Receive transcripts of the AI agent. Data structure: // text: The transcribed text. // sentenceId: The sentence ID. During streaming, the words are sent to the system piece by piece. This ID is used to identify which sentence different pieces belong to. // end: A tag that indicates whether the current piece is the final segment of the sentence. console.log('agentSubtitleNotify', dataChannelMsg.data); } else if (dataChannelMsg.type === 1003) { // Receive transcripts of the user. Data structure: // text: The transcribed text. // sentenceId: The sentence ID. During streaming, the words are sent to the system piece by piece. This ID is used to identify which sentence different pieces belong to. // end: A tag that indicates whether the current piece is the final segment of the sentence. console.log('userSubtitleNotify', dataChannelMsg.data); } else { // Ignore other types of messages } } catch(error) { console.error(error) } });Before joining the channel, call the
aliRtcEngine.setParametermethod to enable the capability for receiving the transcripts.aliRtcEngine.setParameter( JSON.stringify({ data: { enableSubDataChannel: true, }, }), );
Advanced settings
Subscribe to content on-demand
By default, a human agent subscribes to content of all users in the channel, including the end user and AI agent. So, they will receive the audio and video streams from the end user and the speech-to-text recognition results from the AI agent.
If content from the AI agent is not required, subscribe to only the audio and video streams from the end user by performing the following steps:
Before joining the channel, call
setDefaultSubscribeAllRemoteAudioStreamsto disable automatic subscription.// Disable automatic subscription to audio streams. aliRtcEngine.setDefaultSubscribeAllRemoteAudioStreams(false); // Disable automatic subscription to video and screen-sharing streams. aliRtcEngine.setDefaultSubscribeAllRemoteVideoStreams(false);Call
subscribeRemoteMediaStreamto subscribe to a specific user.// Import AliRtcVideoTrack enum via npm. import { AliRtcVideoTrack } from 'aliyun-rtc-sdk'; // You can also import it from the window object. // const AliRtcVideoTrack = window.AliRtcEngine.AliRtcVideoTrack; // Specify the ID of the user you want to subscribe to. const subscribeUserId = 'xxxx'; // Set up an event listener for when a user comes online (remoteUserOnLineNotify) and subscribe to the joined user. // Decide whether to subscribe to a user based on your business logic. aliRtcEngine.on('remoteUserOnLineNotify', (userId) => { if (userId === subscribeUserId) { // Subscribe to all streams of the user (audio, video, and screen-sharing). The system does not prompt an error if the user does not ingest certain streams. // Future streams added by the user will be automatically subscribed to. aliRtcEngine.subscribeRemoteMediaStream( userId, AliRtcVideoTrack.AliRtcVideoTrackBoth, true, true ); } }); // Subscribe to a user already in the channel. if (aliRtcEngine.getOnlineRemoteUsers()?.includes(subscribeUserId)) { // Subscribe to all streams of the user (audio, video, and screen-sharing). The system does not prompt an error if the user does not ingest certain streams. // Future streams added by the user will be automatically subscribed to. aliRtcEngine.subscribeRemoteMediaStream( userId, AliRtcVideoTrack.AliRtcVideoTrackBoth, true, true ); }
Inform users about human takeover
You can obtain the status of human agents during the takeover process through callbacks and provide real-time feedback to users.
To notify the user that the conversation is handed off to a human agent, implement the callback interfaces onHumanTakeoverWillStart and onHumanTakeoverConnected. Sample code:
The client must use AICallKit SDK V1.5.0 or later.
Android
// Callbacks (for reference only)
ARTCAICallEngine.IARTCAICallEngineCallback mCallEngineCallbackWrapper = new ARTCAICallEngine.IARTCAICallEngineCallback() {
@Override
public void onHumanTakeoverWillStart(String takeoverUid, int takeoverMode) {
// When the transition is about to start.
}
@Override
public void onHumanTakeoverConnected(String takeoverUid) {
// When the human agent has successfully taken over.
}
// Other callbacks.
...
};iOS
extension AUIAICallStandardController: ARTCAICallEngineDelegate {
public func onHumanTakeoverWillStart(takeoverUid: String, takeoverMode: Int) {
// When the transition is about to start.
debugPrint("AUIAICallStandardController onHumanTakeoverWillStart:\(takeoverUid) , takeoverMode:\(takeoverMode)")
}
public func onHumanTakeoverConnected(takeoverUid: String) {
// When the human agent has successfully taken over.
debugPrint("AUIAICallStandardController onHumanTakeoverConnected:\(takeoverUid)")
}
// Other callbacks.
...
}Web
engine.on('humanTakeoverWillStart', (uid: string, mode: number) => {
// When the transition is about to start.
console.log('AICallHumanTakeoverWillStart', uid, mode);
});
engine.on('humanTakeoverConnected', (uid: string) => {
// When the human agent has successfully taken over.
console.log('AICallHumanTakeoverConnected', uid);
});
