You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP Laravel中Twilio来电转接遇语音信箱的处理方案咨询

解决方案:Twilio Dial转接时避开语音信箱直接录制留言(无需队列)

针对你遇到的问题,这里提供几个无需修改现有转接流程、不用Twilio队列的可行方案:

方案1:短超时+外呼AMD验证(推荐)

核心思路是先通过短超时的Dial快速判断客服是否接听,若超时则发起外呼并开启AMD(外呼支持AMD),根据AMD结果决定是桥接通话还是引导留言:

代码实现(Laravel)

// 处理来电的初始路由
Route::post('/twilio/incoming', function (Request $request) {
    $twiml = new Twiml();
    
    // 设置15秒超时(语音信箱通常在响铃4-6声后触发,15秒约3-4声)
    $dial = $twiml->dial([
        'timeout' => 15,
        'action' => route('twilio.dial-callback'),
        'method' => 'POST'
    ]);
    $dial->number(env('SUPPORT_PHONE'));
    
    return response($twiml)->header('Content-Type', 'application/xml');
});

// Dial结果回调路由
Route::post('/twilio/dial-callback', function (Request $request) {
    $twiml = new Twiml();
    $dialStatus = $request->input('DialStatus');
    $parentCallSid = $request->input('CallSid');

    switch ($dialStatus) {
        case 'busy':
            // 占线直接引导留言
            $twiml->say('当前客服繁忙,请留下您的留言,结束后按#号键。');
            $twiml->record([
                'action' => route('twilio.save-voice-mail'),
                'finishOnKey' => '#',
                'method' => 'POST'
            ]);
            break;
        case 'no-answer':
            // 发起外呼到客服,开启AMD检测
            $client = new Client(env('TWILIO_SID'), env('TWILIO_TOKEN'));
            $outboundCall = $client->calls->create(
                env('SUPPORT_PHONE'),
                env('TWILIO_PHONE'),
                [
                    'url' => route('twilio.amd-welcome'),
                    'machineDetection' => 'Enable',
                    'statusCallback' => route('twilio.amd-result', ['parentSid' => $parentCallSid]),
                    'statusCallbackEvent' => 'completed',
                    'method' => 'POST'
                ]
            );

            // 给来电者播放等待提示
            $twiml->say('请稍候,我们正在确认客服状态...');
            $twiml->redirect(route('twilio.wait-for-amd', ['callSid' => $outboundCall->sid]));
            break;
        default:
            // 其他状态直接挂断
            $twiml->hangup();
    }

    return response($twiml)->header('Content-Type', 'application/xml');
});

// 外呼客服的欢迎语路由
Route::post('/twilio/amdd-welcome', function () {
    $twiml = new Twiml();
    $twiml->say('请稍候,有来电转接...');
    return response($twiml)->header('Content-Type', 'application/xml');
});

// AMD结果处理路由
Route::post('/twilio/amd-result', function (Request $request) {
    $parentCallSid = $request->input('parentSid');
    $amdResult = $request->input('AnsweredBy');
    $targetCallSid = $request->input('CallSid');
    $client = new Client(env('TWILIO_SID'), env('TWILIO_TOKEN'));

    if ($amdResult === 'machine_start') {
        // 检测到语音信箱,引导原来电者留言
        $client->calls($parentCallSid)->update([
            'url' => route('twilio.record-voice-mail'),
            'method' => 'POST'
        ]);
    } elseif ($amdResult === 'human') {
        // 真人接听,桥接两个通话
        $client->calls($parentCallSid)->update([
            'url' => route('twilio.bridge-call', ['targetSid' => $targetCallSid]),
            'method' => 'POST'
        ]);
    }

    return response()->json(['status' => 'processed']);
});

// 留言录制路由
Route::post('/twilio/record-voice-mail', function () {
    $twiml = new Twiml();
    $twiml->say('当前客服无法接听,请留下您的留言,结束后按#号键。');
    $twiml->record([
        'action' => route('twilio.save-voice-mail'),
        'finishOnKey' => '#',
        'method' => 'POST'
    ]);
    return response($twiml)->header('Content-Type', 'application/xml');
});

// 通话桥接路由
Route::post('/twilio/bridge-call', function (Request $request) {
    $twiml = new Twiml();
    $dial = $twiml->dial();
    $dial->call($request->input('targetSid'));
    return response($twiml)->header('Content-Type', 'application/xml');
});

方案2:实时音频流检测语音信箱

利用Twilio Stream API获取Dial通话的实时音频流,通过自定义音频分析或第三方语音识别服务检测语音信箱特征音/关键词,一旦识别到立即终止Dial并跳转留言流程:

核心步骤

  1. 在Dial时开启Stream,指定你的WebSocket服务地址接收音频流
  2. WebSocket服务实时处理音频数据,识别是否出现语音信箱提示(比如“请留言”“您拨打的用户暂时无人接听”等关键词)
  3. 检测到语音信箱后,调用Twilio API挂断当前Dial通话,触发action回调进入留言流程

初始路由示例

Route::post('/twilio/incoming', function (Request $request) {
    $twiml = new Twiml();
    
    $dial = $twiml->dial([
        'action' => route('twilio.dial-callback'),
        'stream' => [
            'url' => 'wss://your-laravel-server.com/twilio-audio-stream',
            'track' => 'both_tracks'
        ]
    ]);
    $dial->number(env('SUPPORT_PHONE'));
    
    return response($twiml)->header('Content-Type', 'application/xml');
});

注:WebSocket服务需要自己实现,可结合Google Speech-to-Text等API进行实时语音识别。

方案3:调整客服号码的语音信箱设置(非技术方案)

  • 如果客服使用的是Twilio号码:在Twilio控制台关闭该号码的语音信箱功能,设置无人接听时直接挂断,这样Dial会返回no-answer状态,直接进入留言流程。
  • 如果是外部运营商号码:联系运营商调整语音信箱的响铃触发次数(比如设置为10次以上),让Dial在语音信箱启动前就超时,触发留言流程。

内容的提问来源于stack exchange,提问作者Muhammad Yaseen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 07:45:51