개요
항목 | 내용 |
기간 | 2025.03 ~ 2025.05 |
역할 | API 및 배치 시스템 구현 담당 |
기술 스택 | Kotlin, Spring Boot, OpenAI Batch API |
배경
다나와 가격비교 플랫폼에서 상품 데이터를 기반으로 AI가 생성한 추천 문구를 제공하는 서비스를 구축해야 했습니다. 관리자가 다양한 컨셉의 프롬프트를 설정하고, 카테고리별로 추천 문구를 자동 생성하여 API로 제공하는 시스템이 필요했습니다.
문제
•
관리자가 프롬프트와 대상 카테고리를 설정할 수 있어야 함
•
주 단위로 추천 문구를 갱신하는 배치 시스템이 필요
•
카테고리 간 인기 상품이 겹치는 경우 중복 처리가 필요
•
AI 응답의 품질을 검증할 수 있는 프로세스가 필요
•
OpenAI API 호출 비용을 최적화해야 함
무엇을 했나
시스템 아키텍처
flowchart TD
A[관리자 페이지] -->|프롬프트 & 카테고리 설정| B[관리자 API]
B --> C[배치 스케줄러<br>주 1회]
C --> D[상품 데이터 조회]
D --> E[카테고리 간 중복 제거]
E --> F[OpenAI Batch API 호출]
F --> G[1분 주기 폴링]
G --> H{결과 확인}
H -->|성공| I[파싱 & 저장]
H -->|파싱 실패| J[해당 건만 실패 처리]
H -->|미완료| G
I --> K[추천 문구 API 제공]Mermaid
복사
구현 상세
1. OpenAI Batch API 활용
•
실시간 API 대신 Batch API(24시간 내 처리 보장)를 선택한 이유: OpenAI 공식 정책상 Batch API는 실시간 API 대비 토큰당 비용 50% 할인
•
Spring Cloud OpenFeign으로 OpenAI API 클라이언트를 선언적으로 정의하여 외부 API 연동 코드 간결화
•
Kotlin의 tailrec(꼬리 재귀)를 활용하여 배치 상태 폴링을 구현 — 컴파일러가 반복문으로 변환하여 스택 오버플로우 없이 장시간 폴링 가능
•
1분 주기 폴링으로 처리 결과를 확인하고, 배치 상태(COMPLETED, IN_PROGRESS, VALIDATING, FINALIZING)에 따라 분기 처리
2. 프롬프트 최적화
•
토큰 소비를 줄이면서도 품질을 유지하기 위해 프롬프트 튜닝 수행
3. 품질 검증 — 블라인드 테스트
•
같은 상품 목록에 대해 서로 다른 프롬프트로 각각 n회차 돌린 뒤 토큰 소모량 평균 측정
•
샘플링한 프롬프트 결과로 기획자와 개발자 동료들과의 블라인드 테스트 수행
•
프롬프트 결과에 대한 평가는 유의미한 퀄리티 차이가 없었지만, 토큰 사용량은 10% 정도 절감함.
4. AI 응답 포맷 불일치 처리
•
AI 응답은 \n\n으로 구분된 3개의 문장으로 구성되어야 하지만, 간혹 포맷이 다른 응답이 발생
•
3개가 아닌 경우 null을 반환하고 mapNotNull로 걸러내어, 전체 배치를 실패 처리하지 않고 해당 건만 개별 제외
// AI 응답 포맷 검증
private fun parseResponse(response: String): List<String>? {
val lines = response.split("\n\n")
return if (lines.size == 3) {
lines.map { it.trim() }
} else {
null // 포맷 불일치 → 해당 건만 제외
}
}
Kotlin
복사
5. 상품 중복 제거
•
카테고리 간 인기 상품이 겹치는 경우 distinctBy { it.productCode }로 상품 코드 기준 중복 제거 후 배치 파일 생성
6. 배치 로그 기록
•
각 배치 요청별로 요청/응답 토큰 수, 문자 수, finish reason 등을 DB에 기록
•
이 로그를 통해 프롬프트 별 토큰 소비량을 정량적으로 비교할 수 있었고, 이것이 블라인드 테스트의 근거 데이터가 됨
결과
성과
•
프롬프트 최적화를 통해 품질 저하 없이 토큰 사용량 약 10% 절감
•
파싱 실패 건을 개별 처리하여 배치 전체 실패율 0% 유지
•
OpenAI Batch API 활용으로 실시간 API 대비 토큰당 비용 50% 절감 (OpenAI Batch API 공식 정책 기준)
•
관리자가 프롬프트와 카테고리를 직접 설정할 수 있어 기획자의 자율도가 높아짐
•
블라인드 테스트를 통해 프롬프트 품질을 객관적으로 검증하는 프로세스를 확립
배운 점
•
AI 응답은 항상 동일한 포맷으로 돌아오지 않으므로, 파싱 실패를 정상 흐름의 일부로 간주하고 개별 재처리하는 방어적 설계가 중요함
•
토큰을 줄이면 비용은 내려가지만 품질도 내려갈 수 있어서, 블라인드 테스트 같은 객관적 검증 수단이 있어야 의사결정이 가능함
•
24시간 내 처리를 보장하는 외부 API와 연동할 때, 폴링 주기/타임아웃/부분 실패 처리 등 방어적 설계가 필수적이라는 걸 체감함