2026년 운세는 AI 무당에게? Next.js 16과 Groq로 만든 '팩트폭력' 운세 심판관 개발기
1. 들어가며: 왜 이 서비스를 만들었나?
개발자로서 매년 연초가 되면 한 번쯤 호기심을 갖게 되는 도메인이 바로 '운세'입니다. 하지만 시중에 나와 있는 운세 서비스들은 대부분 정해진 데이터베이스에서 텍스트를 조합해 보여주는 방식이라, 몇 번 하다 보면 패턴이 읽히고 금세 지루해지기 마련입니다. 무엇보다 "올해는 다 잘 될 거예요"라는 영혼 없는 위로보다는, 차라리 **"지금처럼 살면 내년에도 똑같습니다"**라고 정신이 번쩍 들게 조언해 주는 친구 같은 서비스가 있으면 좋겠다는 생각이 들었습니다.
이 프로젝트는 "무당(Shaman) 페르소나를 가진 AI가 내 고민을 듣고 즉석에서 신탁을 내려준다면 어떨까?"라는 엉뚱한 상상에서 시작되었습니다. 기술적으로는 최근 화두가 되고 있는 Groq의 압도적인 인퍼런스(Inference) 속도를 직접 검증해보고 싶었고, 최신 Next.js 16 환경에서 생성형 AI를 어떻게 실무 레벨로 통합할 수 있을지 실험해보고자 했습니다.
단순한 토이 프로젝트로 시작했지만, 결과적으로는 'AI의 환각(Hallucination) 제어'와 '사용자 경험(UX) 최적화'라는 두 마리 토끼를 잡기 위해 꽤 치열하게 고민했던 과정을 공유하려 합니다.
2. 핵심 기능과 UX
서비스의 핵심은 '속도'와 '재미'입니다. 사용자가 지루함을 느낄 틈을 주지 않도록 설계했습니다.
2.1 AI 무당의 거침없는 '팩트폭력'
사용자가 이름, 생년월일, 성별, 그리고 현재의 고민을 입력하면 AI는 즉시 2026년의 운세를 분석합니다. 기존 운세와 가장 큰 차별점은 결과가 게임 아이템 등급처럼 SSR(Super Special Rare), SR, R, N으로 나뉜다는 점입니다.
- SSR (10% 확률): AI가 인정하는 최고의 행운. 이걸 뽑으면 하루 종일 기분이 좋습니다.
- N (Normal): "노력하세요"라는 시니컬한 조언이 담긴, 꽝에 가까운 등급입니다.
단순히 텍스트만 보여주는 것이 아니라, 각 등급에 맞춰 재물운, 애정운, 건강운 등을 0~100점 사이의 수치로 시각화하여 보여줍니다.
2.2 소장하고 싶은 '부적' 카드 (Result Card)
결과는 단순히 휘발되지 않고, 마치 게임에서 레어 카드를 뽑은 듯한 비주얼로 제공됩니다. html2canvas를 활용해 결과 화면을 즉시 이미지로 렌더링 하여, 사용자가 "나 SSR 떴음!" 하고 친구들에게 자랑하기 쉽게 만들었습니다. 여기에 "와이파이", "배달 쿠폰" 같은 현대적인 행운의 아이템을 매칭하여 소소한 위트도 놓치지 않았습니다.
3. 기술 스택 선정 이유 (Tech Stack)
트렌디하면서도 실용적인 기술셋을 구성하기 위해 고민했습니다.
-
Next.js 16 (App Router): 현재 프론트엔드 씬의 표준입니다. 특히 이번 프로젝트에서는 서버 컴포넌트(RSC)를 적극 활용하여, API 키 노출 없이 안전하게 서버 사이드에서 LLM을 호출하고 결과를 클라이언트로 스트리밍 하기 위해 선택했습니다.
-
Groq SDK (Model: LLaMA 3.3 70B): 이 프로젝트의 '치트키'입니다. GPT-4o도 훌륭하지만, 실시간 상호작용이 중요한 엔터테인먼트 서비스에서 응답 대기 시간은 치명적입니다. Groq는 초당 수백 토큰을 쏟아내는 미친 속도를 보여주며, 사용자가 "로딩 중"을 느낄 새도 없이 결과를 보여줍니다. LLaMA 3.3 70B 모델은 한국어 이해도도 수준급이라 "시니컬한 무당" 페르소나를 완벽하게 소화했습니다.
-
Vanilla Extract: Zero-runtime CSS-in-JS 라이브러리입니다. 스타일드 컴포넌트의 편리함을 가져가면서도 런타임 오버헤드가 없고, 무엇보다 TypeScript와 결합했을 때의 타입 추론이 강력합니다. 테마 변수 관리가 용이해 다크 모드나 카드 디자인 시스템을 구축할 때 큰 도움을 받았습니다.
-
Zod & TypeScript: LLM의 출력을 신뢰할 수 있는 데이터 구조로 변환하기 위한 필수 도구입니다. 이 부분은 아래 딥 다이브에서 자세히 다루겠습니다.
4. 개발 과정의 챌린지 (Deep Dive)
4.1 "AI는 거짓말쟁이" - 구조화된 데이터 검증하기 (Structured Data Validation)
생성형 AI를 서비스에 붙일 때 가장 골치 아픈 문제는 **'출력의 불확실성'**입니다. 개발자는 AI에게 "반드시 JSON 포맷으로 줘"라고 명령하지만, AI는 가끔 마크다운 코드 블록(```json)을 씌워서 주거나, 심지어는 JSON 문법을 틀리기도 합니다. 운이 나쁘면 약속된 키 값(user_name)을 빼먹고 엉뚱한 키(name)를 보내기도 하죠. 이는 클라이언트에서 Undefined 에러를 유발하여 흰 화면을 보여주는 참사로 이어집니다.
이 과정을 해결하기 위해 저는 **이중 방어막(Double Defense Layer)**을 구축했습니다.
1단계: 모델 레벨의 강제 (Json Mode)
Groq API 호출 시 response_format: { type: 'json_object' } 옵션을 활성화하여 모델이 강제로 유효한 JSON 문자열만 뱉도록 설정했습니다.
2단계: 런타임 스키마 검증 (Zod Validation)
JSON으로 받았다고 끝이 아닙니다. 내용물이 우리가 원하는 스키마(Schema)와 일치하는지 확인해야 합니다. 저는 Zod를 이용해 들어오는 데이터를 현관문 앞에서 철저히 검문 검색했습니다.
// src/services/fortune.service.ts 실제 코드 로직
// 1. 우리가 원하는 데이터의 '모양'을 정의합니다.
const FortuneSchema = z.object({
tier: z.enum(['SSR', 'SR', 'R', 'N']), // 이 4개 중 하나가 아니면 에러!
main_copy: z.string(),
power_score: z.object({
money: z.number().min(0).max(100), // 점수가 105점? 에러!
love: z.number().min(0).max(100),
// ...
}),
// ...
});
// ... Service 로직 내부
try {
// 2. AI의 응답을 파싱하고 검증합니다.
const json = JSON.parse(completionContent);
const validated = FortuneSchema.safeParse(json);
// 3. 검증 실패 시 셧다운 대신 '우아한 실패'를 처리합니다.
if (!validated.success) {
console.error('AI가 이상한 데이터를 줬습니다:', validated.error);
return FALLBACK_DATA; // "신령님이 잠시 혼란스러워 하십니다" 같은 기본값 반환
}
return validated.data; // 완벽하게 타입이 보장된 데이터
} catch (error) {
// ...
}
이 패턴을 적용한 덕분에, AI가 가끔 tier: "S등급" 처럼 엉뚱한 값을 뱉더라도 서비스가 멈추지 않고 안전한 기본값(Fallback)으로 대체되어 사용자 경험을 해치지 않게 되었습니다. 가장 좋은 에러 핸들링은 사용자가 에러가 났다는 사실조차 모르게 하는 것임을 다시 한번 깨달았습니다.
4.2 프롬프트 엔지니어링: 페르소나 주입
AI에게 단순히 "운세를 봐줘"라고 하면 너무 점잖고 교과서적인 답변만 돌아옵니다. 재미 요소를 위해 시스템 프롬프트(System Prompt)에 아주 구체적인 지시를 내렸습니다.
"너는 냉소적이지만 능력 있는 AI 무당이다. 말투는 시니컬하고 위트 있어야 하며, 약간의 신비로움을 풍겨야 한다. 무조건 좋은 말만 하지 말고, SSR 등급은 10% 확률로만 부여해라."
이 과정에서 10가지 이상의 다양한 페르소나를 테스트했고, 결과적으로 사용자가 "뼈 맞았다"고 느끼면서도 기분 나쁘지 않을 정도의 **'적당한 매운맛'**을 찾아낼 수 있었습니다.
5. 마치며
이번 프로젝트를 통해 Next.js 16의 안정성과 Groq의 속도가 결합했을 때 얼마나 강력한 시너지가 나는지 확인할 수 있었습니다. 특히 LLM 애플리케이션에서는 모델의 지능만큼이나 **'결과물의 정합성 검증'**이 중요하다는 것을 배웠습니다. 아무리 똑똑한 AI라도, 시스템 안에서는 통제 가능한 모듈이어야 하니까요.
앞으로는 사용자의 피드백을 반영해, 운세 결과를 카카오톡으로 바로 공유하는 기능과, 친구와 운세 배틀을 붙을 수 있는 기능도 추가해 볼 계획입니다.
여러분의 2026년 운세는 과연 'SSR'일까요? 지금 바로 확인해 보세요. 혹시 압니까? AI 신령님이 로또 번호라도 점지해 줄지.