왜 단일 AI 제공자에 의존하는 것을 그만두었는가
커뮤니티 포럼을 위한 실시간 챗봇을 만들었습니다. OpenAI API만 사용했죠. 간단해 보였습니다.
3주 후, 피크 시간대에 5xx 에러가 발생했습니다. 챗봇이 먹통이 되었습니다. 사용자들은 화가 났습니다. 프로덕션 앱에서는 단일 제공자를 신뢰할 수 없다는 것을 깨달았습니다.
단일 제공자를 사용할 때 몇 가지 문제에 직면했습니다:
- 속도 제한 (Rate limits)
- 타임아웃 (Timeouts)
- 완전한 서비스 중단 (Complete outages)
다른 제공자들도 시도해 보았지만, 모두 형식이 다르고 인증 방식도 제각각이었습니다. 제 코드는 switch-case 문으로 엉망이 되었습니다.
다음과 같은 기능을 갖춘 시스템이 필요했습니다:
- 다양한 제공자의 표준화
- 하나가 실패할 때 자동으로 재시도
- 응답 캐싱
- 특정 벤더 종속(vendor lock-in) 방지
서드파티 라이브러리는 너무 경직되어 있어서 사용하지 않았습니다. 대신 간단한 설계를 사용하여 커스텀 폴백(fallback) 시스템을 구축했습니다.
먼저, 모든 제공자를 위한 공통 인터페이스를 만들었습니다. 이를 통해 어떤 AI 모델이라도 동일한 코드로 작동할 수 있습니다.
다음으로, 라우터(router) 클래스를 구축했습니다. 이 클래스는 순서대로 제공자를 시도합니다. 실패를 관리하기 위해 지수 백오프(exponential backoff)와 간단한 캐싱을 사용합니다.
로직은 다음과 같습니다:
- AI 제공자를 위한 추상 베이스 클래스를 정의합니다.
- OpenAI 및 기타 제공자를 위한 구체적인 클래스를 구현합니다.
- 라우터를 사용하여 제공자 목록을 순회합니다.
- 제공자가 실패하면 라우터는 대기한 후 다음 제공자를 시도합니다.
이 시스템 덕분에 최근 세 차례의 서비스 중단 상황에서 프로젝트를 지킬 수 있었습니다. 구조는 투명하고 단순하게 유지됩니다.
AI로 서비스를 구축한다면 다음 사항을 기억하세요:
- 프로덕션 환경에서는 로컬 딕셔너리 대신 Redis를 캐싱에 사용하세요.
- 지출을 모니터링할 수 있도록 비용 추적 기능을 추가하세요.
- 더 빠른 응답을 위해 비동기(asynchronous) 지원을 구현하세요.
- 속도 제한을 더 잘 처리하려면 "Retry-After" 헤더를 파싱하세요.
프로젝트 규모가 작다면 과도하게 설계(over-engineer)하지 마세요. 하지만 서비스의 가동 시간(uptime)이 중요하다면 폴백을 구축하십시오.
여러분은 프로젝트에서 제공자의 신뢰성을 어떻게 관리하시나요? 폴백 레이어를 사용하시나요, 아니면 단일 벤더에 의존하시나요?