
本文介绍如何利用 twilio 的 answering machine detection(amd)功能,在 javascript 外呼场景中准确区分被叫方挂断、无人接听、接听后立即挂断,以及真正接入语音信箱等状态,从而实现精细化呼叫流程控制。
本文介绍如何利用 twilio 的 answering machine detection(amd)功能,在 javascript 外呼场景中准确区分被叫方挂断、无人接听、接听后立即挂断,以及真正接入语音信箱等状态,从而实现精细化呼叫流程控制。
在使用 Twilio Voice SDK 进行外呼(outbound call)时,一个常见痛点是:无法可靠感知被叫方是否主动拒接(如点击红色挂断按钮)、是否未接听直接转语音信箱,还是被自动应答机/语音信箱截获。与入呼(incoming)不同,Twilio 的 reject 或 cancel 事件仅适用于被叫端(callee)接收的来电,对外呼发起方(caller)完全不可见——这意味着你无法仅靠客户端 SDK 的事件监听来判断“对方是否拒接”。
真正的解决方案在于服务端驱动的 Answering Machine Detection(AMD)。AMD 是 Twilio 提供的一项语音分析能力,它在呼叫接通后的最初几秒内实时分析音频特征(如静音时长、提示音模式、语速语调),并返回权威判定结果:human(真人接听)、machine(语音信箱/应答机)或 fax(传真)。该机制不依赖被叫设备行为,而是基于媒体流分析,因此能稳定覆盖 iOS/Android 各类系统拒接逻辑(包括快速挂断、勿扰模式、自动转语音信箱等场景)。
✅ 正确实现步骤
-
启用 AMD 并配置回调 URL
在服务端发起外呼时,必须显式设置machineDetection: 'Enable',并指定url(指向你的 TwiML 处理端点)。Twilio 将在 AMD 判定完成后,向该 URL 发送携带AnsweredBy参数的 POST 请求:
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = require('twilio')(accountSid, authToken);
client.calls.create({
machineDetection: 'Enable', // 必须启用
url: 'https://your-domain.com/twiml/amd-handler', // 接收 AMD 结果的 endpoint
to: '+1562300000',
from: '+18180000000',
timeout: 30 // 建议设为 30 秒,避免过早超时
})
.then(call => console.log('Call SID:', call.sid))
.catch(err => console.error('Call failed:', err));
-
在回调端点解析 AMD 结果
当 Twilio 回调你的url时,请求体中将包含关键字段:-
AnsweredBy: 值为"human"、"machine"、"fax"或"unknown" -
CallSid: 对应本次呼叫唯一标识 -
CallStatus: 如"in-progress"(此时已接通但尚未判定)或"completed"
示例 Node.js Express 处理逻辑:
-
app.post('/twiml/amd-handler', (req, res) => {
const answeredBy = req.body.AnsweredBy;
const callSid = req.body.CallSid;
console.log(`AMD result for ${callSid}: ${answeredBy}`);
if (answeredBy === 'human') {
// 真人接听 → 播放业务语音或连接通话
res.type('text/xml');
res.send(`
<response><say voice="alice">Hello! This is your appointment reminder.</say></response>
`);
} else if (answeredBy === 'machine') {
// 语音信箱 → 可播放简短留言,或记录为“转语音信箱”
res.type('text/xml');
res.send(`
<response><say voice="alice">Hi, this is an automated reminder. Please call back.</say></response>
`);
} else if (answeredBy === 'unknown') {
// 未成功判定 → 视为未接通,可重试或标记异常
console.warn(`AMD uncertain for ${callSid}`);
}
});
⚠️ 关键注意事项
-
AMD 不是实时事件,而是异步判定:从呼叫接通到收到
AnsweredBy回调通常需 2–8 秒,期间CallStatus仍为"in-progress"。请勿在客户端轮询或依赖即时响应。 -
machineDetection: 'DetectMessageEnd'更激进:若需更早触发(如检测到语音信箱提示音末尾即结束),可选用此模式,但误判率略高;生产环境推荐默认'Enable'。 -
客户端 SDK 无法替代 AMD:Voice SDK 的
disconnect事件仅表示本地连接终止(可能因网络、权限或用户操作),不能等同于“被拒接”。所有业务级状态判定必须以服务端 AMD 结果为准。 - 合规性提醒:在语音信箱中留言前,请确保符合当地法规(如 GDPR、TCPA),必要时加入用户同意机制。
通过合理配置 AMD 并处理其回调,你就能在 Twilio 外呼中可靠识别“被拒接”与“转语音信箱”的本质差异,进而驱动智能重拨、动态话术、CRM 状态同步等高级场景——这才是面向生产环境的健壮方案。










