상품 카테고리나 기업명처럼 허용값이 수백·수천 개인 분류는 거대한 enum을 프롬프트에 넣는 순간 비용과 오류가 함께 커진다. 이때 모델이 자연스러운 ‘가설 후보’를 먼저 쓰게 하고, 그 후보를 실제 통제 어휘로 검색·정규화하는 2단계 패턴이 유용하다.
두 단계를 분리한다
- 후보 생성: 모델에 사용자의 표현을 가장 자연스러운 카테고리 경로로 써 보게 한다. 이 값은 아직 정답 목록에 없어도 된다.
- 정규화: 후보와 원문 질의를 임베딩·키워드 검색으로 허용된 분류표의 상위 후보와 비교한다.
- 검증·반환: 점수 임계값을 통과한 공식 ID만 반환하고, 애매하면 사람 검토 큐나 ‘미분류’로 보낸다.
예를 들어 ‘wood coffee table’에서 모델이 Furniture / Living Room / Coffee Tables 같은 후보를 만들면, 검색 계층은 실제 카탈로그의 유효한 ID 중 가장 가까운 항목만 선택한다. 모델의 그럴듯한 환각은 여기서 최종 사실이 아니라 검색용 query expansion으로 쓰인다.
언제 유리한가
| 상황 | 권장 |
|---|---|
| 10~50개 고정 선택지 | 구조화 출력이나 enum을 직접 쓴다 |
| 수백 개 이상·자주 바뀌는 분류표 | 가설 후보 + 검색 정규화를 검토한다 |
| 법적 코드·결제 상태처럼 오답 불가 | 결정적 규칙과 사람 승인으로 처리한다 |
이 패턴은 오타·동의어·사용자 표현을 흡수하지만, 모델이 만든 후보를 사실로 믿으면 안 된다. 정규화 단계의 허용 목록, 임계값, 오류 표본을 지속적으로 평가해야 한다.
관련 문서
- outlines-tips-structured-generation — 토큰 단계에서 구조화 출력을 강제하는 방법
- rag-tutorial-vector-search-python — 벡터 유사도로 후보를 찾는 검색 방식
- rag-tips-reranking — 검색 후보와 최종 판단을 분리하는 기준
참고 자료
- Don’t classify. Hallucinate! — SoftwareDoug (2026-08-10)