- AI Hub 도덕성 판단 모델(2022) 통합 계획 - 단기: 기초 구축 (도덕성 분류기 + Love Index) - 중기: 감정-윤리 통합 및 베이지안 학습 - 장기: 개인화 및 다중 에이전트 윤리 조정 - 감정 엔트로피 기반 윤리 판단 조정 메커니즘 포함
465 lines
13 KiB
Markdown
Executable File
465 lines
13 KiB
Markdown
Executable File
# 로빙 감정 시스템 현실 적용 5단계 로드맵
|
|
|
|
**작성자**: happybell80 & Claude
|
|
**목적**: 감정 시스템 설계서를 현실적으로 구현 가능한 단계별 계획으로 구체화
|
|
|
|
## 핵심 원칙
|
|
- **MVP 우선**: 복잡한 기능보다 작동하는 기본 기능
|
|
- **측정 가능한 성과**: 각 단계마다 명확한 KPI
|
|
- **점진적 복잡도**: 단순 → 복잡으로 진화
|
|
- **서비스 분리**: 단일 장애점 방지
|
|
- **함수형 프로그래밍 100%**: 하드코딩 0% 목표. 근거없는 하드코딩 값 절대 사용 금지
|
|
- 모든 값은 설정 파일이나 환경변수에서 로드
|
|
- 순수 함수 체인으로 구성
|
|
- 상태 변경 최소화, 불변성 유지
|
|
|
|
---
|
|
|
|
## Phase 1: 7개 감정 기본 구현 (모델 준비 완료, 통합 대기)
|
|
|
|
### 목표
|
|
"이미 학습된 7개 한국어 감정 모델을 skill-embedding에 통합"
|
|
|
|
### 진행 현황 (2025-08-15 기준)
|
|
- ✅ 모델 학습 완료 (F1 56.3%)
|
|
- ✅ ONNX 변환 완료 (442MB)
|
|
- ⏳ skill-embedding 서비스 통합 대기
|
|
- ⏳ /emotion 엔드포인트 구현 필요
|
|
|
|
### 구현 범위
|
|
```python
|
|
# AI Hub 데이터로 학습 완료된 7개 감정
|
|
EMOTIONS = [
|
|
"fear", # 공포 (기본정서)
|
|
"surprise", # 놀람 (기본정서)
|
|
"anger", # 분노 (기본정서)
|
|
"sadness", # 슬픔
|
|
"neutral", # 중립
|
|
"happiness", # 행복
|
|
"disgust" # 혐오
|
|
]
|
|
# 모델 성능: F1 56.3%, Temperature Scaling 1.232
|
|
|
|
# 엔트로피 계산 (7개 감정)
|
|
def calculate_entropy(probs: List[float]) -> float:
|
|
"""7개 감정 확률값으로 엔트로피 계산"""
|
|
return -sum(p * log(p) for p in probs if p > 0)
|
|
```
|
|
|
|
### 기술 스택
|
|
- **감정 모델**: klue/bert-base 기반 → ONNX 변환 완료
|
|
- **서비스**: skill-embedding 확장 (포트 8515, /emotion 추가)
|
|
- **저장**: 기존 ChromaDB 활용 (메타데이터에 감정 추가)
|
|
- **의사결정**: 엔트로피 기반 복잡도 판단
|
|
- **기존 코드**: rb10508_micro의 memory/storage.py 재사용
|
|
- **설정값**: confidence=0.35, entropy=2.0, temperature=1.232
|
|
|
|
### 성능 목표
|
|
- 응답시간: 500ms 이내
|
|
- 정확도: 사용자 평가 3.5/5.0
|
|
- 메모리: 200MB 이내
|
|
|
|
### 데이터 준비 (완료)
|
|
- AI Hub 한국어 대화 데이터셋 38,594개 샘플
|
|
- 7개 감정 균형 분포
|
|
- 학습/검증/테스트 분할 완료
|
|
- 클래스 가중치 적용
|
|
|
|
### 검증 방법
|
|
```bash
|
|
# 단위 테스트
|
|
pytest tests/test_basic_emotions.py
|
|
|
|
# 부하 테스트
|
|
locust -f tests/load_test.py --users 10
|
|
|
|
# 응답시간 측정
|
|
curl -w "@curl-format.txt" http://localhost:8503/analyze
|
|
```
|
|
|
|
### 산출물
|
|
- [x] 7개 감정 모델 학습 완료 (training_emotion) ✅ 2025-08-08
|
|
- [x] ONNX 변환 완료 (442MB) ✅ 2025-08-13
|
|
- [x] 모델 파일 51124 서버 배치 완료 ✅ 2025-08-13
|
|
- [ ] skill-embedding 서비스에 /emotion 엔드포인트 추가 ⏳
|
|
- [ ] Temperature Scaling 적용 (1.232) ⏳
|
|
- [ ] 엔트로피 계산기 구현 ⏳
|
|
- [ ] ChromaDB 메타데이터 통합 ⏳
|
|
- [ ] rb10508_micro 연동 ⏳
|
|
|
|
### 아키텍처 결정 사항 (2025-08-12)
|
|
**문제**: 감정 분석을 어디에 구현할 것인가?
|
|
- Option A: 별도 skill-emotion 서비스 (아키텍처 원칙)
|
|
- Option B: skill-embedding에 통합 (자원 효율성)
|
|
|
|
**최종 결정**: skill-embedding에 통합
|
|
- 이유: ONNX Runtime 공유, 메모리 200MB 절약, 레이턴시 감소
|
|
- 트레이드오프: 서비스 역할 혼재 vs 실용성
|
|
- 향후: 서비스명 변경 고려 (skill-embedding → skill-ai)
|
|
|
|
### 현재 보유 모델 (2025-08-15)
|
|
1. **aihub-7emotions** (메인 모델)
|
|
- 크기: 442MB (ONNX)
|
|
- 감정: fear, surprise, anger, sadness, neutral, happiness, disgust
|
|
- 성능: F1 56.3%, ECE 0.090
|
|
- 위치: /home/admin/ivada_project/onnx_models/aihub-7emotions/
|
|
|
|
2. **korean-sentiment-kcelectra** (보조 모델)
|
|
- 크기: 511MB (ONNX)
|
|
- 감정: 11개 한국어 세분화 감정
|
|
- 성능: F1 70.72%
|
|
- 위치: /home/admin/ivada_project/onnx_models/korean-sentiment-kcelectra/
|
|
|
|
---
|
|
|
|
## Phase 2: 서비스 통합 및 최적화
|
|
|
|
### 목표
|
|
"skill-embedding 서비스 통합, 캐싱 구현, rb10508_micro 연동"
|
|
|
|
### 우선 작업 (로컬 개발자)
|
|
1. skill-embedding에 /emotion 엔드포인트 추가
|
|
2. ONNX 모델 로딩 및 추론 코드 구현
|
|
3. Temperature Scaling (T=1.232) 적용
|
|
4. rb10508_micro에서 감정 API 호출 통합
|
|
|
|
### 최적화 전략
|
|
```python
|
|
# LRU 캐시 적용
|
|
from functools import lru_cache
|
|
|
|
@lru_cache(maxsize=1000)
|
|
def get_emotion_embedding(text: str) -> np.ndarray:
|
|
"""자주 사용되는 텍스트의 임베딩 캐싱"""
|
|
return model.encode(text)
|
|
|
|
# 배치 처리
|
|
async def batch_analyze(texts: List[str]):
|
|
"""여러 텍스트 동시 처리"""
|
|
embeddings = model.encode(texts, batch_size=32)
|
|
return [analyze_emotion(emb) for emb in embeddings]
|
|
```
|
|
|
|
### ChromaDB 튜닝
|
|
- 인덱스 최적화: HNSW 파라미터 조정
|
|
- 쿼리 최적화: top-k를 10으로 제한
|
|
- 연결 풀링: 커넥션 재사용
|
|
|
|
### 프로파일링
|
|
```python
|
|
# 병목 지점 찾기
|
|
import cProfile
|
|
import pstats
|
|
|
|
cProfile.run('analyze_emotion(text)', 'profile_stats')
|
|
stats = pstats.Stats('profile_stats')
|
|
stats.sort_stats('cumulative').print_stats(10)
|
|
```
|
|
|
|
### 성능 목표
|
|
- 응답시간: 200ms (60% 개선)
|
|
- 동시 처리: 50 req/s
|
|
- 캐시 적중률: 30%
|
|
|
|
### 산출물
|
|
- [x] ONNX 모델 변환 완료 (442MB) ✅
|
|
- [ ] skill-embedding /emotion 엔드포인트 구현 ⏳
|
|
- [ ] LRU 캐시 시스템 (5분 TTL)
|
|
- [ ] 배치 처리 API
|
|
- [ ] ChromaDB 감정 메타데이터 인덱싱
|
|
- [ ] 성능 모니터링 (Grafana)
|
|
- [ ] rb10508_micro 감정 기반 응답 톤 조정
|
|
|
|
---
|
|
|
|
## Phase 3: 감정 패턴 분석 및 개인화
|
|
|
|
### 목표
|
|
"장기 감정 패턴 추적, 사용자별 감정 프로파일 구축"
|
|
|
|
### 감정 패턴 분석
|
|
```python
|
|
# 시간별 감정 추적
|
|
class EmotionTracker:
|
|
def __init__(self, user_id: str):
|
|
self.user_id = user_id
|
|
self.history = [] # 시계열 감정 데이터
|
|
|
|
def track(self, emotion_result: dict):
|
|
"""감정 결과를 시계열로 저장"""
|
|
self.history.append({
|
|
"timestamp": datetime.now(),
|
|
"emotions": emotion_result["emotions"],
|
|
"dominant": emotion_result["dominant"],
|
|
"entropy": emotion_result["entropy"]
|
|
})
|
|
|
|
def get_pattern(self, period: str = "day"):
|
|
"""일/주/월 단위 감정 패턴 분석"""
|
|
# 시간대별 주요 감정
|
|
# 감정 변화 추이
|
|
# 엔트로피 패턴
|
|
return analyze_temporal_pattern(self.history, period)
|
|
```
|
|
|
|
### 개인화 전략
|
|
- 사용자별 감정 프로파일 생성
|
|
- 감정 응답 히스토리 학습
|
|
- 개인별 감정 임계값 조정
|
|
- 엔트로피 특이점 활용 (창발적 응답)
|
|
|
|
### 엔트로피 기반 의사결정
|
|
```python
|
|
class EntropyBasedDecision:
|
|
def __init__(self):
|
|
self.entropy_threshold = 2.5 # 특이점 임계값
|
|
|
|
def should_be_creative(self, entropy: float) -> bool:
|
|
"""높은 엔트로피일 때 창의적 응답"""
|
|
return entropy > self.entropy_threshold
|
|
|
|
def adjust_response(self, response: str, emotion_result: dict):
|
|
"""감정에 따른 응답 톤 조정"""
|
|
if emotion_result["dominant"] == "sadness":
|
|
return make_empathetic(response)
|
|
elif emotion_result["dominant"] == "anger":
|
|
return make_calm(response)
|
|
elif self.should_be_creative(emotion_result["entropy"]):
|
|
return make_creative(response)
|
|
return response
|
|
```
|
|
|
|
### 성능 목표
|
|
- 패턴 분석: 일 1회 배치 처리
|
|
- 프로파일 업데이트: 실시간
|
|
- 감정 히스토리: 30일 보관
|
|
- 개인화 정확도: 70% 이상
|
|
|
|
### 산출물
|
|
- [ ] 감정 패턴 분석기
|
|
- [ ] 사용자 감정 프로파일 DB
|
|
- [ ] 엔트로피 기반 의사결정 모듈
|
|
- [ ] 시계열 감정 시각화
|
|
- [ ] 개인화 응답 전략
|
|
|
|
---
|
|
|
|
## Phase 4: 베이지안 학습 시스템
|
|
|
|
### 목표
|
|
"실시간 학습과 개인화된 감정 모델 구축"
|
|
|
|
### 베이지안 파라미터
|
|
```python
|
|
class BayesianEmotionModel:
|
|
def __init__(self):
|
|
# Dirichlet 사전분포 (9개 감정)
|
|
self.emotion_prior = np.ones(9)
|
|
|
|
# Beta 분포 (저장 결정)
|
|
self.save_alpha = 1
|
|
self.save_beta = 1
|
|
|
|
# Gamma 분포 (응답 길이)
|
|
self.length_k = 2
|
|
self.length_theta = 50
|
|
|
|
def update_posterior(self, observation):
|
|
"""관측값으로 사후분포 업데이트"""
|
|
self.emotion_prior += observation['emotion_counts']
|
|
|
|
if observation['saved']:
|
|
self.save_alpha += 1
|
|
else:
|
|
self.save_beta += 1
|
|
|
|
# Gamma 업데이트 (moment matching)
|
|
self.length_k, self.length_theta = \
|
|
self.update_gamma(observation['response_length'])
|
|
```
|
|
|
|
### 예측-평가 루프
|
|
```python
|
|
async def prediction_evaluation_loop(user_input):
|
|
# 1. 예측
|
|
prediction = model.predict_user_response(user_input)
|
|
|
|
# 2. 실제 응답 생성
|
|
actual_response = await generate_response(user_input)
|
|
|
|
# 3. 사용자 반응 수집
|
|
user_reaction = await collect_feedback()
|
|
|
|
# 4. 오차 계산 (3종)
|
|
kl_div = calculate_kl(prediction, user_reaction)
|
|
brier = calculate_brier(prediction, user_reaction)
|
|
ece = calculate_ece(prediction, user_reaction)
|
|
|
|
# 5. 모델 업데이트
|
|
if max(kl_div, brier, ece) > threshold:
|
|
model.update_posterior(user_reaction)
|
|
|
|
return actual_response
|
|
```
|
|
|
|
### 개인화
|
|
- 사용자별 베이지안 파라미터 저장
|
|
- 조직/팀/개인 3단계 계층 구조
|
|
- Cold start: 조직 평균값 사용
|
|
|
|
### 성능 목표
|
|
- ECE: ≤ 0.08
|
|
- Brier Score: ≤ 0.20
|
|
- 학습 수렴: 50회 상호작용
|
|
- 개인화 효과: +15% 만족도
|
|
|
|
### 산출물
|
|
- [ ] 베이지안 모델 클래스
|
|
- [ ] 예측-평가 파이프라인
|
|
- [ ] 3종 오차 메트릭
|
|
- [ ] 사용자별 파라미터 저장소
|
|
- [ ] 학습 곡선 분석
|
|
|
|
---
|
|
|
|
## Phase 5: 프로덕션 및 확장
|
|
|
|
### 목표
|
|
"안정적인 프로덕션 배포와 고급 기능 추가"
|
|
|
|
### 프라이버시 게이트
|
|
```python
|
|
class PrivacyGate:
|
|
def __init__(self):
|
|
self.pii_patterns = load_pii_patterns()
|
|
self.sensitive_topics = load_sensitive_topics()
|
|
|
|
def filter(self, text, metadata):
|
|
# PII 감지
|
|
if self.detect_pii(text):
|
|
return self.anonymize(text)
|
|
|
|
# 민감 주제 필터
|
|
if self.is_sensitive(text):
|
|
return {"summary": self.summarize(text),
|
|
"original": None}
|
|
|
|
# 24시간 옵트아웃
|
|
if metadata.get('opt_out_requested'):
|
|
return None
|
|
|
|
return text
|
|
```
|
|
|
|
### 모니터링 시스템
|
|
```yaml
|
|
# prometheus metrics
|
|
metrics:
|
|
- emotion_analysis_duration_seconds
|
|
- emotion_cache_hit_ratio
|
|
- bayesian_update_count
|
|
- prediction_error_rate
|
|
- privacy_filter_triggers
|
|
|
|
alerts:
|
|
- name: HighECE
|
|
expr: emotion_ece > 0.1
|
|
for: 5m
|
|
|
|
- name: SlowResponse
|
|
expr: emotion_p95_latency > 500
|
|
for: 10m
|
|
```
|
|
|
|
### 고급 기능
|
|
- HDBSCAN 클러스터링 도입
|
|
- 감정 전환 패턴 학습
|
|
- 멀티모달 확장 준비 (음성/표정)
|
|
- 설명가능 AI (LIME/SHAP)
|
|
|
|
### 확장성
|
|
```python
|
|
# 수평 확장 준비
|
|
class EmotionAnalyzerCluster:
|
|
def __init__(self, workers=4):
|
|
self.workers = workers
|
|
self.load_balancer = ConsistentHash()
|
|
|
|
async def analyze(self, text, user_id):
|
|
# 사용자별로 일관된 워커 할당
|
|
worker = self.load_balancer.get_worker(user_id)
|
|
return await worker.analyze(text)
|
|
```
|
|
|
|
### 최종 KPI
|
|
- ECE: ≤ 0.05
|
|
- Brier Score: ≤ 0.18
|
|
- NDCG@10: ≥ 0.6
|
|
- 응답시간 P95: ≤ 300ms
|
|
- 가용성: 99.9%
|
|
|
|
### 산출물
|
|
- [ ] 프라이버시 게이트 시스템
|
|
- [ ] Prometheus/Grafana 대시보드
|
|
- [ ] 수평 확장 아키텍처
|
|
- [ ] HDBSCAN 클러스터링
|
|
- [ ] 프로덕션 배포 (Docker/K8s)
|
|
- [ ] 운영 문서 및 Runbook
|
|
|
|
---
|
|
|
|
## 리스크 및 완화 방안
|
|
|
|
### 기술적 리스크
|
|
1. **ChromaDB 성능 한계**
|
|
- 완화: Redis 캐시 레이어 추가
|
|
- 대안: Pinecone/Weaviate 검토
|
|
|
|
2. **모델 추론 속도**
|
|
- 완화: ONNX 변환, 양자화
|
|
- 대안: DistilBERT 기반 경량 모델
|
|
|
|
3. **베이지안 계산 복잡도**
|
|
- 완화: 근사 알고리즘 사용
|
|
- 대안: 단순 EMA로 대체
|
|
|
|
### 데이터 리스크
|
|
1. **라벨 품질**
|
|
- 완화: 다중 라벨러, 합의 메커니즘
|
|
- 대안: 약지도 학습
|
|
|
|
2. **개인정보 유출**
|
|
- 완화: 로컬 처리, 암호화
|
|
- 대안: 연합 학습
|
|
|
|
### 운영 리스크
|
|
1. **서비스 장애**
|
|
- 완화: Circuit breaker, 폴백
|
|
- 대안: 기본 감정만 제공
|
|
|
|
2. **비용 증가**
|
|
- 완화: 사용량 기반 스케일링
|
|
- 대안: 엣지 디바이스 처리
|
|
|
|
---
|
|
|
|
## 성공 기준
|
|
|
|
### Phase별 체크포인트
|
|
- **Phase 1**: 5개 감정 인식 작동 확인
|
|
- **Phase 2**: 200ms 응답시간 달성
|
|
- **Phase 3**: 9개 감정 정확도 80%
|
|
- **Phase 4**: 개인화 효과 측정 가능
|
|
- **Phase 5**: 프로덕션 안정성 99.9%
|
|
|
|
### 전체 프로젝트 성공 지표
|
|
1. **사용자 만족도**: NPS 40 이상
|
|
2. **기술 성능**: 모든 KPI 목표치 달성
|
|
3. **비즈니스 가치**: 사용자 이탈률 20% 감소
|
|
4. **확장 가능성**: 일 100만 요청 처리
|
|
|
|
---
|
|
|
|
---
|
|
|
|
*이 로드맵은 이상적인 설계를 현실적으로 구현 가능한 단계로 나눈 실행 계획입니다. 각 Phase는 독립적으로 가치를 제공하며, 상황에 따라 중단하거나 방향을 전환할 수 있습니다.* |