如何使用 VAPI 部署 AI 语音代理进行客户支持

发布: (2025年12月4日 GMT+8 16:45)
6 分钟阅读
原文: Dev.to

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

  1. 在 VAPI 仪表板中,找到您的助理的电话设置。
  2. 在 Twilio 控制台 → Phone NumbersBuy NumberConfigure Webhook
  3. 将入站 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.

Back to Blog

相关文章

阅读更多 »