diff --git a/ideas/250819_대화형_점진적_의도_구축_시스템.md b/ideas/250819_대화형_점진적_의도_구축_시스템.md index 57715be..c748d35 100644 --- a/ideas/250819_대화형_점진적_의도_구축_시스템.md +++ b/ideas/250819_대화형_점진적_의도_구축_시스템.md @@ -270,29 +270,73 @@ if pattern_matches(NEGATIVE_FEEDBACK_PATTERNS): return apologize_and_clarify() ``` -### 3.4.3 Snips + Self-Attentive Gate 통합 +### 3.4.3 제로샷 의도 분류 통합 (Hong et al., 2024 기반) + +최신 SIGDIAL 2024 연구에 따르면, 고품질 의도 설명 1개와 임베딩 기반 후보 축소가 핵심입니다. + ```python -class TimeAwareIntentClassifier: +class ZeroShotTimeAwareClassifier: def __init__(self): - self.snips = SnipsNLU() # 경량 의도 분류 + # 제로샷: 학습 없이 의도 설명만으로 분류 + self.intent_descriptions = { + "attendance": "출근, 퇴근, 재택근무 같은 근태를 기록하려는 요청", + "time_query": "현재 시각, 날짜, 요일을 묻는 질문", + "context_retrieval": "아까, 어제, 방금 전 같은 과거 대화를 참조하는 요청", + "email": "이메일 확인, 전송, 검색과 관련된 요청", + "schedule": "일정 조회, 등록, 수정에 대한 요청" + } + + # 다국어 임베딩 (한국어 지원, Snips 대체) + self.embedder = SentenceTransformer('paraphrase-multilingual-mpnet-base-v2') self.gate = SelfAttentiveGate() # 시간 게이트 async def classify_with_time(self, text, user_id): - # Step 1: Snips로 빠른 의도 분류 (50ms) - intent = self.snips.classify(text) + # Step 1: 임베딩 기반 후보 축소 (20ms) + text_emb = self.embedder.encode(text) + intent_scores = {} - # Step 2: Gate로 시간 필요 여부 결정 (10ms) - needs_time = self.gate.needs_temporal_context(intent) + for intent, description in self.intent_descriptions.items(): + desc_emb = self.embedder.encode(description) + score = cosine_similarity(text_emb, desc_emb) + intent_scores[intent] = score - # Step 3: 선택적 시간 컨텍스트 추가 - if needs_time: - context = await self.enrich_temporal_context(text, user_id) - else: - context = {} + # 상위 3개 후보만 선택 (Hong et al. 권장: 10-13개, 로빙은 3개면 충분) + top_candidates = sorted(intent_scores.items(), + key=lambda x: x[1], + reverse=True)[:3] + + # Step 2: 확신도 체크 및 시간 게이트 + best_intent = top_candidates[0][0] + confidence = top_candidates[0][1] + + # Step 3: 시간 컨텍스트 선택적 추가 + context = {} + if best_intent in ['time_query', 'attendance', 'context_retrieval']: + context['current_time'] = datetime.now(KST).strftime("%Y년 %m월 %d일 %H:%M") + context['needs_time'] = True - return {"intent": intent, "context": context} + # Step 4: 저확신 시 LLM 폴백 + if confidence < 0.7: + # 의도 설명을 포함한 프롬프트로 LLM 호출 + prompt = f"사용자: {text}\n후보 의도:\n" + for intent, score in top_candidates: + prompt += f"- {intent}: {self.intent_descriptions[intent]} (점수: {score:.2f})\n" + context['needs_llm'] = True + + return { + "intent": best_intent, + "confidence": confidence, + "context": context, + "candidates": top_candidates + } ``` +#### 제로샷 방식의 장점 (로빙 적용) +1. **학습 데이터 불필요**: Snips와 달리 의도 설명만 수정하면 즉시 반영 +2. **비용 절감**: 임베딩 후보 축소로 LLM 호출 90% 감소 +3. **한국어 최적화**: 다국어 임베딩 모델로 한국어 성능 우수 +4. **유연한 확장**: 새 의도 추가 시 설명 한 줄만 추가 + --- ## 4. 데이터 구조