# 로빙 의도 파악 개선 플랜 **날짜**: 2025-10-17 **작성자**: Claude Code **관련 문서**: - `/home/admin/ivada_project/DOCS/ideas/250920_happybell80_로빙_의도분석_전략.md` - `/home/admin/ivada_project/DOCS/ideas/250819_대화형_점진적_의도_구축_시스템.md` - `/home/admin/ivada_project/DOCS/ideas/250819_시간인식_제로샷_의도분류_시스템.md` **현재 구현**: `/home/admin/ivada_project/rb8001/app/brain/decision_engine.py` (255줄) --- ## 1. 현재 상태 분석 ### 1.1 현재 구현 (DecisionEngine) **방식**: 정규식 패턴 매칭 ONLY ```python def analyze_intent(self, message: str) -> Tuple[IntentType, float]: for intent_type, patterns in self.intent_patterns.items(): for pattern in patterns: if re.search(pattern, message_lower): return intent_type, confidence return IntentType.UNKNOWN, 0.3 ``` **장점**: - ✅ 빠름 (< 10ms) - ✅ 비용 없음 (LLM 호출 불필요) - ✅ 예측 가능 **단점**: - ❌ 복잡한 질문 처리 불가 - ❌ 시간 인식 없음 ("오늘 몇일이야?" → UNKNOWN) - ❌ 맥락 이해 없음 - ❌ 멀티턴 대화 불가 - ❌ 확신도 낮을 때 대응 없음 ### 1.2 실제 문제 사례 | 사용자 질문 | 현재 처리 | 문제점 | |------------|----------|--------| | "오늘 몇일이야?" | UNKNOWN | 시간 질문 패턴 없음 | | "리버스마운틴 유사 기업 찾아서 가치평가해줘" | UNKNOWN | 복잡한 멀티스텝 질문 | | "아까 말한 그 기업 투자 단계는?" | UNKNOWN | 맥락 참조 불가 | | "협업툴 시장 seed 평균은?" | UNKNOWN | 도메인 특화 질문 | **결론**: 현재는 **단순 명령만 처리 가능**. 종합적 질문은 처리 불가. ### 1.3 아키텍처 구조적 문제 (2025-11-26 추가) **현재 구조의 근본적 문제**: - IntentType이 스킬/액션과 직접 1:1 매핑되어 있음 - 의도 파악이 곧 스킬 선택으로 이어지는 구조 - 진정한 "의도 파악(무엇을 원하는가)" → "행동 계획(어떻게 할 것인가)" → "스킬 선택(어떤 도구를 쓸 것인가)"의 단계적 분리가 없음 **예시**: ``` 현재: "일정 등록" → calendar_event intent → calendar_confirm action → CalendarSkill 문제: intent가 이미 구체적 행동(스킬)과 결합됨 ``` **개선 방향**: 1. **의도 파악 단계**: 추상적 목표 파악 - 예: "일정 관리", "정보 검색", "커뮤니케이션", "문서 처리" - 사용자가 무엇을 원하는지 추상적 수준에서 이해 2. **행동 계획 단계**: 구체적 행동 결정 - 예: "일정 등록", "일정 조회", "일정 삭제", "일정 수정" - 의도를 달성하기 위한 구체적 행동 계획 3. **스킬 선택 단계**: 적절한 도구 선택 - 예: `calendar_skill.create_event`, `calendar_skill.get_events`, `calendar_skill.delete_event` - 행동을 수행할 적절한 스킬 선택 **3단계 구조의 장점**: - 의도와 구현의 분리: 같은 의도라도 다른 행동/스킬로 구현 가능 - 확장성: 새로운 스킬 추가 시 기존 의도 재사용 가능 - 유연성: 행동 계획 단계에서 여러 대안 고려 가능 - 명확성: 각 단계의 책임이 명확히 분리됨 --- ## 2. 문서에서 제안한 방법론 ### 2.1 하이브리드 시스템 (250920 문서) **아키텍처**: ``` 사용자 메시지 ↓ ┌─────────────────────────┐ │ 1단계: 정규식 FastPath │ → 명확한 패턴 (이메일, 뉴스 등) └─────────────────────────┘ ↓ (매칭 실패) ┌─────────────────────────┐ │ 2단계: 임베딩 후보 축소 │ → 제로샷 분류 (상위 3개) └─────────────────────────┘ ↓ (확신도 < 0.7) ┌─────────────────────────┐ │ 3단계: LLM 확인 │ → 최종 의도 결정 └─────────────────────────┘ ``` **장점**: - 단순 명령: 정규식으로 빠르게 처리 (기존 유지) - 복잡한 질문: LLM 활용 - LLM 호출 최소화 (비용 절감 70%) ### 2.2 제로샷 의도 분류 (250819 문서) **핵심**: 1. 의도 설명(description)만으로 분류 (학습 데이터 불필요) 2. 임베딩 유사도로 후보 축소 (20ms) 3. 확신도 낮으면 LLM 폴백 **구현**: ```python intent_descriptions = { "time_query": "현재 시각, 날짜, 요일을 묻는 질문", "startup_analysis": "스타트업 기업 분석, 유사 기업 검색, 가치평가 요청", "context_retrieval": "과거 대화를 참조하는 요청 (아까, 어제, 방금 등)", "email": "이메일 확인, 전송, 검색과 관련된 요청" } # 임베딩 유사도 → 후보 3개 → 확신도 체크 → LLM 폴백 ``` ### 2.3 시간 인식 주입 (250819 문서) **문제**: "오늘 몇일이야?" → "2024년 5월 16일" (실제: 2025년 9월 9일) **해결**: ```python TIME_PATTERNS = ["오늘", "내일", "어제", "몇일", "몇시", "요일"] if any(p in message for p in TIME_PATTERNS): context["current_time"] = datetime.now(KST).strftime("%Y년 %m월 %d일 %H:%M") context["needs_time"] = True ``` ### 2.4 멀티턴 대화 시스템 (250819 문서) **현재**: 단일 턴만 처리 **목표**: 3-5턴 대화 지원 (Phase 2) **슬롯 필링 예시**: ``` User: "이메일 보낼건데..." Robeing: "누구에게 보내실까요?" User: "happybell 지메일로" Robeing: "어떤 내용을 보내실까요?" User: "감사 인사" Robeing: "공손한 톤으로 작성하겠습니다. 발송할까요?" User: "응" Robeing: "전송했습니다." ``` **필요 컴포넌트**: - Redis 세션 관리 - 슬롯 스키마 정의 - 컨텍스트 상태 추적 --- ## 3. 개선 플랜 (단계별 구현) ### Phase 1: 시간 인식 + 임베딩 후보 축소 (2주) **목표**: 시간 질문 오류 해결, 복잡한 질문 기본 대응 **구현 내용**: 1. **시간 컨텍스트 주입** (app/brain/decision_engine.py) - TIME_PATTERNS 정의 - 시간 관련 질문 시 KST 자동 주입 2. **임베딩 기반 후보 축소** (app/brain/intent_classifier.py 신규) - SentenceTransformer 임베딩 - 의도 설명(description) 정의 - 코사인 유사도 → 상위 3개 후보 3. **확신도 기반 LLM 폴백** - confidence < 0.7 → LLM 호출 - 의도 설명 포함 프롬프트 **예상 효과**: - 시간 질문 오류율: 100% → 1% - 복잡한 질문 대응률: 0% → 60% - LLM 호출 비율: 100% → 30% (단순 명령은 정규식) **코드 증가**: +300줄 ### Phase 2: 멀티턴 대화 (1개월) **목표**: 3-5턴 대화 지원, 슬롯 필링 **구현 내용**: 1. **컨텍스트 관리 시스템** (app/context/ 신규) - Redis 세션 저장 - WorkContext 스키마 - 타임아웃 관리 (30분) 2. **슬롯 필링 시스템** - 스킬별 슬롯 정의 (required/optional) - 자동 질문 생성 - 충돌 해결 3. **대화 상태 추적** - Idle → Collecting → Confirming → Executing **예상 효과**: - 작업 완성률: 60% → 90% - 사용자 만족도 증가 **코드 증가**: +800줄 **단점**: - LLM 비용 20배 증가 (7턴 대화 기준) - 응답 시간: 500ms → 2,600ms ### Phase 3: 도메인 특화 (추가 1개월) **목표**: 스타트업 분석 등 도메인 특화 의도 처리 **구현 내용**: 1. **스타트업 분석 의도** (app/brain/decision_engine.py) - STARTUP_ANALYSIS 의도 추가 - LangGraph 워크플로우 연동 2. **Neo4j/TF-IDF 검색 통합** - 유사 기업 검색 스킬 - 베이지안 평가 스킬 3. **도메인 지식 주입** - 스타트업 용어 사전 - 산업 분류 체계 **예상 효과**: - "리버스마운틴 유사 기업 찾아서 가치평가해줘" → 처리 가능 - "협업툴 시장 seed 평균은?" → 처리 가능 **코드 증가**: +1,200줄 --- ## 4. 우선순위 결정 ### 4.1 시급도 평가 | 문제 | 시급도 | 영향도 | Phase | |------|--------|--------|-------| | 시간 질문 오류 | 🔴 HIGH | 일상 대화 | Phase 1 | | 복잡한 질문 미지원 | 🟡 MEDIUM | 고급 기능 | Phase 1 | | 멀티턴 대화 부재 | 🟡 MEDIUM | UX | Phase 2 | | 도메인 특화 미지원 | 🟢 LOW | 특수 기능 | Phase 3 | ### 4.2 권장 순서 **즉시 구현 (1-2주)**: 1. Phase 1 - 시간 인식 + 임베딩 후보 축소 - ROI: 매우 높음 (적은 코드로 큰 효과) - 리스크: 낮음 (기존 코드 영향 최소) **중기 구현 (1-2개월)**: 2. Phase 2 - 멀티턴 대화 - ROI: 중간 (복잡도 증가, 비용 증가) - 리스크: 중간 (컨텍스트 관리 복잡) **장기 구현 (3-4개월)**: 3. Phase 3 - 도메인 특화 - ROI: 높음 (특정 사용 사례에만 적용) - 리스크: 낮음 (독립적 기능) --- ## 5. Phase 1 상세 구현 계획 ### 5.1 파일 구조 ``` rb8001/ ├── app/ │ ├── brain/ │ │ ├── decision_engine.py # 기존 (수정) │ │ ├── intent_classifier.py # 신규 (임베딩 분류) │ │ ├── intent_descriptions.py # 신규 (의도 설명) │ │ └── time_aware_helper.py # 신규 (시간 컨텍스트) │ └── tests/ │ └── test_intent_classifier.py # 신규 ``` ### 5.2 구현 순서 #### Step 1: 시간 인식 (3일) ```python # app/brain/time_aware_helper.py TIME_PATTERNS = { "absolute_time": ["오늘", "내일", "어제", "몇일", "몇시", "요일"], "relative_time": ["아까", "방금", "조금전"], "time_reference": ["그때", "언제", "며칠"] } def inject_time_context(message: str, context: Dict) -> Dict: if any(p in message for patterns in TIME_PATTERNS.values() for p in patterns): context["current_time"] = datetime.now(KST).strftime("%Y년 %m월 %d일 %H:%M") context["needs_time"] = True return context ``` #### Step 2: 임베딩 분류 (5일) ```python # app/brain/intent_classifier.py class ZeroShotIntentClassifier: def __init__(self): self.embedder = SentenceTransformer('paraphrase-multilingual-mpnet-base-v2') self.intent_descriptions = load_intent_descriptions() def classify(self, text: str) -> Tuple[str, float, List]: # 임베딩 text_emb = self.embedder.encode(text) # 후보 축소 scores = {} for intent, desc in self.intent_descriptions.items(): desc_emb = self.embedder.encode(desc) scores[intent] = cosine_similarity(text_emb, desc_emb) # 상위 3개 top_3 = sorted(scores.items(), key=lambda x: x[1], reverse=True)[:3] return top_3[0][0], top_3[0][1], top_3 ``` #### Step 3: DecisionEngine 통합 (3일) ```python # app/brain/decision_engine.py (수정) def analyze_intent(self, message: str, context: Dict) -> Tuple[IntentType, float]: # 1. 시간 컨텍스트 주입 context = inject_time_context(message, context) # 2. 정규식 FastPath (기존) for intent_type, patterns in self.intent_patterns.items(): for pattern in patterns: if re.search(pattern, message): return intent_type, 0.9 # 3. 임베딩 분류 (신규) intent_str, confidence, candidates = self.intent_classifier.classify(message) # 4. 확신도 체크 if confidence < 0.7: # LLM 폴백 intent_str = await self.llm_fallback(message, candidates, context) return IntentType(intent_str), confidence ``` #### Step 4: 의도 설명 정의 (2일) ```python # app/brain/intent_descriptions.py INTENT_DESCRIPTIONS = { "time_query": "현재 시각, 날짜, 요일을 묻는 질문", "email": "이메일 확인, 전송, 검색과 관련된 요청", "news": "뉴스 검색, 확인, 요약 요청", "startup_analysis": "스타트업 기업 분석, 유사 기업 검색, 가치평가 요청", "context_retrieval": "아까, 어제, 방금 등 과거 대화를 참조하는 요청", "general_chat": "일반적인 대화, 인사, 잡담" } ``` ### 5.3 테스트 케이스 ```python # app/tests/test_intent_classifier.py test_cases = [ # 시간 질문 ("오늘 몇일이야?", "time_query", 0.9), ("지금 몇시야?", "time_query", 0.9), # 복잡한 질문 ("리버스마운틴 유사 기업 찾아줘", "startup_analysis", 0.8), ("협업툴 시장 seed 평균은?", "startup_analysis", 0.7), # 맥락 참조 ("아까 말한 그 기업", "context_retrieval", 0.85), # 기존 패턴 (정규식) ("이메일 보내줘", "email", 0.9), ("뉴스 찾아봐", "news", 0.9) ] ``` --- ## 6. 성능 및 비용 분석 ### 6.1 Phase 1 예상 성능 | 지표 | 현재 | Phase 1 | 개선 | |------|------|---------|------| | 단순 명령 응답 시간 | 10ms | 10ms | 0% | | 복잡 질문 응답 시간 | - | 150ms | 신규 | | LLM 호출 비율 | 100% | 30% | -70% | | 시간 질문 정확도 | 0% | 99% | +99% | | 복잡 질문 대응률 | 0% | 60% | +60% | ### 6.2 비용 분석 **현재 (복잡한 질문 시)**: - 모두 LLM으로 폴백 → 100% LLM 호출 **Phase 1 후**: - 정규식 매칭: 60% (비용 0원) - 임베딩 분류: 25% (비용 < 1원/1000건) - LLM 폴백: 15% (기존 대비 -85%) **월간 비용 (10만건 기준)**: - 현재: $300 - Phase 1: $50 (-83%) --- ## 7. 리스크 및 대응 ### 7.1 리스크 요인 | 리스크 | 확률 | 영향 | 대응 | |--------|------|------|------| | 임베딩 모델 용량 큼 | 중 | 중 | 경량 모델 선택 (miniLM) | | 확신도 임계값 조정 어려움 | 중 | 중 | A/B 테스트로 최적값 탐색 | | 기존 코드 영향 | 낮 | 중 | 기존 로직 보존 (정규식 우선) | ### 7.2 롤백 계획 - Phase 1은 기존 코드에 추가만 하므로 롤백 용이 - `USE_INTENT_CLASSIFIER=false` 환경변수로 비활성화 가능 --- ## 8. 다음 단계 ### 8.1 즉시 실행 1. **Phase 1 구현 시작** (추천) - 2주 소요 - ROI 매우 높음 - 리스크 낮음 2. **임베딩 모델 선택** - `paraphrase-multilingual-mpnet-base-v2` (420MB) vs - `paraphrase-multilingual-MiniLM-L12-v2` (120MB) 3. **의도 설명 초안 작성** - 현재 IntentType 15개에 대한 설명 ### 8.2 의사 결정 필요 1. Phase 2 (멀티턴 대화) 진행 여부 - 장점: UX 대폭 개선 - 단점: LLM 비용 20배, 복잡도 증가 2. Phase 3 (도메인 특화) 우선순위 - 스타트업 분석 외 다른 도메인? --- ## 9. 참고 자료 ### 9.1 관련 문서 - 로빙 의도분석 전략: `DOCS/ideas/250920_happybell80_로빙_의도분석_전략.md` - 대화형 시스템: `DOCS/ideas/250819_대화형_점진적_의도_구축_시스템.md` - 제로샷 분류: `DOCS/ideas/250819_시간인식_제로샷_의도분류_시스템.md` ### 9.2 연구 논문 - Hong et al. (2024): Zero-shot Intent Classification (SIGDIAL) - 핵심: 고품질 의도 설명 + 임베딩 후보 축소 ### 9.3 기술 스택 - SentenceTransformer (임베딩) - Redis (세션 관리, Phase 2) - PostgreSQL (대화 로그) --- **작성 완료**: 2025-10-17 **권장 다음 액션**: Phase 1 구현 시작 (2주 스프린트) **검토 필요**: 임베딩 모델 선택, 의도 설명 초안 --- ## 10. 관련 문서 - **[의도 파악 3단계 아키텍처 전환 계획](./251126_intent_3step_architecture_plan.md)** (2025-11-26) - 의도 파악 → 행동 계획 → 스킬 선택의 3단계 구조 설계 - LLM 기반 제로샷 의도 분석으로 무한한 의도 처리 가능 - TDD 시나리오 및 구현 계획 포함