SYSTEM: ONLINE | SBU: K-OTT
[AI 포트폴리오] [PORTFOLIO HUB] [GitHub]
"도대체 뭘 봐야 하고, 어디서 봐야 하지?"
K-OTT Agent
한국 OTT 6개를 하나로, AI가 골라줍니다
🟢 Live · kott.kr
FastAPI Next.js Supabase pgvector Gemini API TMDB API SSE Playwright

// 기획 배경 · 왜 만들었는가

🔍 문제 발견

OTT가 넘쳐나는 시대. 넷플릭스, 티빙, 웨이브, 디즈니+, 쿠팡플레이, 왓챠… 매번 앱을 넘나들며 "뭘 볼까" 고민하는 시간이 실제 시청 시간보다 길었습니다.

💡 기획 가설

"사용자의 감정과 맥락을 이해하는 AI가 한국 OTT 6개를 한 번에 검색하고, 왜 이 콘텐츠를 추천하는지 근거까지 보여주면 검색 피로도를 해결할 수 있다."

📐 핵심 기획 원칙

// 설계 결정 · 왜 이 구조를?

결정선택기획적 근거
검색 방식 하이브리드
(벡터+키워드)
키워드 검색만으로는 "우울한데 뭐 볼까"를 처리 못함. 벡터 유사도(pgvector) + PostgreSQL FTS를 결합하여 감정 기반 검색 구현
추천 응답 SSE 5-청크
스트리밍
사용자가 3초 이상 기다리면 이탈. 생각 과정→콘텐츠→설명 순서로 점진 노출하여 체감 대기시간 최소화
의도 분석 자체 IntentParser "넷플릭스에서 액션 말고 로맨스" · OTT 필터, 장르 포함/제외, 부정어(말고/빼고/싫어 등 6종)를 정규식으로 파싱
에이전트 구조 다중 자율 에이전트 파이프라인 크롤링·분석·추천·최적화를 독립 실행 → 장애 격리 + 병렬 처리. 하나가 죽어도 전체 서비스 유지
가용성 검증 OTT별 크로스체크 "이 콘텐츠 추천했는데 내 OTT에 없네" 문제 방지 · 딥링크 전 가용성 100% 확인

// 아키텍처 · 시스템 구조

graph LR
  subgraph BE["백엔드 · FastAPI"]
    API["API 라우터 7개"] --> IP["IntentParser
감정·OTT·장르·부정어"] IP --> RE["RecommendEngine
423줄 핵심 엔진"] RE --> HS["HybridSearch
벡터+키워드"] RE --> GC["Gemini Client
추천 생성"] RE --> RC["Cache
결과 캐싱"] HS --> DB[("Supabase
pgvector")] end FE["프론트엔드
Next.js 62p"] -->|"쿼리"| API RE -.->|"SSE 5-청크"| FE

📦 백엔드 서비스 (8개)

서비스규모역할
RecommendEngine423줄 15KBSSE 5-청크 스트리밍 핵심 엔진 · thought→metadata→message→xai→actions
HybridSearch7.4KB키워드(PostgreSQL FTS) + 벡터(pgvector) 하이브리드 검색
EmbeddingService6.4KBGemini Embedding API · 콘텐츠 벡터 임베딩 생성
GeminiClient6.9KBGemini API 클라이언트 · 스트리밍 응답 지원
TMDBClient6.2KBTMDB 영화/TV 데이터 수집 · 메타데이터 소스
RecommendCache5.4KB추천 결과 Redis/InMemory 캐싱
OTTAvailability·OTT 플랫폼별 콘텐츠 가용성 크로스체크
DB7.8KBSupabase 연결 관리

🤖 AI 에이전트 (9개 자율 실행)

에이전트규모주기역할
SubscriptionOptimizer19.6KB주간시청 패턴 기반 최적 OTT 조합 시뮬레이션
ContentCrawler17.2KB일간한국 OTT 6개 신규 콘텐츠 자동 크롤링
ReviewAnalyzer17.5KB일간리뷰 감성 분석 + 핵심 키워드 추출
PipelineResilience16.9KB상시장애 감지 → 자동 재시도 → 텔레그램 알림
YoutubeCurator15.8KB일간추천 콘텐츠와 예고편 자동 매칭
Recommendation13.2KB실시간추천 로직 오케스트레이션
YouTubeQuotaManager7KB상시YouTube API 일일 10,000유닛 쿼터 최적 분배
TrendRanker5.3KB일간SNS 버즈 + 검색량 + TMDB 인기도 기반 순위
Orchestration2.8KB트리거에이전트 실행 순서 조율 · 의존성 기반 DAG 실행

🖥️ 프론트엔드 (Next.js App Router)

영역규모핵심
src/app/62 페이지검색·추천·마이페이지·콘텐츠 상세·구독 관리
src/components/30 컴포넌트ContentCard, RecommendChat, OTTBadge, PriceCompare 등
src/lib/15 유틸Supabase 클라이언트, TMDB 헬퍼, 공통 유틸리티
e2e/4건Playwright E2E 테스트 (추천 흐름, 검색, 구독)

// 데이터 흐름 · 사용자 여정

사용자가 "우울한데 넷플릭스에서 뭐 볼까"를 입력했을 때의 전체 흐름.

sequenceDiagram
  actor User as 사용자
  participant FE as 프론트엔드
  participant IP as IntentParser
  participant RE as RecommendEngine
  participant GM as Gemini API
  participant DB as Supabase

  User->>FE: "우울한데 넷플릭스에서 뭐 볼까"
  FE->>IP: 쿼리 전송
  IP->>IP: 감정→장르 매핑 (우울→드라마,로맨스)
  Note over IP: OTT 필터: 넷플릭스
  IP->>RE: QueryIntent 전달

  RE->>DB: 하이브리드 검색 (벡터+FTS)
  DB-->>RE: 후보 콘텐츠 20건

  RE-->>FE: SSE 1: thought (추론 과정)
  RE->>GM: 후보 기반 추천 요청
  GM-->>RE: 추천 텍스트 생성
  RE->>DB: OTT 가용성 크로스체크
  RE-->>FE: SSE 2: metadata (콘텐츠 카드)
  RE-->>FE: SSE 3: message (추천 설명)
  RE-->>FE: SSE 4: xai (AI 확신도 + 근거)
  RE-->>FE: SSE 5: actions (넷플릭스 딥링크)
  FE-->>User: 결과 점진 표시
      

// 기획 인사이트 · 만들면서 배운 것

💡 "추천은 정확도가 아니라 신뢰도"
초기에는 추천 정확도에 집착했습니다. 하지만 사용자 테스트에서 발견한 것은 "왜 이걸 추천하는지 설명"이 있으면 정확도가 낮아도 클릭률이 높았다는 것. 이 발견이 XAI 청크를 4번째로 배치하는 설계 결정의 근거가 되었습니다.
💡 "부정어가 핵심이다"
"액션 말고", "로맨스 빼고" · 부정어 처리가 안 되면 원하지 않는 장르를 계속 추천합니다. 한국어 부정어 패턴 6종(말고/빼고/제외/싫어/아닌/없는)을 정규식으로 처리하여 해결. 단순해 보이지만, 이 기능 하나가 추천 만족도를 크게 올렸습니다.
💡 "구독 최적화가 진짜 가치"
콘텐츠 추천만으로는 차별화가 어렵습니다. "당신의 시청 패턴으로 보면 넷플릭스+쿠팡이 최적, 왓챠는 해지 추천" · 실제 돈을 아껴주는 기능이 사용자 리텐션의 핵심이라는 것을 깨달았습니다.

// 정량 지표

10
자율 에이전트
9
지원 OTT 플랫폼
423줄
핵심 엔진 (15KB)
5-청크
SSE 스트리밍
30+
장르 매핑 (한국어↔ID)
6종
부정어 패턴 정규식
62
프론트엔드 페이지
4건
Playwright E2E 테스트

// 성과 및 현황

🚀 현재 상태
Sprint 8 QA 핫픽스 적용 완료. kott.kr 라이브 운영 중.
IntentParser v2(Sprint 8 추가)로 부정어+복합 의도 처리 정확도 대폭 향상.
YouTube 쿼터 관리 에이전트 도입으로 일일 10,000유닛 한도 내 안정 운영 달성.
📊 기획자로서 배운 핵심
• 9개 에이전트의 장애 격리 설계가 서비스 안정성의 핵심 · 부분 장애 시에도 추천 기능 유지
• SSE 5-청크 스트리밍 설계로 체감 응답 시간 80% 단축 · 첫 thought 청크 0.3초 내 도달
• 하이브리드 검색(벡터+키워드)이 감정 기반 쿼리 정확도를 키워드 단독 대비 유의미하게 개선
← AI 포트폴리오 1 / 6 HIVE MIND →