如何使用 VAPI 部署 AI 语音代理进行客户支持
Source: Dev.to
抱歉,我需要您提供要翻译的具体文本内容。请粘贴文章的正文(除代码块和 URL 之外),我将为您翻译成简体中文,并保留原有的 Markdown 格式。
TL;DR
大多数语音代理在客户中途打断或通话量激增时会出现故障。本指南展示如何使用 VAPI 的原生语音基础设施和 Twilio 的运营商级电话系统构建可在生产环境使用的 AI 语音代理,以同时处理上述情况。预计响应时间低于 500 毫秒,具备正确的抢话(barging‑in)处理,并在 API 超时时自动故障切换。
技术栈
- VAPI – 语音 AI
- Twilio – 电话路由
- Webhook server – 业务逻辑集成
API Access & Authentication
- VAPI API 密钥 – 从
dashboard.vapi.ai获取 - Twilio 账户 SID 和 Auth Token – 来自
console.twilio.com - 已启用语音功能的 Twilio 电话号码
- OpenAI API 密钥 – 用于访问 GPT‑4 模型
开发环境
- Node.js 18+ 或 Python 3.9+
- ngrok(或类似的隧道工具)用于 webhook 测试
- Git 用于版本控制
技术要求
- 公共 HTTPS 端点用于 webhook 处理程序(生产环境)
- SSL 证书(Let’s Encrypt 可用)
- 服务器内存 ≥ 512 MB(推荐 1 GB)
- 稳定的互联网连接(实时音频上传 ≥ 10 Mbps)
Knowledge Assumptions
- REST API 集成经验
- Webhook 事件处理模式
- 对语音协议(SIP、WebRTC)的基本了解
- JSON 配置管理
成本意识
| 服务 | 约成本 |
|---|---|
| VAPI(模型 + 语音合成) | $0.05 – $0.10 每分钟 |
| Twilio(语音分钟) | $0.0085 每分钟 |
| Twilio 电话号码 | $1 / 月 |
架构概览
flowchart LR
A[Customer Calls] --> B[Twilio Number]
B --> C[VAPI Assistant]
C --> D[Your Webhook Server]
D --> E[CRM/Database]
E --> D
D --> C
C --> B
B --> A
Twilio 负责电话路由;VAPI 负责语音 AI。您的服务器通过 webhook 将它们桥接。保持这些职责分离,以避免幻音问题。
Assistant Configuration
const assistantConfig = {
name: "Support Agent",
model: {
provider: "openai",
model: "gpt-4",
temperature: 0.7,
systemPrompt: "You are a customer support agent. Extract: customer name, issue type, account number. If caller interrupts, acknowledge immediately and adjust."
},
voice: {
provider: "11labs",
voiceId: "21m00Tcm4TlvDq8ikWAM",
stability: 0.5,
similarityBoost: 0.75
},
transcriber: {
provider: "deepgram",
model: "nova-2",
language: "en",
endpointing: 255 // ms silence before considering speech ended
},
recordingEnabled: true,
serverUrl: process.env.WEBHOOK_URL,
serverUrlSecret: process.env.WEBHOOK_SECRET
};
Tip: endpointing = 255 毫秒是比较激进的,适用于快速的支持交互。如果在不稳定的移动网络上出现误判中断,请将其提升至 400 毫秒。
Webhook 服务器(Node.js + Express)
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
// Validate webhook signatures – production requirement
function validateSignature(req) {
const signature = req.headers['x-vapi-signature'];
const payload = JSON.stringify(req.body);
const hash = crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(payload)
.digest('hex');
return signature === hash;
}
app.post('/webhook/vapi', async (req, res) => {
if (!validateSignature(req)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const { message } = req.body;
try {
switch (message.type) {
case 'function-call':
// Example: fetch customer data from CRM
const customerData = await fetchCustomerData(message.functionCall.parameters.accountNumber);
res.json({ result: customerData });
break;
case 'end-of-call-report':
// Log call metrics
await logCallMetrics({
callId: message.call.id,
duration: message.call.endedAt - message.call.startedAt,
cost: message.call.cost,
transcript: message.transcript
});
res.sendStatus(200);
break;
case 'speech-update':
// Real‑time transcript for live‑agent handoff
if (message.status === 'in-progress') {
await updateLiveTranscript(message.call.id, message.transcript);
}
res.sendStatus(200);
break;
default:
res.sendStatus(200);
}
} catch (error) {
console.error('Webhook error:', error);
res.status(5xx).json({ error: 'Processing failed' });
}
});
app.listen(3000);
重要提示: VAPI 要求在 5 秒内返回响应。对于耗时较长的外部调用,请立即使用 res.sendStatus(202) 回复,并异步处理工作,随后通过 VAPI API 发送结果。
将 Twilio 连接到 VAPI
- 在 VAPI 仪表板中,找到您的助理的电话设置。
- 在 Twilio 控制台 → Phone Numbers → Buy Number → Configure Webhook。
- 将入站 webhook URL 设置为 VAPI 助理的电话端点(在 VAPI 仪表板中提供)。
对于外呼电话,请在创建或升级支持工单时以编程方式触发它们。
监控指标(前 100 次通话)
| 指标 | 目标 |
|---|---|
| 中断准确率 | > 95 % |
| 错误抢话 | 92 % |
| 转录准确率(嘈杂环境) | > 85 % |
如果中断准确率低于 90 %,将 endpointing 提高到 300 ms 并将语音 stability 降至 0.4,以实现更快的截断。
音频处理管道
graph LR
A[Microphone] --> B[Audio Buffer]
B --> C[Voice Activity Detection]
C -->|Speech Detected| D[Speech-to-Text]
C -->|No Speech| E[Error: Silence]
D --> F[Intent Detection]
F --> G[Response Generation]
G --> H[Text-to-Speech]
H --> I[Speaker]
D -->|Error: Unrecognized Speech| J[Error Handling]
J --> F
F -->|Error: No Intent| K[Fallback Response]
K --> G
本地测试使用 ngrok
# Start ngrok tunnel (run in terminal)
ngrok http 3000
示例 curl 测试 (Node.js 代码片段)
const crypto = require('crypto');
const fetch = require('node-fetch');
const testPayload = {
message: {
type: "function-call",
functionCall: {
name: "getCustomerData",
parameters: { customerId: "test-123" }
}
}
};
const hash = crypto
.createHmac('sha256', process.env.VAPI_SERVER_SECRET)
.update(JSON.stringify(testPayload))
.digest('hex');
fetch('https://your-ngrok-url.ngrok.io/webhook/vapi', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-vapi-signature': hash
},
body: JSON.stringify(testPayload)
})
.then(res => res.json())
.then(data => console.log('Webhook response:', data))
.catch(err => console.error('Webhook failed:', err));
注意: 免费 tier 的 ngrok URL 在 2 小时后会失效。每次重启后请在 VAPI 仪表盘中更新
serverUrl,以避免 404 错误。
签名验证
validateSignature 函数将请求负载的 HMAC‑SHA256 哈希与 x-vapi-signature 头部进行比较。签名不匹配时会返回 401 响应,从而防止重放攻击和未授权触发昂贵的 API 调用。
客户呼叫 → Twilio → VAPI → Your webhook → CRM/Database → (loop) → VAPI → Twilio → Customer.