如何基于Twilio Functions与TwiML实现呼叫升级转接系统
Twilio Functions 实现呼叫逐级升级转接方案
全程基于你现有在用的Functions+TwiML栈实现,不需要额外接入其他服务,核心靠<Dial>动词的超时配置、状态回调能力就能跑通。
核心流转逻辑对齐
完全匹配你提的规则:
- 第一级:呼叫首个被叫号码,振铃12s(可在10-15s区间自行调整)未接听/拒接/不可达,自动转第二级
- 第二级:呼叫单个备用号码,同样振铃12s未接,自动转第三级
- 第三级:同时呼叫2-3个备用号码,任意号码接通后自动切断其他振铃,双方直接通话
- 三级都无人接听可走兜底逻辑(语音留言/挂断/短信通知均可)
具体实现步骤
1. 提前配置常量
你可以把各层级的被叫号码存在Twilio Functions的环境变量里,不用硬编码到代码里,后期调整号码不用改逻辑:
- 环境变量加
FIRST_NUMBER:首个被叫号码 - 环境变量加
SECOND_NUMBER:第二级单个备用号码 - 环境变量加
BACKUP_1/BACKUP_2/BACKUP_3:第三级并行呼叫的备用号码 - 统一设置振铃超时时间,建议默认12s,低于10s容易因为运营商接通用时导致误触发超时。
2. 编写核心处理Function
新建一个名为escalation-handler的Function,单函数即可处理所有层级流转,不用拆分多个接口,参考代码如下:
exports.handler = function(context, event, callback) { const twiml = new Twilio.twiml.VoiceResponse(); // 从请求参数获取当前呼叫所处的升级层级,来电初始默认是第1级 const currentLevel = parseInt(event.currentLevel || 1); const RING_TIMEOUT = 12; // 振铃超时时长,单位秒 // 层级路由配置 const routeMap = { 1: { numbers: [context.FIRST_NUMBER], nextLevel: 2 }, 2: { numbers: [context.SECOND_NUMBER], nextLevel: 3 }, 3: { numbers: [context.BACKUP_1, context.BACKUP_2, context.BACKUP_3], nextLevel: null // 最后一级无后续 } }; const currentRoute = routeMap[currentLevel]; // 层级配置异常走兜底 if (!currentRoute || currentRoute.numbers.some(n => !n)) { twiml.say('抱歉,当前所有坐席均无法接听,请稍后再拨'); twiml.hangup(); return callback(null, twiml); } // 组装Dial规则 const dialConfig = { timeout: RING_TIMEOUT, answerOnBridge: true, // 关键配置:被叫真正摘机才判定接通,避免被彩铃/语音信箱误截 }; // 本层级呼叫结束后,未接通就自动跳转到下一级 if (currentRoute.nextLevel) { dialConfig.action = `/escalation-handler?currentLevel=${currentRoute.nextLevel}`; } else { // 最后一级未接通走兜底 dialConfig.action = '/voicemail-handler'; } const dial = twiml.dial(dialConfig); // 把当前层级的所有号码加入Dial,传入多个号码时Twilio会自动并行振铃 currentRoute.numbers.forEach(phoneNum => { dial.number(phoneNum); }); return callback(null, twiml); };
如果需要最后一级的语音信箱逻辑,可以再加个简单的voicemail-handlerFunction:
exports.handler = function(context, event, callback) { const twiml = new Twilio.twiml.VoiceResponse(); twiml.say('所有坐席暂时无法接听,请在滴声后留言,我们会尽快回复'); twiml.record({ maxLength: 30, transcribe: false }); twiml.hangup(); return callback(null, twiml); };
3. 号码Webhook配置
把你Twilio号码的「来电呼叫」Webhook地址,直接绑定到escalation-handler的访问路径,请求方式选POST即可,不需要其他额外配置。
关键避坑点
- 第三级并行呼叫必须开
answerOnBridge: true,不然只要有一个号码触发了运营商彩铃/自动语音信箱,就会直接判定接通,掐断其他号码的振铃,导致真正的值班人员接不到电话 - 可以通过action回调带的
event.DialCallStatus参数做更细的规则:比如状态是busy(占线)、failed(不可达)的时候,不用等振铃超时,直接跳转到下一级,减少呼叫等待时间 - 不要把timeout设到15s以上,大部分运营商的默认未接超时是30s,设10-15s的区间能保证在运营商触发超时前完成转接
- 记得开Functions的Twilio请求校验,避免接口被恶意调用产生话费损失
可选优化
- 可以搭配Twilio Sync存储呼叫记录,避免同一个主叫短时间内反复触发升级流程
- 最后一级无人接听时,可以加一段发送短信的逻辑,把主叫号码推送给值班人员
- 可以加时段判断,工作时间走上述升级流程,非工作时间直接转值班手机或者语音信箱
内容的提问来源于stack exchange,提问作者Oliver
相关产品推荐
相关产品推荐

