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

如何基于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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 04:18:21