- plans/251016_emotion_integration_plan.md: Integration strategy - troubleshooting/251016_emotion_classifier_router_integration.md: Implementation docs - Router integration with skill-embedding EmotionClassifier - USE_EMOTION_ANALYSIS environment variable control - Test scripts and activation guide 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
265 lines
6.1 KiB
Markdown
265 lines
6.1 KiB
Markdown
# 감정 분류기 통합 계획
|
|
|
|
**날짜**: 2025-10-16
|
|
**작성자**: Claude
|
|
**목표**: Phase 3 감정 온톨로지를 실제 대화에 통합
|
|
|
|
---
|
|
|
|
## 현재 상태
|
|
|
|
### 구현 완료
|
|
- ✅ EmotionClassifier (skill-embedding 연동)
|
|
- ✅ emotion_likelihood_ontology.py (11개 규칙)
|
|
- ✅ OntologyReasoner.reason_with_emotion()
|
|
- ✅ ethics_constraints_ontology.py (Router 통합)
|
|
|
|
### 미구현
|
|
- ❌ Router에 감정 분석 통합
|
|
- ❌ 감정 정보를 LLM 컨텍스트에 전달
|
|
- ❌ 실제 대화에서 감정 기반 응답
|
|
|
|
---
|
|
|
|
## 통합 방식 결정
|
|
|
|
### 방식 1: 증거 기반 우도 조정 (복잡)
|
|
|
|
**흐름**:
|
|
```
|
|
사용자 메시지 → 감정 분석 → 증거 추출 → reason_with_emotion() → 조정된 증거 → LLM
|
|
```
|
|
|
|
**문제점**:
|
|
- "증거"를 어떻게 추출할 것인가?
|
|
- 일반 대화에서는 명확한 증거가 없음
|
|
- Coldmail처럼 구조화된 데이터가 아님
|
|
|
|
**적용 가능한 경우**:
|
|
- 의사결정 지원 (투자, 구매 등)
|
|
- 정보 비교 (장단점 분석)
|
|
|
|
### 방식 2: 감정 컨텍스트 전달 (실용적) ✅ 선택
|
|
|
|
**흐름**:
|
|
```
|
|
사용자 메시지 → 감정 분석 → context에 감정 추가 → LLM (감정 고려 응답)
|
|
```
|
|
|
|
**장점**:
|
|
- 구현 간단
|
|
- 모든 대화에 적용 가능
|
|
- LLM이 감정을 자연스럽게 활용
|
|
- 추후 확장 용이
|
|
|
|
**구현 방법**:
|
|
```python
|
|
# 1. 감정 분석
|
|
emotion_result = await emotion_classifier.predict_async(message)
|
|
user_emotion = emotion_result['top_label'] # fear, joy, sadness, etc.
|
|
emotion_confidence = emotion_result['top_p']
|
|
|
|
# 2. context에 추가
|
|
context['user_emotion'] = user_emotion
|
|
context['emotion_confidence'] = emotion_confidence
|
|
|
|
# 3. LLM에 전달 (프롬프트에서 활용)
|
|
llm_response = await llm_service.process_request(llm_request)
|
|
```
|
|
|
|
---
|
|
|
|
## 구현 계획
|
|
|
|
### 1단계: 환경변수 추가
|
|
|
|
**.env**:
|
|
```bash
|
|
# Emotion Analysis (Phase 3 Ontology)
|
|
USE_EMOTION_ANALYSIS=false # 기본값: 비활성화
|
|
```
|
|
|
|
**config.py**:
|
|
```python
|
|
USE_EMOTION_ANALYSIS: bool = os.getenv("USE_EMOTION_ANALYSIS", "false").lower() == "true"
|
|
```
|
|
|
|
### 2단계: Router에 감정 분석 통합
|
|
|
|
**위치**: `router.py` → `_call_internal_llm()` 메서드
|
|
|
|
**추가 코드**:
|
|
```python
|
|
# Phase 3: 감정 분석 (옵션)
|
|
if settings.USE_EMOTION_ANALYSIS:
|
|
try:
|
|
from app.core.emotion.emotion_classifier import get_classifier
|
|
emotion_classifier = get_classifier()
|
|
|
|
emotion_result = await emotion_classifier.predict_async(message)
|
|
user_emotion = emotion_result['top_label']
|
|
emotion_confidence = emotion_result['top_p']
|
|
|
|
# context에 추가
|
|
if context is None:
|
|
context = {}
|
|
context['user_emotion'] = user_emotion
|
|
context['emotion_confidence'] = emotion_confidence
|
|
|
|
logger.info(f"Emotion detected: {user_emotion} (confidence: {emotion_confidence:.2f})")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Emotion analysis failed: {e}")
|
|
```
|
|
|
|
### 3단계: LLM 프롬프트에 감정 정보 활용
|
|
|
|
**위치**: `llm_service.py` 또는 프롬프트 생성 부분
|
|
|
|
**프롬프트 예시**:
|
|
```python
|
|
if context.get('user_emotion'):
|
|
emotion = context['user_emotion']
|
|
emotion_map = {
|
|
'fear': '불안',
|
|
'joy': '기쁨',
|
|
'sadness': '슬픔',
|
|
'anger': '분노',
|
|
'surprise': '놀람',
|
|
'disgust': '혐오',
|
|
'trust': '신뢰',
|
|
'neutral': '평온'
|
|
}
|
|
emotion_kr = emotion_map.get(emotion, emotion)
|
|
|
|
prompt += f"\n\n[참고] 사용자의 현재 감정 상태: {emotion_kr}"
|
|
prompt += f"\n이 감정을 고려하여 공감적이고 적절한 응답을 제공해주세요."
|
|
```
|
|
|
|
### 4단계: 응답에 감정 정보 포함 (디버깅용)
|
|
|
|
**응답 형식**:
|
|
```python
|
|
result = {
|
|
"success": True,
|
|
"content": final_content,
|
|
"model_used": llm_response.model_used,
|
|
"emotion_detected": user_emotion, # 추가
|
|
"emotion_confidence": emotion_confidence # 추가
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 테스트 계획
|
|
|
|
### 테스트 케이스
|
|
|
|
1. **불안 (fear)**:
|
|
- 입력: "요즘 회사가 걱정돼요..."
|
|
- 기대: 위로와 안정감 있는 응답
|
|
|
|
2. **기쁨 (joy)**:
|
|
- 입력: "오늘 승진했어요!"
|
|
- 기대: 축하와 긍정적인 응답
|
|
|
|
3. **슬픔 (sadness)**:
|
|
- 입력: "실패해서 너무 속상해요"
|
|
- 기대: 공감과 위로의 응답
|
|
|
|
4. **중립 (neutral)**:
|
|
- 입력: "날씨가 어때요?"
|
|
- 기대: 일반적인 정보 제공
|
|
|
|
### 검증 방법
|
|
|
|
```bash
|
|
# 로그 확인
|
|
docker logs rb8001 --tail 100 | grep -E "Emotion detected|user_emotion"
|
|
|
|
# 응답 확인
|
|
# Slack에서 대화 → 로그에서 감정 정보 확인
|
|
```
|
|
|
|
---
|
|
|
|
## 향후 확장 (Phase 3.5)
|
|
|
|
### reason_with_emotion() 통합
|
|
|
|
**적용 시나리오**: 의사결정 지원
|
|
|
|
**예시**:
|
|
```python
|
|
# 사용자: "이 투자 어떻게 생각하세요?"
|
|
# 감정: fear (불안)
|
|
|
|
# 1. LLM이 증거 생성
|
|
evidences = [
|
|
{"type": "위험", "content": "시장 변동성", "prior_likelihood": 0.6},
|
|
{"type": "긍정", "content": "성장 가능성", "prior_likelihood": 0.5}
|
|
]
|
|
|
|
# 2. 감정 기반 조정
|
|
adjusted, explanation = reasoner.reason_with_emotion("fear", evidences)
|
|
# 위험 0.6 → 0.78 (+30%)
|
|
|
|
# 3. 조정된 증거로 최종 응답
|
|
```
|
|
|
|
---
|
|
|
|
## 성능 영향
|
|
|
|
### 추가 처리 시간
|
|
- 감정 분석 API 호출: ~50-100ms
|
|
- skill-embedding 서비스 응답 시간
|
|
|
|
### 완화 방법
|
|
- 비동기 호출 (await)
|
|
- 타임아웃 설정 (10초)
|
|
- 실패 시 graceful degradation
|
|
|
|
---
|
|
|
|
## 롤백 방법
|
|
|
|
### 환경변수 비활성화
|
|
```bash
|
|
USE_EMOTION_ANALYSIS=false
|
|
docker compose down && docker compose up -d
|
|
```
|
|
|
|
---
|
|
|
|
## 일정
|
|
|
|
### 즉시 (오늘)
|
|
- [x] 통합 계획 수립
|
|
- [ ] 환경변수 추가
|
|
- [ ] Router 코드 수정
|
|
- [ ] 테스트 및 검증
|
|
|
|
### 내일 (2025-10-17)
|
|
- [ ] 실전 데이터 수집
|
|
- [ ] 감정 분석 정확도 확인
|
|
|
|
### 향후 (Phase 3.5)
|
|
- [ ] reason_with_emotion() 통합 (의사결정 지원)
|
|
- [ ] 감정 기반 추천 시스템
|
|
- [ ] 베이지안 학습 (피드백 기반)
|
|
|
|
---
|
|
|
|
## 결론
|
|
|
|
**선택한 방식**: 감정 컨텍스트 전달 (방식 2)
|
|
|
|
**이유**:
|
|
- 간단하고 실용적
|
|
- 모든 대화에 적용 가능
|
|
- LLM의 자연어 이해 능력 활용
|
|
- 점진적 확장 가능
|
|
|
|
**다음 단계**: Router에 감정 분석 코드 추가
|