
Python, LangChain, Whisper, Kokoro를 사용한 음성 대 음성 (Speech-to-Speech) AI 챗봇 구축하기
요약
Python, LangChain, OpenAI Whisper, Kokoro를 활용하여 로컬 환경에서 실행 가능한 음성 대 음성(Speech-to-Speech) AI 챗봇을 구축하는 가이드입니다. 음성 인식부터 LLM 추론, 텍MP 변환까지의 전체 파이프라인과 지속적인 대화 메모리 유지 방법을 다룹니다.
핵심 포인트
- OpenAI Whisper를 이용한 실시간 음성 인식 구현
- LangChain을 활용한 대화형 AI 및 지속적 메모리 관리
- Kokoro 라이브러리를 통한 자연스러운 TTS 합성
- 로컬 환경에서 실행 가능한 완전한 음성 비서 아키텍처 구축
여러분 중 많은 분과 마찬가지로, 저도 제가 하는 거의 모든 일에 매일 LLM (Large Language Models)을 사용합니다. 주제에 대한 콘텐츠를 생성하든, 코드의 버그를 해결하든, 문서를 요약하든, 혹은 그저 문제를 소리 내어 생각하든 말이죠. 하지만 때로는 질문을 프롬프트(Prompt)에 직접 타이핑해야 하는 귀찮음이 저를 괴롭히곤 합니다. 특히 제가 무엇을 말하고 싶은지 정확히 알고 있을 때 더욱 그렇습니다.
그 점이 저를 생각하게 만들었습니다: 만약 내가 그냥 말할 수 있다면 어떨까? 제약 사항과 주관이 담긴 세련된 상용 제품이 아니라, 내가 이미 사용하고 있는 도구들을 사용하여 직접 만든 무언가를 통해서 말이죠. 그래서 저는 제가 하는 말을 듣고, LLM을 사용하여 생각한 뒤, 답변을 다시 말해주는 Python 기반의 음성 챗봇을 만들었습니다. 이 모든 과정은 로컬(Locally)에서 실행되며, 대화 전반에 걸쳐 지속적인 메모리(Persistent Memory)를 유지합니다.
이 글에서는 세 가지 라이브러리를 사용하여 정확히 그것을 구축하는 방법을 살펴봅니다: 음성 인식(Speech Recognition)을 위한 OpenAI Whisper, 대화형 AI (Conversational AI)를 위한 LangChain, 그리고 텍스트 음성 변환 (Text-to-Speech) 합성을 위한 Kokoro입니다. 그 결과물은 여러분의 개인 컴퓨터에서 실행할 수 있고 원하는 대로 확장할 수 있는 완전한 기능의 음성 대 음성 (Speech-to-Speech) AI 어시스턴트입니다.
자기소개
저는 David Archanjo이며, 기술 산업에서 10년 이상의 경력을 가진 풀스택 엔지니어 (Full-Stack Engineer)입니다. 저는 소프트웨어 개발과 AI 엔지니어링 (AI Engineering)에 열정을 가지고 있으며, 개발자들이 실제 애플리케이션을 구축하는 데 도움이 되는 기술 기사를 통해 실용적인 지식을 공유하는 것을 즐깁니다.
목차
- 서론 (Introduction)
- 사전 요구 사항 (Prerequisites)
- 아키텍처 개요 (Architecture Overview)
- 프로젝트 설정 (Project Setup)
- 구성 (Configuration)
- Whisper를 이용한 음성 인식 (Speech Recognition with Whisper)
- LangChain을 이용한 대화형 AI (Conversational AI with LangChain)
- 지속적인 대화 기록 (Persistent Conversation History)
- Kokoro를 이용한 텍스트 음성 변환 (Text-to-Speech with Kokoro)
- 모두 통합하기 (Put It All Together)
- 애플리케이션 실행하기 (Running the Application)
- 다음 단계 (Next Steps)
- 마무리 (Wrap Up)
서론 (Introduction)
이 가이드는 Python을 사용하여 완전히 기능하는 음성 기반 AI 챗봇을 구축하는 과정을 안내합니다. 이 챗봇은 음성 입력을 듣고, 거대 언어 모델 (LLM)을 사용하여 이를 이해하며, 자연스러운 합성 음성으로 응답합니다. 이 모든 과정은 항상 연속적이고 지속적인 대화 루프 내에서 이루어집니다.
이를 달성하기 위해 우리는 세 가지 별개의 기술을 결합합니다:
- Whisper: OpenAI의 음성 인식 모델로, 여기서는
pywhispercpp를 통해 마이크 입력을 텍스트로 전사 (transcribe)하는 데 사용됩니다. - LangChain: LLM 기반 애플리케이션을 구축하기 위한 프레임워크로, 대화 체인 (conversational chain)과 지속적인 메모리 (persistent memory)를 관리하는 데 사용됩니다.
- Kokoro: LLM의 텍스트 응답을 음성 오디오로 변환하는 가볍고 ONNX 기반인 텍스트 음성 변환 (TTS) 엔진입니다.
동기 (Motivation)
대부분의 LLM 챗봇 튜토리얼은 텍스트 입력과 텍스트 출력 단계에서 멈춥니다. 실제 대화형 인터페이스에는 두 가지 추가 계층이 필요합니다: 음성 언어를 이해하는 것과 음성 응답을 생성하는 것입니다. 이러한 계층을 개별적으로 구축하는 것은 간단하지만, 이를 하나의 응집력 있고 상태를 유지하는 (stateful) 파이프라인으로 연결하는 것이 진정한 핵심 작업입니다.
이 가이드는 바로 그 연결, 즉 원시 오디오 입력에서부터 세션 간에 SQL 데이터베이스에 저장되는 지속적인 대화 메모리를 포함한 음성 AI 응답에 이르는 과정을 다룹니다.
우리가 구축할 것 (What We Will Build)
이 가이드를 마칠 때쯤, 우리는 다음과 같은 기능을 갖춘 작동 가능한 Python 애플리케이션을 갖게 됩니다:
- 침묵 감지 (silence detection)를 처리하며 마이크 입력을 지속적으로 경청합니다.
- Whisper를 사용하여 음성을 텍스트로 전사합니다.
- 전사된 텍스트를 LLM 기반의 LangChain 대화 체인을 통해 전달합니다.
- 대화 기록을 SQLite 데이터베이스에 지속적으로 저장합니다.
- Kokoro를 사용하여 LLM의 응답을 오디오로 변환하고 스피커를 통해 재생합니다.
사전 요구 사항 (Prerequisites)
시작하기 전에 다음 사항들이 준비되었는지 확인하십시오:
- Python 3.10 이상 및
pip설치됨 - Python 가상 환경 (virtual environments)에 대한 기본적인 숙련도
- 작동 가능한 마이크 및 오디오 출력 장치
일반 용어 및 약어 (Common Terms and Abbreviations)
이 가이드 전반에 걸쳐 다음과 같은 용어 및 약어를 접하게 됩니다:
- ONNX: Open Neural Network Exchange, 한 프레임워크에서 학습된 모델을 다른 런타임에서 실행할 수 있도록 하는 머신러닝 모델 표현 표준입니다.
- VAD: Voice Activity Detection (음성 활동 감지), 오디오에서 음성을 감지하는 데 사용되는 기술입니다.
- STT: Speech-to-Text (음성-텍스트 변환), 오디오를 텍스트로 변환하는 프로세스입니다.
- TTS: Text-to-Speech (텍스트-음성 변환), 텍스트를 오디오로 변환하는 프로세스입니다.
API Key 설정 (API Key Setup)
본 기사에서는 llama.cpp 등을 사용하여 OpenAI 호환 API를 통해 노출된 로컬 호스팅 언어 모델을 사용할 수 있습니다. 이 설정을 통해 모든 예제를 공식 OpenAI 서비스를 사용할 때 작성하는 코드와 동일하게 유지하면서, 완전히 로컬 머신에서 실행할 수 있습니다.
# OpenAI
export OPENAI_API_KEY="sk-your-openai-api-key"
...
저는 개인적으로 오픈 모델(예: Gemma 4)을 로컬에서 서빙하기 위해 llama.cpp의 독립형 배포판인 llamafile을 사용하고 추천합니다:
./llamafile \
-m gemma-4-E2B-it-Q4_K_M.gguf \
--server \
...
--alias gpt-4o는 서버가 로컬 모델을 gpt-4o라는 이름으로 노출하도록 지시합니다. LangChain의 관점에서는 OpenAI GPT-4o 모델에 연결된 것과 정확히 동일하게 동작하므로, 이 기사의 모든 예제가 코드 변경 없이 동일한 init_chat_model 설정을 통해 작동할 수 있습니다:
from langchain.chat_models import init_chat_model
llm = init_chat_model(model="gpt-4o", model_provider="openai")
이 로컬 설정을 투명하게 작동시키려면 다음 환경 변수도 구성해야 합니다:
export OPENAI_BASE_URL="http://localhost:8000/v1"
참고 (NOTE): 이미 OpenAI API 키를 보유하고 있다면,
OPENAI_BASE_URL환경 변수를 제거하고OPENAI_API_KEY의 플레이스홀더 값을 본인의 키로 교체하기만 하면 됩니다. 이 글 전체에 나오는 예제들은 수정 없이 그대로 작동할 것입니다.
아키텍처 개요 (Architecture Overview)
코드로 들어가기 전에, 구성 요소들이 어떻게 상호작용하는지 이해해야 합니다. 챗봇은 오디오 이벤트에 의해 구동되는 하나의 연속적인 루프(loop)로 작동합니다.
이 흐름은 설계상 엄격하게 선형적(linear)이며 블로킹(blocking) 방식입니다. 어시스턴트는 말하는 동안에는 듣지 않으며, 생각하는 동안에는 말하지 않습니다. 이러한 설계는 구현을 단순하게 유지하고 오디오 피드백(audio feedback)과 같은 문제를 방지하지만, 인간이 자연스럽게 나누는 대화보다는 유연함이 떨어지는 대가로 이루어집니다.
구성 요소의 역할 (Component Responsibilities)
| 구성 요소 | 라이브러리 | 역할 |
|---|---|---|
| 음성 활동 감지 (Voice Activity Detection) | pywhispercpp | 마이크 스트림에서 음성 경계 및 침묵 감지 |
| ... |
프로젝트 설정 (Project Setup)
이 프로젝트는 최소한의 평면적인 구조로 구성됩니다:
/
├── ai_chatbot.py # 메인 애플리케이션 진입점
├── config.py # 모든 설정 상수 및 환경 변수 로드
...
애플리케이션 의존성 (requirements.txt)
이 프로젝트는 다음의 Python 패키지들에 의존합니다:
langchain==0.3.27
langchain-openai==0.3.27
langchain-community==0.3.27
...
이 패키지들은 LLM 오케스트레이션 (orchestration), 음성 인식 (Whisper.cpp), 음성 활동 감지 (voice activity detection), 음성 합성 (Kokoro ONNX), 설정 관리 및 터미널 출력을 위해 필요한 구성 요소들을 제공합니다.
의존성 설치 (Installing Dependencies)
가상 환경을 생성하고 제공된 requirements.txt로부터 필요한 패키지들을 설치합니다.
python -m venv .venv
source .venv/bin/activate # Windows의 경우: .venv\Scripts\activate
pip install -r requirements.txt
시스템 의존성 (System Dependencies)
애플리케이션을 실행하기 전에 시스템 수준에서 다음 도구들을 설치해야 합니다.
Ubuntu/Debian에서는 apt를 사용하세요:
sudo apt-get install espeak-ng portaudio19-dev
macOS에서는 Homebrew를 사용하세요:
brew install espeak-ng portaudio
Windows에서는 Chocolatey를 사용하세요:
choco install espeak-ng portaudio
eSpeak-NG 설치 확인
새 터미널 창을 열고 다음을 실행하세요:
espeak-ng "Testing eSpeak-NG is working"
기본 오디오 출력(아마도 로봇 목소리로)을 통해 지정된 문구 _"Testing eSpeak-NG is working"_이 들려야 합니다.
모델 파일 다운로드 (Downloading Model Files)
pywhispercpp는 첫 실행 시 Whisper 모델 가중치(weights)를 자동으로 다운로드합니다. config.py에서 사용할 모델 크기를 설정할 수 있습니다. 하지만 Kokoro 모델 파일은 kokoro-onnx 릴리스 페이지에서 수동으로 다운로드하여 models/ 디렉토리에 배치해야 합니다.
설정 (Configuration)
상수(constants)와 환경 변수(environment variables)를 코드베이스 곳곳에 흩어놓는 대신, 모든 설정을 단일 config.py 모듈로 중앙 집중화합니다. 다른 모든 모듈은 이 모듈로부터 임포트(import)합니다. 이렇게 하면 애플리케이션을 조정하기가 더 쉬워지며, 비밀 정보(secrets)와 정적 설정(static configurations)을 애플리케이션 로직으로부터 분리하여 유지할 수 있습니다.
.env 파일
.env 파일로부터 환경 변수를 로드하기 위해 python-dotenv를 사용합니다.
MODEL=gpt-4o
MODEL_PROVIDER=openai
SESSION_ID=user_session
...
config.py 파일
import os
from dotenv import load_dotenv
from langchain_core.runnables.config import RunnableConfig
...
이러한 구조를 사용하는 이유
환경, 사용자 또는 배포 대상 간에 변경될 수 있는 모든 값은 config.py 또는 .env에 저장됩니다. 메인 애플리케이션 파일(ai_chatbot.py)에는 하드코딩된 문자열이나 매직 넘버(magic numbers)가 포함되지 않습니다. 이러한 분리는 애플리케이션 로직을 건드리지 않고도 설정을 재정의할 수 있기 때문에 테스트를 더 용이하게 만듭니다.
IGNORED_TRANSCRIPTIONS 집합(set)은 Whisper의 실질적인 문제를 처리합니다. Whisper가 거의 무음이거나 배경 소음이 있는 경우, 빈 문자열을 반환하는 대신 [BLANK_AUDIO]와 같은 플레이스홀더(placeholder) 문자열을 생성할 때가 있습니다. 우리는 LLM(대규모 언어 모델)에 전달하기 전에 이러한 값들을 필터링하여 제거합니다.
Whisper를 이용한 음성 인식 (Speech Recognition)
Whisper는 OpenAI에서 개발한 범용 음성 인식 모델입니다. 이 모델은 방대하고 다양한 오디오 데이터셋으로 학습되었으며 여러 언어의 전사(transcription)를 지원합니다. 여기서는 pywhispercpp를 통해 이를 사용하는데, 이는 CPU 추론(inference)에 최적화된 Whisper의 C++ 구현체인 whisper.cpp에 대한 Python 바인딩(bindings)을 제공합니다.
Assistant 클래스
pywhispercpp에는 전체 음성 인식 파이프라인을 캡슐화하는 고수준(high-level) Assistant 유틸리티 클래스가 포함되어 있습니다. 오디오 캡처, VAD(음성 활동 감지), 그리고 Whisper 추론을 직접 처리하는 대신, 우리는 콜백 함수(callback function)만 제공하면 됩니다. Assistant는 완전한 발화(utterance)의 전사를 마칠 때마다 주어진 콜백을 자동으로 호출합니다.
이것이 오디오 입력과 애플리케이션의 나머지 부분 사이의 핵심 통합 지점입니다.
음성 활동 감지 (Voice Activity Detection)의 작동 방식
Assistant는 내부적으로 webrtcvad를 사용하여 음성 경계(speech boundaries)를 감지합니다. 마이크로부터 오디오를 지속적으로 읽어 들여 버퍼(buffer)에 저장합니다. 사람이 말을 멈춘 것을 감지하면(silence_threshold 밀리초보다 긴 침묵), 버퍼링된 오디오를 전사(transcription)를 위해 Whisper로 전달한 다음, 그 결과를 지정된 콜백(callback)으로 전달합니다.
Assistant 초기화하기
Assistant 초기화 과정은 다음과 같습니다:
from pywhispercpp.examples.assistant import Assistant
# 음성 비서 초기화
...
세 가지 생성자(constructor) 매개변수에 대하여:
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기