442ms 지연 시간을 달성한 음성 AI 플랫폼 구축기: 전체 아키텍처 공개
요약
특정 API 제공업체에 종속되지 않는 오픈 소스 음성 AI 플랫폼 Mithivoices의 아키텍처를 소개합니다. 추상화 계층과 설정 시스템을 통해 Piper, ElevenLabs, OpenAI 등을 자유롭게 교체하며 442ms의 초저지연 엔드 투 엔드 성능을 달성하는 방법을 다룹니다.
핵심 포인트
- 제공업체에 종속되지 않는 추상화 계층 설계의 중요성
- Piper, Whisper 등을 활용한 442ms 초저지연 달성
- LangGraph를 이용한 상태 유지 메모리 구현
- FastAPI와 Redis WebSocket 기반의 실시간 오디오 엔진
대부분의 음성 AI 튜토리얼은 "ElevenLabs API를 호출하세요"에서 끝납니다.
그것은 플랫폼이 아닙니다. ElevenLabs가 가격 정책을 변경하는 순간 무너지는 데모일 뿐입니다.
저는 30일 동안 Mithivoices를 구축하는 데 시간을 보냈습니다. 이는 19개 이상의 신경망 음성(Neural voices), 8개 언어(Hindi, Malayalam, Marathi 포함), 그리고 442ms의 엔드 투 엔드(End-to-end) 지연 시간을 갖춘 오픈 소스 TTS/STT 플랫폼입니다. 핵심 설계 결정 사항은 다음과 같습니다. 코드 수정 없이 설정(Config) 변경 한 번으로 Piper, ElevenLabs, OpenAI 또는 Coqui 사이를 전환할 수 있도록 하는 것입니다.
이것이 전체 아키텍처입니다. 필요한 부분을 가져가세요.
목차
- 클라우드 전용 음성 AI의 진짜 문제점
- 우리가 구축하고 있는 것
- 1단계: 추상화 계층 (Abstraction Layer)
- 2단계: 설정 시스템 (Config System)
- 3단계: 실시간 오디오 엔진 (Real-Time Audio Engine)
- 4단계: 상태 유지 메모리를 위한 LangGraph
- 5단계: 442ms를 달성한 방법
- 프로젝트 구조
- 실행 방법
- 다음에 구축할 것
- 내가 나 자신에게 해주고 싶은 세 가지 이야기
클라우드 전용 음성 AI의 진짜 문제점 {#the-real-problem}
모든 프로덕션(Production) 음성 시스템은 결국 동일한 벽에 부딪힙니다:
| 문제 | 발생하는 현상 |
|---|---|
| ElevenLabs가 가격을 3배 인상함 | 하룻밤 사이에 유닛 이코노믹스(Unit economics)가 붕괴됨 |
| ... |
해결책은 "최고의" 제공업체를 선택하는 것이 아닙니다. 제공업체가 중요하지 않게 만드는 추상화 계층(Abstraction layer)을 구축하는 것입니다.
우리가 구축하고 있는 것 {#what-were-building}
제공업체에 구애받지 않는(Provider-agnostic) 음성 AI 플랫폼:
- TTS: 기본적으로 로컬의 Piper TTS 사용 → 설정을 통해 ElevenLabs/OpenAI로 전환 가능
- STT: 기본적으로 로컬의 Whisper STT 사용 → 설정을 통해 클라우드 Whisper/Deepgram로 전환 가능
- 오케스트레이션 (Orchestration): 실시간 양방향 오디오를 위한 FastAPI + Redis WebSocket 엔진
- 메모리 (Memory): LangGraph 상태 유지 에이전트(Stateful agents) — 대화 문맥이 턴(Turn) 간에 유지됨
- 목표: 500ms 미만의 엔드 투 엔드(End-to-end) 지연 시간 (우리는 442ms를 달성했습니다)
1단계: 추상화 계층 (가장 중요한 부분) {#step-1-abstraction-layer}
이것을 가장 먼저 구축하세요. 다른 모든 것들이 여기에 연결됩니다.
# voice/base.py
from abc import ABC, abstractmethod
from dataclasses import dataclass
...
이제 Piper를 로컬 기본값으로 구현합니다:
# voice/providers/piper_tts.py
import asyncio
import tempfile
...
그리고 ElevenLabs를 즉시 교체 가능한 클라우드 옵션으로 추가합니다 — 동일한 인터페이스를 사용하여 앱의 코드 변경 없이 교체 가능합니다:
# voice/providers/elevenlabs_tts.py
import httpx
from voice.base import TTSProvider, TTSConfig
...
2단계: 설정 시스템 (모든 것을 제어하는 단 하나의 파일) {#step-2-config-system}
# config.yml — 제공자를 교체할 때 편집하는 유일한 파일
tts:
...
Provider factory(제공자 팩토리) — 설정에 따라 적절한 클래스를 로드합니다:
# voice/factory.py
import yaml
from voice.providers.piper_tts import PiperTTSProvider
...
각 제공자(
openai_tts.py,coqui_tts.py등)는 동일한TTSProvider인터페이스를 구현하는 개별 파일입니다. 전체 구현체는 리포지토리의backend/디렉토리에 있습니다.
3단계: 실시간 오디오 엔진 (FastAPI + Redis) {#step-3-audio-engine}
이곳이 지연 시간(Latency)의 성패가 결정되는 지점입니다. 양방향 스트리밍을 위한 WebSocket과 핸들러와 파이프라인 사이의 버퍼링을 위한 Redis를 사용합니다.
# backend/app/main.py
import json
import time
...
왜 인메모리(in-memory) 큐가 아닌 Redis를 사용했나요? 처음에는 인메모리 방식을 시도했습니다. 하지만 실제 부하가 발생하는 상황에서는 프레임 드랍(frame dropped)이 발생했습니다. Redis는 약 3ms의 지연 시간을 추가하지만, 동시 세션 환경에서 시스템을 프로덕션 수준으로 안정화해 줍니다.
4단계: 상태 유지 메모리를 위한 LangGraph {#step-4-langgraph}
이 기술이 없다면 매 턴(turn)은 새로운 대화가 됩니다. 이 기술을 통해 에이전트는 전체 세션 동안의 문맥(Context)을 기억할 수 있습니다.
# agents/conversation.py
from langgraph.graph import StateGraph, END
from langgraph.checkpoint.aioredis import AsyncRedisSaver
...
에이전트는 대화에서 벗어나 작업(예약 잡기, 데이터베이스 쿼리 등)을 수행한 뒤, Redis 체크포인팅(checkpointing)을 통해 전체 문맥을 유지하면서 결과와 함께 대화로 다시 돌아올 수 있습니다.
5단계: 어떻게 442ms를 달성했는가 {#step-5-442ms}
전체 지연 시간 분석 결과는 다음과 같습니다:
| 단계 | 시간 | 방법 |
|---|---|---|
| 오디오 수신 + Redis 버퍼 | ~10ms | 디스크 I/O를 완전히 배제 |
| ... |
가장 중요했던 두 가지 결정 사항은 다음과 같습니다:
1. LLM 추론을 위해 Groq 사용. 이들의 LPU 하드웨어는 이러한 워크로드에서 표준 GPU 추론보다 10~20배 더 빠릅니다. Groq와 일반적인 클라우드 LLM 엔드포인트 간의 차이는 평균 약 300ms입니다. 이는 로봇처럼 느껴지는 것과 대화하는 것처럼 느껴지는 것 사이의 격차입니다.
2. medium이 아닌 base Whisper 모델 사용. 정확도는 약 4% 떨어지지만, 지연 시간(Latency)은 약 110ms 감소합니다. 실시간 대화를 위해서는 이 트레이드오프(Trade-off)가 100% 옳습니다. 오프라인에서 전사(Transcript)를 사후 처리할 때는 언제든지 medium 모델을 실행할 수 있습니다.
프로젝트 구조 {#project-structure}
ai-voice-platform/
├── backend/
│ ├── app/
...
실행 방법 {#running-it}
# Clone
git clone https://github.com/mithivoices/ai-voice-platform
cd ai-voice-platform
...
프론트엔드: http://localhost:5173 · API: http://localhost:8000
사용 가능한 엔드포인트(Endpoints):
| 엔드포인트 (Endpoint) | 메서드 (Method) | 기능 |
|---|---|---|
/health | GET | 서버 상태 |
| ... |
다음에 구축할 것 {#what-to-build-next}
실행에 성공했다면 다음을 시도해 보세요:
- 힌디어 음성 에이전트 추가 — 설정에서
language: hi_IN으로 변경하면 힌디어 모델이 자동으로 다운로드됩니다. - 오프라인 배포 — Piper와 Whisper를 로컬에서 실행하여 인터넷 연결 없이 사용합니다. Raspberry Pi 5에서 작동합니다.
- 스트리밍 TTS (Streaming TTS) — 전체 응답을 기다리는 대신 오디오 청크(Chunk)가 합성되는 대로 스트리밍합니다.
- "act" 노드 추가 — LangGraph 에이전트를 캘린더 API, 데이터베이스 또는 예약 시스템에 연결합니다.
시작하기 전 나 자신에게 해주고 싶은 세 가지 {#three-things}
추상화를 먼저, 구현은 나중에. 첫 번째 시도에서 Piper를 WebSocket 핸들러에 직접 구축했습니다. 추상화 계층을 추가하기 위해 이를 뜯어내는 데 3일이 걸렸습니다. 구현을 시작하기 전에 인터페이스를 먼저 구축하세요.
지연 시간은 복리로 작용합니다. 한 단계에서 절약한 50ms는 단순히 50ms를 아끼는 것에 그치지 않습니다. 그것은 대화 전체의 느낌을 바꿉니다. 600ms와 442ms의 차이는 로봇 같은 느낌과 실제 같은 느낌의 차이입니다.
오디오 파이프라인 (Audio pipelines)에서 Redis는 타협할 수 없는 필수 요소입니다. 테스트 단계에서는 인메모리 큐 (In-memory queues)로도 충분히 작동합니다. 하지만 동시 세션 (Concurrent sessions)이 발생하는 환경에서는 프레임 드롭 (Drop frames) 현상이 발생합니다. Redis는 약 3ms의 지연 시간을 추가하지만, 시스템을 프로덕션 수준으로 안정화해 줍니다.
전체 소스 코드, 제품 요구 사양서 (PRD), 기술 요구 사양서 (TRD) 문서는 github.com/mithivoices/ai-voice-platform에서 확인할 수 있습니다.
이 플랫폼을 활용해 IVR 시스템, 힌디어 음성 비서, 오프라인 키오스크 등 무엇이든 만드셨다면 댓글로 알려주세요. 사람들이 실제로 무엇을 구현해내는지 보고 싶습니다.
음성 AI 파이프라인을 구축하며 마주친 가장 어려운 지연 시간 병목 현상 (Latency bottleneck)은 무엇이었나요?
이 기사는 AI의 도움을 받아 작성되었으며, Mithivoices를 구축하고 출시한 Aryan Panwar가 기술적 정확성을 검토했습니다.
📌 전체 케이스 스터디 및 프로젝트 분석은 aryanpanwar.in에서 확인하세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기