AI 여자친구 개발일지(3) - 실시간 처리를 위한 하이브리드 아키텍처

사실 지연 없는 실시간 상호작용을 구현하기 위해서는 단순히 Faster Whisper와 같은 고성능 모델을 선택하는 것만으로는 충분하지 않습니다. 애플리케이션 아키텍처 자체에서 발생하는 지연을 근본적으로 최소화해야 합니다.
따라서 본 프로젝트에서는 로직 설계 단계부터 지연 최소화를 최우선 고려사항으로 삼아 다음과 같은 접근 방식을 채택했습니다

매끄러운 GUI 응답성을 유지하면서, STT, LLM, TTS로 이어지는 무거운 AI 파이프라인을 어떻게 효율적으로 처리하는것이 과제라고 할수 있겠습니다.

이를 해결하기 위해 하이브리드 동시성 아키텍처와 핵심 기술 스택, 그리고 확장성을 고려한 추상화 전략에 대해 상세히 기술합니다.

1. 하이브리드 동시성 모델: QThread와 asyncio의 통합

애플리케이션의 안정성과 성능을 보장하기 위해, PyQt의 스레딩 모델과 Python의 네이티브 비동기 라이브러리인 asyncio를 결합한 하이브리드 모델을 채택했습니다. 각 구성 요소의 역할은 다음과 같이 명확히 분리됩니다.

  • 메인 스레드 (GUI Thread): 이 스레드는 PyQt의 이벤트 루프에 의해 전적으로 관리됩니다. UI 렌더링, 사용자 이벤트의 감지 및 해당 시그널(Signal) 발생에 대한 책임만을 가집니다. 장기 실행 작업을 이 스레드에서 수행하는 것을 엄격히 금지하여, 애플리케이션의 UI가 '얼어붙는(freezing)' 현상을 원천적으로 방지합니다.
  • 워커 스레드 (Worker Thread): QThread를 사용하여 생성되는 백그라운드 스레드입니다. 모든 비 UI 로직, 즉 STT, LLM, TTS 파이프라인 전체가 이 스레드로 오프로드(offload)됩니다. AIEngine과 같은 핵심 로직 객체는 moveToThread() 메서드를 통해 이 워커 스레드에서 실행됩니다.
  • asyncio 이벤트 루프: 워커 스레드 내부에서 실행되는 비동기 처리의 핵심입니다. LLM 및 TTS API 호출과 같은 다수의 네트워크 I/O 작업을 논블로킹(non-blocking) 방식으로 동시에 관리하여, I/O 대기 시간 동안의 비효율을 최소화하고 전체 처리량을 극대화합니다.

2. 핵심 기술 스택 및 구현 전략

설계된 아키텍처 위에서 각 기능을 수행할 구체적인 기술 스택과 그 구현 전략은 다음과 같습니다.

LLM (Core Intelligence): Google Gemini

프로젝트의 핵심 지능을 담당하는 LLM으로는 Google의 Gemini를 선정했습니다. 단순 텍스트 응답을 넘어, 구조화된 JSON 출력을 요청하여 AI의 감정 상태, 표정, 행동 지침까지 파싱할 수 있다는 점에서 시스템의 표현력을 확장하는 데 유리합니다.

STT (Speech-to-Text): GPU 가속을 통한 Fast Whisper

STT 처리 속도를 극대화하고 로컬 환경에서 높은 정확도를 확보하기 위해 GPU 가속 기반의 Fast Whisper를 채택했습니다.

  • 기술적 과제: model.transcribe() 함수는 내부적으로 GPU에서 연산을 수행하지만, Python 코드 상에서는 작업이 완료될 때까지 기다리는 동기(synchronous) 함수입니다. 만약 이 함수를 asyncio 이벤트 루프에서 직접 호출하면, GPU 연산이 끝날 때까지 이벤트 루프 전체가 블로킹됩니다.
  • 구현 전략: asyncio 이벤트 루프의 loop.run_in_executor()를 사용해 transcribe 함수 호출을 별도의 스레드 풀에 위임합니다. 이를 통해 GPU 연산이 진행되는 동안 이벤트 루프는 다른 비동기 작업(네트워크 통신 등)을 계속 처리할 수 있으며, 시스템 전체의 효율성과 반응성을 유지합니다.
 

TTS (Text-to-Speech): ElevenLabs

AI 페르소나의 정체성을 결정하는 음성 합성 엔진으로는 표현력이 뛰어난 ElevenLabs를 선택했습니다.

  • 구현 전략: ElevenLabs API는 비동기 스트리밍을 지원하므로, asyncio 모델에 최적화되어 있습니다. async def 함수 내에서 API와 통신하며 음성 데이터 청크(chunk)를 실시간으로 수신하고, 이를 오디오 출력 모듈로 전달하여 지연 시간이 거의 없는(low-latency) 음성 출력을 구현합니다.

상태 관리: 명시적 상태 머신 (Explicit State Machine)

복잡한 상호작용 속에서 발생할 수 있는 경쟁 조건(race condition)을 방지하고 시스템 동작의 예측 가능성을 높이기 위해, 애플리케이션의 상태를 명시적으로 관리하는 상태 머신을 도입합니다. Python의 Enum을 사용하여 아래와 같이 상태를 정의합니다.

from enum import Enum

class AppState(Enum):
    IDLE = "시스템 대기"
    LISTENING = "음성 입력 수신"
    PROCESSING_STT = "음성 데이터 처리"
    THINKING = "LLM 응답 생성"
    SPEAKING = "음성 합성 및 출력"

중앙 컨트롤러인 AIEngine이 현재 상태를 소유하며, 상태 전이 로직을 엄격하게 제어합니다.

3. 아키텍처 설계: 모듈화와 추상화

관심사 분리 원칙에 입각하여 시스템을 기능별 모듈로 상세히 분할했으며, 교체될 가능성이 있는 외부 의존성에는 Provider 디자인 패턴을 적용하여 추상화 수준을 높입니다.

STTProvider라는 추상 기반 클래스(ABC)를 정의하고, FastWhisperProvider가 이를 상속받아 구체적인 로직을 구현하는 방식입니다. 이를 통해 AIEngine은 구체적인 STT 구현 기술에 대한 의존성이 분리되어, 향후 다른 STT 엔진으로 교체 시 코드 변경을 최소화할 수 있습니다.

 

긴 글 읽어주셔서 감사합니다.

니디걸 오버도즈 DATEN ROUTE

반응형