실시간 AI 기반 회의 어시스턴트를 만드는 것은 기획서에서는 멋져 보입니다. 하지만 현실은 레이턴시, API 속도 제한, 그리고 AI 모델이 실시간 음성 데이터의 폭포수를 감당하도록 설계되지 않았다는 냉혹한 현실과의 끝없는 전쟁입니다. 이것은 VORA 엔지니어링 팀이 구글 제미나이 API를 거의 박살낸 이야기—그리고 어떻게 고쳤는지에 대한 기록입니다.

꿈: 실시간 AI 음성 보정

VORA의 핵심 약속은 단순합니다: 회의 중 자연스럽게 말하면, AI가 전사하고, 전문 용어를 보정하고, 질문을 감지하고, 요약을 생성합니다—모두 실시간으로. Web Speech API가 원시 전사를 처리하지만, 출력은 종종 엉망입니다. "API"는 "에이피아이"가 되고, "LogP"는 "로그피"로, 도메인 특화 용어들은 참혹하게 변합니다.

여기서 제미나이 Flash가 등장합니다. Web Speech API에서 확정된 모든 문장을 제미나이에 보내 지능적인 문맥 기반 보정을 받는 파이프라인을 설계했습니다. 첫 번째 버전은 아키텍처 다이어그램에서 우아해 보였죠.

[마이크] → [Web Speech API] → [원시 텍스트] → [제미나이 API: 보정 + 질문 감지] → [정제된 UI]
                               ↓
                    [60초마다: 제미나이 요약 태스크]

악몽: 429 에러의 폭격

실제 회의 음성으로 테스트한 순간, 재앙이 시작됐습니다. 2분 후 콘솔 화면:

// 실시간 회의 2분 후 콘솔 출력 [GeminiAPI] CORRECTION 시작 (gemini-flash-latest) - 큐: 0 [GeminiAPI] CORRECTION 완료 [GeminiAPI] CORRECTION 시작 (gemini-flash-latest) - 큐: 3 [GeminiAPI] CORRECTION 시작 (gemini-flash-latest) - 큐: 5 ERROR [GeminiAPI] CORRECTION 에러: HTTP 429 - Resource has been exhausted ERROR [GeminiAPI] QA 에러: HTTP 429 - Resource has been exhausted ERROR [GeminiAPI] SUMMARY 에러: HTTP 429 - Resource has been exhausted // ...전체 시스템이 침묵. 모든 AI 기능 마비.

무슨 일이 벌어진 걸까?

사람은 분당 약 150-180 단어를 말합니다. Web Speech API는 2-5초마다 결과를 확정합니다. 즉, 텍스트 보정만으로도 분당 12-30개의 제미나이 API 요청을 보내고 있었습니다. 질문 감지, AI 답변, 주기적 요약까지 더하면 분당 40-50개 이상의 요청—제미나이 무료 티어 RPM(분당 요청 수) 한도인 15를 훨씬 초과했습니다.

최악인 점은? 429 에러가 한 번 시작되면 연쇄적으로 확산된다는 것입니다. 보정 큐가 밀리고, 요약 요청이 쌓이고, 재시도 로직이 더 많은 요청을 쏟아냅니다. 제미나이가 단순히 느려진 게 아니라—완전히 마비됐습니다.

해결: 4단계 방어 아키텍처

단 하나의 트릭으로 해결한 게 아닙니다. 수 주간의 실전 테스트를 거쳐 정제한 체계적이고 다층적인 접근법이었습니다.

1단계: 로컬 우선 사전 보정 (API 호출 제로)

첫 번째 돌파구는 대부분의 보정에 AI가 전혀 필요 없다는 깨달음이었습니다. 흔한 오인식을 올바른 용어로 매핑하는 로컬 발음 사전을 구축했습니다:

// text-corrector.js - 로컬 사전 (API 불필요) const dictionary = { '에이피아이': 'API', '유아이': 'UI', '에스디케이': 'SDK', '지피티': 'GPT', // 세션 중 동적으로 학습된 용어들... }; // 로컬 빠른 보정은 즉시 실행, 네트워크 호출 없음 quickCorrect(text) { let corrected = text; for (const [wrong, correct] of Object.entries(dictionary)) { if (corrected.includes(wrong)) { corrected = corrected.split(wrong).join(correct); } } return corrected; }

이것만으로 API 요청의 약 40%를 제거했습니다. 로컬 사전은 세션 중 학습도 합니다: 제미나이가 성공적으로 보정한 용어는 로컬에 저장되어 같은 보정에 다시 API 호출이 필요 없습니다.

2단계: 타입별 속도 제한이 있는 우선순위 큐

모든 API 태스크가 동등하게 중요하지는 않습니다. 사용자의 직접 질문이 루틴한 텍스트 보정에 절대 차단되어서는 안 됩니다. 우선순위 큐를 구현했습니다:

// gemini-api.js - 우선순위 기반 태스크 실행 const priorityMap = { 'QA': 0, // 최우선: 사용자 질문 즉시 처리 'CORRECTION': 1, // 보통: 텍스트 보정은 몇 초 기다릴 수 있음 'SUMMARY': 2 // 최하: 요약은 어차피 60초마다 실행 }; // 타입별 최소 간격 (RPM 관리) this.minIntervals = { CORRECTION: 5000, // 최대 분당 12개 보정 QA: 500, // 질문은 거의 즉시 처리 SUMMARY: 10000, // 최대 분당 6개 요약 GLOBAL: 1500 // 하드 플로어: 총 분당 40개 절대 초과 불가 };

핵심 인사이트

타입별 간격을 도입함으로써, 음성 보정이 폭주해도 QA나 요약 파이프라인을 굶기지 않도록 보장했습니다. 1.5초의 글로벌 간격이 하드 실링 역할을 하여, 격렬한 토론 중에도 총 RPM을 구글 한도 이내로 유지합니다.

3단계: 지능형 스킵 로직 (AI 트리아지)

반직관적인 부분: 모든 문장에 AI 보정이 필요하지는 않습니다. 문장이 제미나이에 보낼 만큼 "흥미로운지" 판단하는 트리아지 함수를 만들었습니다:

// 전문 용어 오인식 가능성이 있는 패턴일 때만 제미나이로 전송 mightNeedAICorrection(text) { const indicators = [ /[가-힣]{2,}(닙|맙|빕)/, // 약물명 패턴 (-닙, -맙) /(값|농도|수치|결과)/, // 측정 관련 단어 /[가-힣]\s?[가-힣]\s?[가-힣]/, // 3연속 음절 (약어 가능성) /(로그|피|씨|케이|에이)/, // 한국어화된 영어 발음 /(그\s?값|그것|이것|저것)/, // 지시 대명사 (문맥 필요) ]; return indicators.some(pattern => pattern.test(text)); }

"네, 계속하죠"나 "동의합니다" 같은 단순한 문장은 AI를 완전히 건너뜁니다. 이것으로 API 호출을 약 30% 추가 절감했습니다.

4단계: 백그라운드 비차단 보정

마지막 퍼즐: 보정이 백그라운드에서 비동기로 진행됩니다. 사용자는 로컬 보정된 텍스트를 즉시 봅니다. 제미나이의 보정이 도착하면(때로 2-5초 후), UI가 스파클 배지(✨)와 함께 부드럽게 업데이트됩니다.

결과: Before vs. After

성능 비교

지표 개선 전 (무식한 방법) 개선 후 (4단계 방어)
분당 API 호출 40-50+ 8-12
429 에러 2분 후 지속적 발생 60분+ 세션에서 제로
체감 보정 지연시간 3-8초 (블로킹) 0ms 로컬 + 2s AI 폴리시
시스템 안정성 5분 후 크래시 2시간+ 안정 세션

다음 진화: Groq과의 듀얼 AI 아키텍처

4단계 방어에도 본질적인 긴장이 있습니다: 실시간 보정은 속도를 원하지만, 제미나이의 강점은 깊은 문맥 이해입니다. 현재 Groq의 Llama 3.3 70B가 지연 시간에 민감한 1차 보정을 담당하고(LPU 하드웨어 가속으로 일관적인 1초 미만 응답), 제미나이는 가장 잘하는 것에 집중하는 듀얼 AI 아키텍처로 운영 중입니다—문맥 이해, 요약, 지능형 Q&A.

[음성] → [로컬 사전] → [Groq/Llama: 빠른 보정 (저지연)] → [화면 표시]
                    ↓ (병렬)
          [제미나이: 깊은 문맥 (요약, Q&A, 학습)]

교훈의 타임라인

1주차: "그냥 다 제미나이로 보내자"

무식한 접근법. 시스템이 2분 만에 사망. 모든 문장이 API 호출을 트리거. 429 에러가 연쇄적으로 전체 시스템을 마비시킴.

2주차: "지수 백오프를 추가하자"

크래시 방지에는 도움이 됐지만 10-30초의 보정 지연이 발생. 사용자가 오래된 텍스트를 봄. 실시간 사용에 허용 불가.

3주차: "로컬 사전 + 간격 쓰로틀링"

큰 돌파구. API 호출 60% 감소. 하지만 우선순위 충돌은 남아있었음—피크 발화 시 요약이 보정을 차단.

4주차: "우선순위 큐 + AI 트리아지 + 백그라운드 보정"

최종 아키텍처. 429 에러 제로. 부드러운 실시간 경험. 사용자가 로컬 보정과 AI 보정의 차이를 구분하지 못함.

실시간 AI 애플리케이션을 만드는 개발자들을 위한 조언

  1. "무제한" API 티어를 절대 믿지 마세요. 유료 플랜에도 버스트 제한이 있습니다. 첫날부터 최악의 경우를 설계하세요. 분당 10개 이상의 요청을 생성할 수 있다면, 큐 시스템이 필요합니다.
  2. 로컬 우선은 타협이 아니라 기능입니다. 80% 정확한 0ms 로컬 보정이 99% 정확한 5초 AI 보정보다 무한히 낫습니다. 사용자는 완벽함보다 지연시간을 더 민감하게 느낍니다.
  3. 무자비하게 우선순위를 매기세요. 모든 AI 태스크가 동등하지 않습니다. 사용자의 직접 질문이 루틴 백그라운드 작업 뒤에서 기다려서는 안 됩니다. 우선순위 레벨과 타입별 속도 제한을 구현하세요.
  4. AI 보정을 비차단으로 만드세요. 최선의 사용 가능한 결과를 즉시 보여주고, 백그라운드에서 다듬으세요. AI가 텍스트를 개선할 때의 "반짝임" 효과는 실제로 사용자에게 불편함이 아닌 즐거움을 줍니다.
  5. 트리아지 시스템을 구축하세요. 입력의 30-50%는 아마 AI가 전혀 필요 없을 것입니다. 간단한 정규식이나 휴리스틱 체크로 엄청난 API 비용을 절약하고 체감 속도를 개선할 수 있습니다.
  6. 끊임없이 모니터링하세요. 우리는 실시간 큐 깊이, API 처리 상태, 에러율을 보여주는 관리자 대시보드를 만들었습니다. 없었다면 눈먼 채로 디버깅하고 있었을 것입니다.
  7. 멀티 모델 아키텍처를 고려하세요. 서로 다른 AI 모델은 서로 다른 강점과 속도 제한을 가지고 있습니다. 지연 시간에 민감한 작업에는 빠른 모델을, 심층 분석에는 똑똑한 모델을 사용하는 것이 하나의 모델로 모든 것을 처리하는 것보다 종종 더 낫습니다.
  8. 세션 학습은 복리처럼 쌓입니다. 로컬에 캐시된 모든 AI 보정은 미래의 API 호출 하나를 줄여줍니다. 10분 후면, 세션 사전이 네트워크 요청 없이 60% 이상의 보정을 처리합니다.

직접 체험해 보세요

VORA는 무료, 회원가입 없는 AI 회의 어시스턴트입니다. 이 포스트에서 설명한 아키텍처를 직접 경험해 보세요: VORA 실행하기. 모든 처리는 브라우저에서 이루어지며—회의 데이터는 절대 우리 서버를 거치지 않습니다.