🤖 몽타주 챌린지 알고리즘: AI 채점 시스템의 비밀
채점은 규칙 기반이 아니라 멀티모달 AI 판단입니다
몽타주 챌린지는 얼굴 랜드마크 좌표를 뽑아서 기하학적으로 비교하는 방식이 아니라, 원본 사진과 사용자가 그린 그림 두 장을 그대로 Google Gemini 멀티모달 비전 모델(Vertex AI 경유)에 넘겨 사람처럼 “보고 판단”하게 하는 방식을 씁니다. 정교한 벡터 연산 대신, AI가 두 이미지를 함께 인식하며 형태·특징의 유사도를 종합적으로 평가하고 0~100점과 코멘트를 생성합니다.
프롬프트 엔지니어링으로 점수 분포를 다듬습니다
같은 모델이어도 프롬프트 설계에 따라 결과가 크게 달라집니다. 저희는 초기 버전에서 점수가 특정 구간에 몰리는 문제를 발견해, 채점 지침에서 “점수를 특정 범위로 유도하는” 표현을 제거하고 0~100점 전 구간을 실제 유사도에 따라 온전히 활용하도록 지침을 다시 설계했습니다. 촌평은 그림 실력만 평가하고 인물의 외모는 언급하지 않도록 별도 규칙으로 제약을 걸어둔 상태고요.
프론트엔드: 라이브러리 없는 순정 Canvas 드로잉
그림판은 외부 드로잉 라이브러리 없이 HTML5 Canvas API를 직접 다뤄 구현했습니다. 포인터 이벤트를 좌표(월드 좌표계)로 변환해 저장하고, 매 프레임 확대/이동 값을 반영한 변환행렬을 적용해 렌더링하는 방식이라 핀치줌으로 확대해서 그려도 좌표가 어긋나지 않습니다. 태블릿 등 고주사율 입력 기기에서는 좌표 손실을 막기 위해 포인터 이벤트의 중간 좌표까지 모아 처리합니다.
인프라: 서버리스 + 자동 확장
Firebase App Hosting(Next.js SSR) 위에서 동작하며, 트래픽이 급증해도 인스턴스가 자동으로 늘어나는 구조입니다. 도전장(친구에게 공유하는 그림·점수)은 Firestore에 저장되고 7일 뒤 자동 만료됩니다. 카카오톡 등에 링크를 공유했을 때 뜨는 미리보기 이미지도 요청마다 실시간으로 동적 생성됩니다.
어뷰징 방지: App Check + 레이트리밋
채점 API는 Firebase App Check(reCAPTCHA v3)로 검증된 실제 브라우저 요청인지 확인한 뒤에만 처리하며, 스크립트로 API를 직접 두드리는 시도는 차단됩니다. 여기에 IP 기준 분당·일일 요청 한도를 추가로 걸어 트래픽 급증이나 남용 시도에 대비하고 있습니다. 물론 모든 시스템이 그렇듯 완벽한 방어란 없고, 저희도 계속 지켜보면서 다듬어가는 중입니다.
업로드 검증: 용량 제한과 형식 체크
사진과 그림 데이터는 서버로 들어오는 시점에 크기 상한을 두고 거부합니다. 지나치게 큰 파일을 반복 전송해 서버 자원을 소모시키는 형태의 남용을 막기 위한 최소한의 방어이고, Firestore 문서 용량 한도(1MB)를 넘지 않도록 도전장 저장 직전에도 별도로 한 번 더 검증합니다. 카카오톡 공유용 미리보기 이미지도 PNG 대신 JPEG로 변환해 전송하는데, 이는 이미지 생성 엔진이 특정 포맷을 제대로 렌더링하지 못하는 문제를 실제로 겪고 나서 고친 부분입니다.
채점 비용은 왜 Vertex AI로 처리하나요
Gemini는 Google AI 개발자용 API로도 호출할 수 있지만, 무료 등급은 하루 요청 수 한도가 낮아 트래픽이 몰리는 순간 서비스가 끊길 위험이 있습니다. 그래서 실제 서비스 트래픽은 Google Cloud의 Vertex AI 경로로 처리하고 있는데, 이쪽은 확장성과 처리량 면에서 훨씬 안정적입니다. 로컬 개발 환경에서만 개발자용 API 키로 자동 전환되도록 분기를 나눠뒀어요.