📝 한줄 요약
21기 때 만들어둔 사주 서비스를, 방학 기간에 조금씩 만져봤다. 실제로 몇 개의 사주를 넣어보니 틀린 결과들이 나왔고, 거기서부터 버그 수정, 무료 API 삽질, 실전 데이터 구축, 스트리밍 응답까지 — 천천히 66개 커밋이 쌓이면서 "프로토타입"이 조금씩 "제품"에 가까워졌다.
바쁘시면 이것만 읽어도 돼요:
AI가 짠 코드의 테스트가 34개 전부 통과인데, 실제로 내 사주를 넣어보니 14일이나 틀렸다
무료 AI API(Gemini, Groq)로 돌리려니 하루 사주 1~2건이 한계. 결국 Gemini 결제 등록 → 1건당 12원
"메마른 대지에 핀 꽃" 같은 기존 사주 앱 비유를 탈피하기 위해 MZ 비유 사전(80개+) 구축
NDJSON 스트리밍으로 34초 대기 → 0.2초 만에 화면 전환
40대 이상 연애 표현 자동 치환, 60대 이상 부모 단정 금지 등 나이대별 필터링
🎯 이런 분들께 도움돼요
AI로 서비스를 만들어보려는 1인 개발자/창업자
"프로토타입은 만들었는데 제품 수준이 아닌데..." 하는 분
AI 코딩 도구에 관심 있는 비개발자 — "실제로 서비스 운영하면 어떤 일이 생기는지" 궁금한 분
😫 문제 상황 (Before)
한동안 손을 못 댔다. 지피터스 방학(?) 기간 동안 시간이 날 때마다 조금씩 만져본 정도. 엄청 열심히 했다기보다는, 생각날 때 열어서 이것저것 고쳐보는 식이었다. 22기에서 오픈클로 헤르메스 배우면서도 짬짬이 해보려고 한다. 어쨌든 어느 날 다시 프로젝트를 열고 실제로 내 사주를 넣어봤다.
결과가 틀렸다.
다른 사주 사이트에서 보던 내 사주와 달랐다. 일주가 완전히 다른 값이 나왔고, 오행 분포도 맞지 않았다. 그런데 자체 테스트는 34개 전부 통과 상태였다.
여기서부터 하나씩 고쳐보기 시작했다.
🛠️ 사용한 도구
Claude Code (bkit 플러그인): 전체 개발, 버그 분석, 프롬프트 설계, 테스트
AI 해설: Gemini 2.5 Flash (현재) / Groq Llama 3.3 70B (초기)
pencil.dev: 랜딩 페이지 디자인
Vercel: 프로덕션 배포
🔧 작업 과정
내 사주가 14일이나 틀렸다 — 근데 테스트는 통과?
1993년 4월 8일 오후 2시를 넣었다. 다른 사주 사이트에서는 계유/병진/기미/신미가 나오는데, 우리 서비스에서는 일주부터 완전히 다른 값이 나왔다.
원인은 만세력 계산의 기준점 하나. 숫자 하나를 40에서 54로 바꾸니까 해결. 하지만 가장 소름 끼쳤던 건, 테스트 코드도 같은 잘못된 값을 "정답"으로 넣어뒀다는 것. 자기가 자기를 채점하는 구조. 실제 사용자 데이터로 외부 검증을 하지 않았으면 런칭 후에야 발견됐을 거다.
무료 AI API와의 전쟁
사주 계산은 고쳤는데, AI 해설이 안 나왔다. API 크레딧이 없었다.
Gemini: "무료 1,500 요청"이라더니 실제 내 계정은 일일 20 요청. 사주 1건이면 끝
Groq: 무료 14,400 요청이라 옮겼더니 이번엔 일일 토큰 한도. 사주 2건이면 소진
70B → 8B 자동 폴백 시스템을 만들었지만, 8B도 분당 한도에 걸림
결국 Gemini에 결제 계정을 등록해서 한도를 풀었다. 사주 1건당 약 12원. 무료에 집착하느라 이틀을 날렸다.
50,000명 실전 데이터 — AI 해 설의 게임 체인저
AI에게 "사주 해설 써줘"라고 하면 "토 기운이 많으시네요. 안정적인 성격입니다." 수준의 일반론만 나왔다.
결정적 차이를 만든 건 실전 도메인 데이터였다. 60갑자 일주론 데이터를 구조화해서 프롬프트에 주입했다.
예를 들어 "기미(己未) 일주"를 AI가 볼 때:
이전: "기미" 두 글자만 보고 알아서 해석
이후: "절대 움직이지 않고 꼿꼿하며 고집이 센 관인상생 비견. 적성직업(50,000명 통계): 교육자, 강사, 상담사, 작가..."
MBTI도 유형명 라벨("INTJ") 대신 12개 속성 서술형 프로필(핵심 성격, 연애 스타일, 스트레스 반응, 성장 방향 등)을 넣었다.
기존 사주 앱 비유를 탈피하라 — 언어 표현 레퍼런스 사전
AI에게 사주 해설을 쓰게 하면 "메마른 대지에 핀 꽃", "드넓은 바다를 항해하는" 같은 뻔한 자연 비유가 나온다. 기존 사주 앱이랑 똑같아진다.
그래서 100개 이상의 비유 문장을 만들었다. 카테고리별로 자동 선별해서 프롬프트에 3개씩 주입:
성격: "에스프레소처럼 진한데 한번 맛 들이면 못 끊어"
약점: "네 인생의 최종보스는 네 고집이야"
연애: "네 연애는 로맨스가 아니라 스릴러야"
커리어: "맨날 백코러스 하다가 네 무대를 놓치고 있어"
Before: "메마른 대지에 핀 꼿꼿한 꽃, 타인을 위해 녹아내리는 열정" After: "겉으론 덤덤, 속으론 세상을 쥐고 흔드는 흙덩이"
점쟁이 코스프레를 벗기다
서비스 전체 텍스트 80개 항목을 화면 순서대로 나열하고, 하나씩 톤을 바꿨다. 사용성 좋은 국내 앱들의 UX writing을 벤치마킹해서, 운세 앱이 아니라 커머스/핀테크/에듀테크에서 검증된 패턴을 가져왔다.
Before
After
"네 눈을 보니... 다시 왔구나"
"오늘은 뭐 볼래?"
"운명 해설"
"운명 리딩"
"AI 서비스가 한계에 도달"
(이런 말 자체를 안 함)
"요청이 너무 많아"
"지금 잠깐 쉬고 있어. 조금 있다가 다시 와줘."
핵심 규칙: 한 문장에 상황 + 행동 유도, "실패"라는 단어를 서비스에서 완전히 지움.
34초 대기를 0.2초로 — NDJSON 스트리밍
가장 큰 체감 변화. 이전에는 "운명 보기" 누르면 34초 동안 로딩 화면만 보다가 한꺼번에 결과가 나왔다. Vercel 60초 타임아웃에 걸려서 아예 결과가 안 나오는 경우도 있었다.
API 응답을 NDJSON 스트리밍으로 바꿨다:
0.2초: 사주 데이터 도착 → 즉시 화면 전환
10초~: 해설이 하나씩 채워지기 시작
사용자는 "운명을 읽는 중... 6/18" 카운터를 보면서 진행
같은 총 시간이지만 체감은 완전히 다르다.
대운(10년 운) — 다른 앱에 있고 우리한테 없던 것
"다른 사주 앱 대비 부족한 게 뭘까?" 물어봤더니 답이 바로 나왔다. 대운. 10년 주기 운의 흐름인데 우리 서비스엔 아예 없었다.
대운 계산은 생각보다 복잡했다. 양간/음간에 따른 순행/역행, 절기까지 일수 계산, 율리우스일수(JDN) 변환까지. 처음에 대운 시작이 32세로 나왔는데, 실제로는 9세여야 했다.
이제 "재물운"이나 "올해 운세"에서 "지금 기미 대운이라 토의 안정기인데, 39세부터 경신 대운이 오면 커리어에 변화가 올 거야" 같은 구체적 해설이 가능해졌다.
"먼저 분석해, 그다음에 써" — 2-Stage 프롬프트 체이닝
18개 카테고리를 한 번에 "다 써줘"라고 하면 뒤로 갈수록 품질이 떨어졌다. 그래서 2단계로 나눴다.
Stage 1 (1회 호출): 사주를 먼저 분석해서 핵심 인사이트를 구조화된 JSON으로 추출. Stage 2 (3회 × 6카테고리): Stage 1의 인사이트를 기반으로 해설 작성. 이전 청크의 제목들을 다음 청크에 전달해서 내용 반복 방지.
18개 해설이 하나의 스토리처럼 이어졌다. "일주 해설"에서 발견한 성격 특성이 "연애운"에서도 자연스럽게 연결되는 식.
60대 이상에서 "연애" "썸" 쓰지 마
테스트 중 60대 생년월일을 넣었더니 "연애"라는 단어가 나왔다. 물론 연애를 하고 썸을 타는 분들도 많겠지만, 사주 해설이라는 맥락에서는 조심스러운 부분이 있다. "부모님이 이러이러합니다"라는 표현도, 부모님이 안 계신 분이 보면 불편할 수 있고. 자녀가 있을지 없을지 모르는 상황에서 "자녀가~" 라는 표현도 마찬가지.
그래서 나이대별 강제 필터링을 후처리에 넣었다.
40대+: "연애", "썸" 같은 표현을 나이에 맞게 치환
60대+: "부모님이" → "부모님이 계시다면"
프롬프트에 규칙을 넣어도 AI가 무시할 때가 있다. 그래서 코드에서 강제로 치환하게 했다. AI를 100% 믿지 않고, 후처리로 보완하는 패턴.
10명 랜덤 테스트 — 패턴으로 잡는 디테일
80~00년생 다양한 조합 5건을 돌리고 자동 품질 체크 스크립트로 검사했다. 발견한 것들:
"네" 29번 반복. 한 카테고리에서 "네 사주에... 네가... 네 안에..." → "10번 이상 쓰지 마" 규칙 추가
"~니까."로 끝나는 문장. 한국어에서 자연스럽지 않은 종결 → "~거든.", "~이야."로 마무리하도록 규칙 추가
이름 호출 문제. "강지인아" → "지인아"로 성 빼고 부르도록 후처리, 1회 결과 당 최대 3회.
이런 건 한 번 돌려보는 것만으로는 안 보인다. 여러 건을 돌려보고 자동 검사로 패턴을 잡아야 보이는 것들이다.
✅ 결과 (After)
항목
Before (PRD 완성 시점)
After (현재)
사주 정확도
14일 오차
타 사주 사이트와 100% 일치
해설 카테고리
12개 (6/3/3)
18개 (6/6/6)
해설 품질
AI 일반론
50,000명 데이터 + MZ 비유 사전
체감 속도
34초 대기
0.2초 화면 전환 (스트리밍)
AI 비용
무료 (한도 지옥)
₩12/건
UX writing
"기운이 어지럽구나~"
사용성 좋은 국내 앱 스타일
나이 대응
없음
40대+ 필터링
커밋
21개
66개
💬 배운 것
테스트 34개 통과 ≠ 정확함. AI가 코드와 테스트를 같이 짜면 같은 오답을 공유한다. 실제 데이터로 외부 검증 필수.
AI 해설 품질 = 넣어주는 데이터의 깊이. "써줘"가 아니라 50,000명 실전 통계를 먹인 뒤 "이걸 기반으로 써줘"라고 해야 한다.
비유를 AI에게 맡기면 다 비슷해진다. 비유 사전을 직접 만들어서 주입해야 차별화가 된다.
스트리밍은 체감을 바꾼다. 총 시간은 같아도 "0.2초에 화면 전환 + 점진적 채움"은 완전히 다른 경험.
AI의 불완전함은 코드로 보완한다. 프롬프트 규칙을 무시해도 후처리에서 강제 치환하면 100% 적용.
📋 재사용 가능한 프롬프트
프롬프트 1: NDJSON 스트리밍 API
내 API 응답이 30초 이상 걸려서 사용자가 이탈해. NDJSON 스트리밍으로 바꿔줘. 먼저 메타데이터를 보내고, AI 생성 결과가 나올 때마다 부분 전송하는 구조로. 프론트에서는 fetch + getReader()로 점진적 렌더링.
프롬프트 2: MZ 비유 사전으로 AI 어휘 차별화
AI가 만든 텍스트가 다른 서비스와 비유가 똑같아. [도메인]에 맞는 현대적 비유 사전을 만들어줘. MZ 용어, 드라마/영화, 음악, 게임, 일상 비유를 카테고리별로. 프롬프트에 3개씩 랜덤 주입하는 구조로.
🚀 앞으로
지난 주에 개인 사업자도 냈고, 도메인도 샀다. 22기 스터디에서 오픈클로와 헤르메스 공부하면서 짬짬이 계속 만져보려고 한다. 아직 오류 나는 결과들이 있어서 지인들에게 링크를 못 뿌렸는데, 다음주 쯤에는 꼭!!! 최소 30명의 테스터를 모아봐야겠다.
남은 건 결제 연동 → 베타 테스트 → 런칭. 아직 갈 길이 멀지만, 시간 날 때마다 조금씩 붙잡아 봐야지!!!