왜 사주 분석 자동화가 4초만에 30페이지 PDF를 만드는가
사주 분석은 도메인 전문가만 다루던 작업이었습니다. 한 건 분석에 두세 시간이 걸렸고, 주문이 몰리면 그날 밤은 책상에서 보내야 했습니다. auto-saju 케이스에서 만든 파이프라인은 같은 작업을 4초 안에 끝냅니다. 그러나 핵심은 "GPT를 썼더니 빨라졌다"가 아닙니다. 도메인 룰을 코드로 만들고, LLM을 그 룰의 빈칸 채우기에만 쓴 것이 차이를 만들었습니다.
사람이 직접 봐야만 가능했던 일
사주 분석은 정보가 누적되는 작업입니다. 양력 생년월일과 출생시간을 받아 만세력으로 사주팔자를 도출하고, 오행과 십신을 계산하고, 대운 흐름을 읽고, 마지막으로 성격·직업·재물·건강 등 11개 영역에 대한 해석을 풀어쓴다. 각 단계가 정확해야 마지막 해석이 의미를 갖습니다.
그래서 수작업 운영의 가장 큰 문제는 시간이 아니라 품질의 흔들림이었습니다. 같은 사람이 봐도 컨디션에 따라 결과가 달라졌고, 주문이 밀리면 분석이 짧아졌고, 분석이 짧아지면 환불 요청이 늘었습니다.
"분석을 잘 하는 게 문제가 아니라, 잘 하는 걸 매일 똑같이 반복하는 게 문제였습니다."
GPT-4를 분석가가 아닌 도구로 쓰는 법
처음 떠오르는 발상은 "GPT에게 사주를 분석해달라고 하면 되지 않나"입니다. 실제로 해보면 그렇지 않습니다. LLM은 만세력 계산을 못합니다. 음력·양력 변환을 자주 틀리고, 십신 계산은 매번 다른 답을 내고, 대운 시작 나이는 환각으로 채웁니다.
대신 우리가 한 건 LLM에게 빈칸을 채우게 한 것입니다. 사주 8자, 오행 분포, 십신 비율, 현재 대운 — 이 모든 것을 코드로 결정한 뒤, 그 결과를 프롬프트의 입력으로 주고 "이 사주를 가진 사람의 직업 성향을 풀어써라"라는 식으로만 LLM을 호출했습니다.
def assemble_prompt(saju_data: SajuData, section: str) -> str:
"""LLM에게 '분석해달라'가 아니라 '풀어써달라'고 요청한다."""
return PROMPT_TEMPLATES[section].format(
pillars=saju_data.pillars, # 코드가 계산
five_elements=saju_data.elements, # 코드가 계산
ten_gods=saju_data.ten_gods, # 코드가 계산
current_daewoon=saju_data.daewoon, # 코드가 계산
)이 차이가 실무에서는 큽니다. 도메인 룰은 결정적이고 반복가능하기에 같은 입력이 항상 같은 결과를 냅니다. LLM은 자연어 설명만 담당하므로 환각이 생기더라도 "데이터는 맞고 표현이 어색한" 수준으로 제한됩니다.
4초의 안쪽 — 파이프라인 분해
전체 처리는 다섯 단계로 쪼개집니다. 각 단계가 실패하면 다음 단계로 넘어가지 않고 큐에 다시 들어갑니다.
1. 입력 사전조립 (≈100ms)
생년월일·시간·성별 입력을 받아 만세력 라이브러리로 사주 8자를 도출합니다. 음력 변환과 윤달 처리는 검증된 데이터셋을 그대로 사용합니다.
2. GPT-4 호출, 구조화 출력 강제 (≈3초)
11개 섹션을 각각 별도 호출로 처리합니다. JSON 스키마를 강제(response_format)하여 누락 필드가 없도록 합니다. 한 섹션이라도 검증을 통과하지 못하면 그 섹션만 재시도합니다.
response = client.chat.completions.create(
model="gpt-4",
response_format={"type": "json_schema", "json_schema": SECTION_SCHEMA},
messages=[...],
)3. 결과 검증 (≈50ms)
스키마 통과만으로는 부족합니다. "직업 영역인데 결혼 얘기가 나오면" 카테고리 룰로 거부합니다. 거부된 섹션은 한 번 더 호출(최대 2회). 그래도 안 되면 사람에게 알림.
4. PDF 자동 조판 (≈600ms)
Prawn(Ruby) 또는 Python의 ReportLab으로 한글 폰트(Pretendard, 나눔고딕)를 임베드한 30페이지 PDF를 생성합니다. 표지·목차·본문·요약을 분리된 모듈로 조립.
5. SMTP 발송 (≈150ms)
SendGrid로 비동기 발송. 발송 결과를 EmailLog에 기록하여 실패 시 관리자가 한 번 클릭으로 재발송.
-- email_logs: 이력 추적용 핵심 테이블
SELECT order_id, status, error_message, created_at
FROM email_logs
WHERE status = 'failed' AND created_at > now() - interval '1 day';도메인 + LLM = 진짜 자동화
이 시스템이 안정적인 이유는 GPT가 똑똑해서가 아니라, GPT가 틀려도 되는 영역에만 들어가 있기 때문입니다. 사주 8자 같은 결정적 데이터는 코드가 책임지고, GPT는 표현만 담당합니다.
LLM 자동화 프로젝트를 검토할 때 우리가 가장 먼저 확인하는 것은 "LLM이 틀리면 시스템이 어디까지 망가지나"입니다. 결정적 영역과 생성 영역을 분리할 수 있는 프로젝트일수록 자동화 효과가 큽니다. 분리할 수 없는 도메인이라면 자동화의 ROI를 다시 따져야 합니다.
자세한 케이스: auto-saju