- 역할
- 기획 · 풀스택 개발 (개인)
- 기간
- 2026.07 —
01개요
리그·컵·유럽대항전에 흩어진 팀 일정을 한 축으로 통합해 밀집도·폼 같은 지표를 서버에서 계산하고, LLM은 그 계산 결과를 문장으로 옮기는 역할만 맡는 진단·예측 앱입니다. 사람 판단 / 구현 AI(Claude Code) / 다른 벤더의 검증 AI로 역할을 나눈 10단계 파이프라인으로, 화면 5개 중 3개를 요구사항 정의 → 인수 테스트 109건 → 구현 → 교차 리뷰 순으로 완주했습니다. 직접 만든 @usetaehwan/ui를 볼트 그린 테마로 재사용합니다.
02작업 사례
- 사례 1
하루 100요청 예산 아래에서 개발하기
- 문제
- 외부 데이터 API 무료 티어가 하루 100요청입니다. 개발 중 화면을 몇 번 새로고침하면 하루 예산이 몇 분 안에 사라집니다.
- 파악
- 예산은 선택이 아니라 제약이었습니다. 호출을 아끼는 게 아니라, 개발 중에는 호출 자체가 일어나지 않는 구조가 필요했습니다.
- 해결
- 실호출 원본 응답을 한 번 캡처해 파일로 저장(리그 380경기·컵 879경기 등 15개)하고 기본 모드를 replay로 두었습니다. 예산 상한도 100이 아닌 80으로 낮춰 경계 오차를 흡수하고, sync_log로 캡처 이후 실 API 호출 0회를 확인했습니다.
- 사례 2
형식은 맞는데 내용이 빈 AI 응답이 '성공'으로 판정되던 결함
- 문제
- AI 진단 배지가 'AI 분석'으로 바뀌었는데 화면은 빈 껍데기였습니다. 실제로 받은 응답은 {"headline":"placeholder", "metric":"", "value":""} 같은 형태였습니다.
- 파악
- JSON 스키마의 required는 키가 존재하는지만 보장하고, 빈 문자열과 빈 배열도 통과시킵니다. 스키마만 믿고 성공으로 처리한 것이 원인이었고, 모델 effort를 낮춰 사고 토큰이 0이 된 것이 빈 응답을 유발한 부가 원인이었습니다.
- 해결
- 재료 통제(프롬프트에 들어갈 계산 결과를 코드가 만든다) → 코드 게이트(표본 5건 미만이면 호출하지 않는다) → 응답 검증(파싱 단계에서 빈 값 거부) 세 겹에 스키마를 더했습니다. LLM은 계산 결과를 문장으로 옮기는 역할만 맡고, 숫자는 서버가 만듭니다.
- 사례 3
같은 입력인데 프롬프트 지문이 흔들린다
- 문제
- 저장된 AI 진단을 재사용해야 하는데 매번 규칙 기반 폴백이 표시됐습니다. 폴백이 정상 동작해서 아무것도 깨지지 않았고, 그래서 한참 눈치채지 못했습니다.
- 파악
- 재사용 판정에 쓰는 프롬프트 SHA-256 지문이 JVM을 다시 띄울 때마다 달라졌습니다. 원인은 Map.copyOf가 돌려주는 불변 맵 — 순회 시작 위치와 방향이 기동마다 System.nanoTime()으로 뽑는 SALT로 정해집니다. JVM 30회 기동으로 실측하니 항목 4개 컬렉션에서 7가지 순서가 나왔습니다. 같은 원인이 2회, 정렬 tiebreaker 누락으로 같은 규칙의 다른 표면이 1회 더 발견됐습니다.
- 해결
- enum 선언 순서로 순회를 고정하고 회귀 테스트 4개로 봉인했습니다. 두 번째 발생 시점에 '프롬프트에 들어가는 컬렉션은 순회 순서를 코드로 고정한다'를 규칙으로 승격했고, 저장분을 버릴 때 지문 불일치를 로그에 남기도록 바꿨습니다.
- 사례 4
합의된 지표 정의를 데이터 검산으로 뒤집다
- 문제
- 일정 밀집 구간의 정의를 정하는 문답에서 '간격 4일 이하 경기가 2회 이상 연속'이라는 정의가 추천되고 수용 직전이었습니다. 문장으로는 자연스러웠습니다.
- 파악
- 실제 한 시즌 52경기로 두 정의를 계산해 봤습니다. 추천안은 전 대회 8구간·리그만 3구간, 대안(임의의 14일 창 안 5경기 이상)은 3구간·0구간. 지표의 목적이 '전 대회 일정이 리그 단독보다 얼마나 빡빡한가'인데, 리그 단독에서도 밀집을 검출하는 정의는 변별력이 없었습니다.
- 해결
- 대안을 채택하고 응답 계약에 승격했습니다(14일·5경기는 파라미터). 인수 테스트에 수치를 고정해 정의를 바꾸려면 테스트가 먼저 깨지게 했고, '숫자를 만드는 규칙은 문장이 아니라 결과표로 승인한다'를 파이프라인 규칙에 추가했습니다.
03핵심 기능
API 예산 아래 동기화
외부 데이터 API 무료 티어가 하루 100요청이라, 실호출 원본을 캡처한 뒤 기본 모드를 replay로 두었습니다. 캡처 이후 개발 중 실 API 호출은 0회입니다.
LLM 환각 세 겹 억제
재료 통제 → 코드 게이트(표본 5건 미만이면 호출하지 않음) → 응답 검증. 스키마의 required가 키 존재만 보장해 빈 문자열로 채운 응답이 '성공'으로 판정되던 결함을 코드 레벨 검증으로 막았습니다.
프롬프트 결정론
Map.copyOf가 JVM 기동마다 순회 순서를 바꿔 프롬프트 지문이 흔들리고, 저장된 진단이 조용히 버려지던 문제를 30회 기동에서 7가지 순서로 실측해 확인했습니다. enum 순서 고정과 회귀 테스트로 봉인했습니다.
역할 분리 파이프라인
요구사항 승인 전 구현 금지, 기계 검사 통과 전 리뷰 금지 같은 게이트로 절차를 강제했습니다. 백엔드 자동 테스트 289개를 갖췄고, 무료 플랜을 유지하도록 저장된 진단은 API 키 없이도 서빙되게 설계했습니다.
04스택
Spring Boot 3.5Java 21Next.js 15TypeScriptTailwind v4PostgreSQLNeonAnthropic API
◀ 도감으로B