VAD, Backchanneling, Sentiment Routing으로 CSAT 향상

발행: (2025년 12월 13일 오후 03:38 GMT+9)
5 min read
원문: Dev.to

Source: Dev.to

TL;DR

대부분의 음성 AI 에이전트는 고객의 말을 중간에 끊거나 감정 신호를 놓쳐 CSAT 점수가 크게 떨어집니다.
해결책:

  • Voice Activity Detection (VAD) 은 잘못된 턴 획득을 방지합니다.
  • Backchanneling (“mm‑hmm”, “I see”) 은 끊지 않고도 적극적인 경청을 표시합니다.
  • Sentiment routing 은 화난 발신자를 화를 내기 전에 에스컬레이션합니다.

VAPI의 VAD 설정 + Twilio의 콜 라우팅으로 구현했습니다.
결과: 에스컬레이션 40 % 감소, CSAT 점수 25 % 상승. 불필요한 내용 없이 실제 운영에 바로 적용 가능한 패턴만 제공합니다.

Prerequisites

API Access

  • VAPI API 키 (dashboard.vapi.ai에서 발급)
  • Twilio Account SID + Auth Token (console.twilio.com에서 확인)
  • Voice 기능이 활성화된 Twilio 전화번호

Technical Requirements

  • Node.js 18+ (async/await 및 native fetch 지원)
  • 웹훅용 공개 HTTPS 엔드포인트 (예: 로컬 개발 시 ngrok)
  • SSL 인증서 (Twilio는 HTTP 웹훅을 거부합니다)

System Dependencies

  • 동시 호출당 최소 512 MB RAM (VAD 처리 오버헤드)
flowchart TD
    B[VAD Detection] --> C{Silence > 800ms?}
    C -->|Yes| D[Inject Backchannel]
    C -->|No| E[Continue Listening]
    D --> F[Sentiment Analysis]
    E --> F
    F --> G{Score}
    G -->|Yes| H[Route to Human]
    G -->|No| I[AI Response]

VAD는 매 오디오 청크마다 트리거됩니다. 웹훅은 speech-update 이벤트와 부분 전사를 받아옵니다. 감정 분석은 완전한 발화에만 수행해야 하며, “I’m fru…”와 같은 중간 전사는 잘못된 부정 결과를 초래합니다.

Real‑Time Sentiment Routing

핵심 포인트: 대화가 흐트러지기 전에 실시간으로 감정을 분석하고 라우팅을 트리거하는 웹훅 핸들러입니다.

const express = require('express');
const app = express();

function analyzeSentiment(transcript) {
  const negativeKeywords = {
    'frustrated': -0.3,
    'angry': -0.5,
    'terrible': -0.4,
    'useless': -0.6,
    'cancel': -0.7,
    'manager': -0.8
  };

  let score = 0;
  const words = transcript.toLowerCase().split(' ');
  words.forEach(word => {
    if (negativeKeywords[word]) score += negativeKeywords[word];
  });

  return Math.max(score, -1.0); // Cap at -1.0
}

app.post('/webhook/vapi', async (req, res) => {
  const { message } = req.body;

  if (message.type === 'transcript' && message.transcriptType === 'final') {
    const sentiment = analyzeSentiment(message.transcript);

    // Inject backchannel if user paused mid‑sentence
    if (message.silenceDuration > 800 && sentiment > -0.3) {
      return res.json({
        action: 'inject-message',
        message: 'mm-hmm'   // Non‑verbal acknowledgment
      });
    }

    // Route to human if sentiment tanks
    if (sentiment <= -0.5) {
      return res.json({
        action: 'transfer',
        target: 'human_agent'
      });
    }
  }

  res.sendStatus(200);
});
sequenceDiagram
    participant VAPI
    participant User
    participant Webhook
    participant Server

    VAPI->>User: Plays welcome message
    User->>VAPI: Provides input
    VAPI->>Webhook: transcript.final event
    Webhook->>Server: POST /webhook/vapi with user data
    alt Valid data
        Server->>VAPI: Update call config with new instructions
        VAPI->>User: Provides response based on input
    else Invalid data
        Server->>VAPI: Send error message
        VAPI->>User: Error handling message
    end
    Note over User,VAPI: Call continues or ends based on user interaction
    User->>VAPI: Ends call
    VAPI->>Webhook: call.completed event
    Webhook->>Server: Log call completion

Testing & Validation

Local Testing

VAPI CLI와 ngrok을 사용해 로컬에서 웹훅을 테스트합니다. 이는 프로덕션 전 통합 버그의 약 80 %를 사전에 발견할 수 있게 해줍니다.

# Terminal 1: Start your Express server
node server.js   # runs on port 3000

# Terminal 2: Forward webhooks to local server
npx @vapi-ai/cli webhook forward --port 3000
// Example snippet inside server.js for local testing
app.post('/webhook/vapi', async (req, res) => {
  const { message } = req.body;

  if (message?.type === 'transcript') {
    const sentiment = analyzeSentiment(message.transcript);
    console.log(`[TEST] Transcript: "${message.transcript}"`);
    console.log(`[TEST] Sentiment Score: ${sentiment}`);
    // Add any additional debug actions here
  }

  res.sendStatus(200);
});

위 과정을 실행하고 CLI를 통해 샘플 전사를 전송한 뒤 다음을 확인합니다:

  1. 설정된 침묵 시간 이후에만 백채널이 삽입되는지.
  2. 감정 점수가 에스컬레이션 임계값 이하일 때 콜이 인간 에이전트에게 전달되는지.
  3. 레이스 컨디션이 발생하지 않는지 (서버 로그에 전사당 하나의 액션만 기록되어야 함).

로컬 검증이 끝나면 웹훅을 프로덕션 HTTPS 엔드포인트에 배포하고 Twilio Voice 웹훅 URL을 업데이트합니다. 이후 실시간 메트릭(에스컬레이션 비율, 평균 CSAT, 지연 시간)을 모니터링하세요.

Back to Blog

관련 글

더 보기 »