서비스 링크: https://stylesense-khaki.vercel.app/
(※ 첫 접속 시 서버 기동으로 잠시 지연될 수 있습니다.)
📌 세 줄 요약
사진 한 장을 업로드하면 퍼스널 컬러를 진단하고, 실시간 날씨 맥락까지 결합해 오늘 입기 좋은 2가지 룩(Daily/Special)을 룩북 이미지로 추천해주는 서비스 “StyleSense”를 만들었습니다. 목표는 ‘그럴듯한 데모’가 아니라, 배포 링크로 실제 동작하는 제품까지 완성하는 것이었습니다.
그리고 이 프로젝트의 핵심은, 프롬프트를 길게 쓰는 것보다 확률적으로 흔들리는 AI 결과를 ‘아키텍처와 시스템’으로 통제하는 방법을 실제로 구현하고 검증하는 것이었습니다.
1) 배경: “오늘 뭐 입지?”를 AI로 풀어보고 싶었습니다
아이디어는 일상에서 출발했습니다. 옷을 좋아하든 싫어하든, 출근 전에는 늘 비슷한 고민을 합니다.
- 오늘 날씨가 애매한데… 뭘 입지?
- 톤에 맞게 입고 싶은데… 막상 고르기 어렵네?
- 코디 추천은 많은데… 내 사진/내 톤까지 반영되면 좋겠다.
그래서 생각했습니다.
“사진 한 장만 올리면, 퍼스널 컬러와 날씨를 같이 반영해서 코디를 추천해주면 꽤 쓸모 있지 않을까?”
2) 시작은 빠르게: Gems → AI Studio → Cursor로 넘어간 이유
처음에는 속도가 중요하다고 생각해서, 가볍게 프로토타이핑부터 했습니다.
- Gems: 30분 안에 결과는 나왔지만, 제가 원하는 방향으로 세부 튜닝하기가 어려웠습니다.
- AI Studio: 빠르게 만들 수 있었지만, 제품 수준으로 “통제 가능한 형태”를 만들기에는 제한이 있었습니다.
결국 결론은 하나였습니다.
“내가 원하는 방향으로 ‘요리’하려면 자유도가 필요하다. 그럼 Cursor로 가자.”
다만 이 선택은 장점만 있진 않았습니다.
AI Studio는 플랫폼이 깔아둔 인프라/가드레일 위에서 달리지만, Cursor는 제가 하나씩 설계하고 통제해야 했습니다.
(덕분에 배포/의존성/CORS 같은 현실 이슈도 직접 밟고 해결했습니다. 힘들었지만… 성장(?) 😇)
3) 목표: 프로토타입이 아니라 ‘작동하는 제품’으로 끝내기
이번 목표는 단순히 기능 구현이 아니라, 사용자가 실제로 쓸 수 있는 흐름을 갖추는 것이었습니다.
- 사진 1장 업로드 → 퍼스널 컬러 분석
- 실시간 날씨 결합
- 오늘의 코디 2가지 룩북(Daily/Special) 생성
- 이미지 다운로드
- 링크로 공유해도 동작하는 프로덕션 배포
4) 진행 방식: Strategist(Gemini/ChatGPT) × Executor(Cursor)
작업 방식도 의도적으로 설계했습니다.
- 전략가: Gemini/ChatGPT
문제 정의, 우선순위, “무엇을 통제해야 제품이 되는지” 결정 - 실행가: Cursor
Ask/Plan/Agent 모드를 활용해 코드 반영 → 빌드 → 배포 → 검증까지 밀어붙이기
중간에 재미있는 깨달음도 있었는데요. 처음엔 “전략은 밖에서 세우고 Cursor는 실행만”이라고 생각했는데, 진행하다 보니 Cursor도 Ask/Plan/Agent를 잘 쓰면 전략까지 상당 부분 흡수할 수 있었습니다. 결국 도구보다 “어떻게 지시하고 검증하느냐”가 더 중요했습니다.
5) 제품 구조: ‘에이전트 워크플로우’로 만들기 (LangGraph + Tool calling/MCP)
StyleSense는 단일 프롬프트 앱이 아니라, LangGraph 기반 워크플로우로 구성했습니다.
입력 검증 → 비전 분석 → 외부 데이터(날씨) 조회 → 추천 생성 → 검증/보정까지를 노드 단위로 분리해 연결했습니다.
특히 날씨처럼 모델이 “추측”하면 안 되는 데이터는 Tool calling/MCP 방식으로 분리했습니다.
여기서 MCP를 쓴 이유는 단순합니다: 도구 인터페이스를 표준화해두면, 데이터 공급자(Tavily 등)가 바뀌어도 워크플로우를 안정적으로 유지할 수 있기 때문입니다.
요약하면, “AI가 잘하길 기대”하기보다 어느 단계가 흔들리는지 측정하고 필요한 곳만 최소 수정으로 개선할 수 있게 만드는 구조를 목표로 했습니다.
(도식) LangGraph 워크플로우 개요

6) AI의 흔들림을 ‘시스템’으로 통제하기⭐
6-1) “측정 도구가 먼저다”: 회귀 테스트 자동화 게이트(QA-Lite)
AI 결과는 눈으로만 보면 착각하기 쉽습니다. 그래서 품질을 올리기 전에, 먼저 품질을 측정할 수 있는 게이트부터 만들었습니다.
- 회귀 테스트 자동화 게이트(이미지 생성 없는 Regression Gate)
- 시나리오 + 시드(seed) 고정으로 자동 실행
- 결과는 JSONL로 남겨 통과/실패로 판단
팩트: seed 42 고정 / 12개 시나리오 100% 통과, error_count 0
| 시나리오 ID | 지역 (기온 맥락) | 스타일 | 성별 | 퍼스널 컬러 | 검증 결과 (Pass/Fail) |
| male-sexy-seoul | 서울 (-2.6°C) | 섹시 | 남성 | 여름 뮤트 | PASS |
| female-sexy-seoul | 서울 (-2.6°C) | 섹시 | 여성 | 봄 브라이트 | PASS |
| male-chic-helsinki | 헬싱키 (-8.4°C) | 시크 | 남성 | 여름 트루 | PASS
|
| female-elegant-dubai | 두바이 (24.1°C) | 우아 | 여성 | 봄 라이트 | PASS |
| male-minimal-seoul | 서울 (-2.6°C) | 미니멀 | 남성 | 가을 딥 | PASS |
| … 외 7종 | 글로벌 랜덤 | 혼합 | 혼합 | 혼합 | PASS |
PM 관점 한 줄: “운 좋게 잘 됐다”가 아니라, 가드레일(게이트)을 세워서 품질을 유지하는 방식이었습니다.
6-2) 경량형 Self-correction 루프(Mini A): “딱 한 번만” 보정하기
이미지 생성은 확률적으로 흔들립니다(크롭/중복 인물/비율 등).
하지만 마음에 들 때까지 무한 재시도하면 비용과 지연이 폭주합니다. 그래서 Mini A는 이렇게 설계했습니다.
- 실패를 감지하면
- LLM을 다시 불러 프롬프트를 새로 쓰지 않고(추가 판단/리라이트 없이)
- 미리 정의한 짧은 패치 토큰(Patch Token)을 프롬프트 끝에 append-only로 덧붙인 뒤
- 이미지 생성만 최대 1회 재시도합니다. (Max Retry = 1)
예를 들어 크롭 이슈가 나면 CROP_STABILITY, 인물 중복이 보이면 SINGLE_PERSON, 남성 비율이 무너지면 MALE_PHYSIQUE_STABILITY 같은 처방 토큰을 추가하는 방식입니다.
핵심은 “더 똑똑하게 다시 쓰는 것”보다, 가이드라인을 빠르고 확실하게 강화해 1회 안에 정답률을 높이는 실무형 구조를 택한 점이었습니다.
그리고 “루프가 실제로 동작했는지”는 말로 끝내지 않기 위해, 강제 실패 시나리오를 넣어 JSONL에 review_attempt=2가 찍히는 것으로 증명했습니다.
(중요 포인트는 ‘재시도 자체’가 아니라, 재시도가 발생했음을 기록으로 남기는 구조였습니다.)
6-3) 가장 치명적인 문제: 같은 사진인데 퍼스널 컬러가 바뀜 → ‘일관성’부터 해결
수동 테스트 중 가장 치명적인 문제는 이거였습니다.
“같은 사진을 올렸는데, 퍼스널 컬러 진단이 매번 바뀐다.”
사용자가 자기 퍼스널 컬러를 어느 정도 알고 있는 경우가 많기 때문에, 이 문제는 신뢰를 바로 무너뜨립니다.
원인은 Vision LLM의 확률적 변동성이었고, 저는 “정확도를 당장 100점으로 만들기”보다 일관성(Consistency)부터 확보하는 쪽을 택했습니다.
- 이미지 콘텐츠 SHA256 해시 기반 캐싱(
.pc_cache.json) - 동일 이미지면 동일 퍼스널 컬러 결과 고정
그리고 UX적으로 기술적 한계를 숨기지 않고, 결과 영역에 아래 문구를 배치했습니다.
ⓘ 사진의 조명·해상도 등에 따라 퍼스널 컬러 결과가 달라질 수 있습니다.
7) 배포: Vercel + Render로 ‘진짜 링크’를 만들기
배포는 늘 마지막 관문입니다. 이번 프로젝트는 프론트/백엔드를 분리했습니다.
- Front: Vercel
- Backend(FastAPI): Render
배포 과정에서 가장 크게 부딪힌 건 크게 두 갈래였습니다.
(1) 의존성 충돌로 인한 빌드 실패, 그리고 (2) 도메인 분리로 인한 통신(CORS) 차단입니다.
결과적으로 “코드가 돌아간다”와 “프로덕션에서 돌아간다”는 정말 다른 이야기였습니다.
최종적으로는:
NEXT_PUBLIC_API_BASE_URL환경변수로 백엔드 URL 주입- FastAPI CORS에
allow_origin_regex=r"^https://.*\.vercel\.app$"적용 - PC/모바일에서 업로드→결과→다운로드까지 동작 확인
8) Tech Stack
- 프론트: 초기 1회 v0로 빠르게 뼈대를 잡고, 이후 Next.js 구조를 Cursor에서 정리해 진행했습니다.
- 백엔드/오케스트레이션: FastAPI + LangGraph
- 날씨: Weather MCP (Tavily API)
- 이미지 생성: FAL AI
- 배포: Vercel(Front) + Render(Backend)
9) 결과: 스모크 테스트로 ‘제품 완성’ 확인
프로덕션 배포 후, PC/모바일에서 최소 스모크 테스트를 진행했습니다.
- 남/여 + 스타일 조합 테스트(스트릿/섹시/댄디 등)
- 업로드 필터링: 강아지/꽃/다인물 → Alert으로 정상 차단
- 이미지 다운로드 정상 동작
10) 교훈(Lessons): Cursor의 자유도 vs AI Studio의 편의성
이번 프로젝트에서 얻은 교훈은 현실적으로 이렇습니다.
- AI Studio/Gems는 빠릅니다. 하지만 내가 원하는 디테일로 통제하기엔 한계가 있습니다.
- Cursor는 자유도가 높습니다. 대신 모든 걸 내가 설계하고 운영 가능한 형태로 통제해야 합니다.
특히 이미지 생성은 같은 코드라도 표현/순서가 바뀌면 결과가 흔들릴 수 있어, “시스템적 통제(측정/보정/증명)”가 꼭 필요했습니다.
처음엔 “AI Studio에서 만든 것처럼 Cursor에서도 쉽게 되겠지”라고 생각했는데, 이게 착각이었습니다.
AI Studio는 이미 잘 깔린 인프라 위에서 돌아가고, Cursor는 내가 하나씩 시스템을 세워야 했습니다.
결국 “AI를 잘 쓰는 것”과 “AI 제품을 출시 가능한 형태로 만드는 것”은 다른 문제였고, 이번 프로젝트는 그 차이를 몸으로 배운 경험이었습니다.
11) 남은 과제(Backlog)
- 퍼스널 컬러 정확도(Accuracy) 정량 평가(일관성은 확보했으니 다음 단계)
- React 19 의존성 지뢰 제거(우회 플래그 제거)
- CORS 허용 범위를 프로덕션 도메인 리스트로 축소 +
/health엔드포인트 추가
마치며
AI를 ‘코딩’하는 시대를 넘어, ‘오케스트레이션’하는 시대로...
StyleSense 프로젝트를 마무리하며 가장 크게 느낀 점은, AI 제품의 본질이 모델의 지능 그 자체보다 시스템의 예측 가능성과 검증 가능성에 있다는 사실이었습니다.
이번 작업은 단순한 기능 구현이 아니라, AI PM으로서 불확실성이 큰 생성형 AI를 어떻게 시스템 아키텍처인 LangGraph 안에서 관리하고, QA-Lite와 Self-correction 같은 품질 장치로 통제 가능한 형태로 설계할 것인지 고민한 과정이었습니다.
결국 중요한 것은 AI가 한 번 그럴듯한 결과를 내는지가 아니라, 흔들릴 수 있는 결과를 서비스 수준의 신뢰로 끌어올릴 수 있는가였습니다. 이번 프로젝트를 통해 그 신뢰는 모델 하나가 아니라, 구조와 검증, 운영의 조합으로 만들어진다는 점을 다시 확인했습니다.
무엇보다 이번 프로젝트는 전략가(Gemini/ChatGPT)와 실행가(Cursor)를 오케스트레이션하며, AI를 단순한 도구가 아니라 운영 가능한 제품으로 빌드해본 실전 경험이었습니다. 앞으로도 AI의 화려함 자체보다, 실제 서비스 안에서 안정적으로 작동하는 구조와 품질 체계를 설계하는 일에 더 집중해보려 합니다.
서비스 링크: https://stylesense-khaki.vercel.app/
(※ 첫 접속 시 서버 기동으로 잠시 지연될 수 있습니다.)








