DOCS/journey/plans/251204_emotion_based_addressing_system.md
Claude-51124 6b6457b4de Consolidate addressing docs into single file
- Remove: 251204_addressing_ux_scenarios.md
- Remove: 251204_addressing_test_report.md
- Remove: 251204_addressing_v2_scenarios.md
- Update: 251204_emotion_based_addressing_system.md (v1+v2 통합)
- 312 원칙: 하나의 문제 = 하나의 파일
2025-12-04 17:05:09 +09:00

5.6 KiB

감정 기반 호칭 시스템 구현

작성일: 2025-12-04
수정일: 2025-12-04 (v2 구현 완료)
작성자: happybell80
상태: v2 구현 완료 (75% 정확도)


배경 및 목표

  • 현재: 모든 사용자를 "사용자님" 또는 user.name으로 획일적 호칭
  • 문제: 감정 상태/상황 무시, metadata (nickname, position) 미활용
  • 목표: 감정 기반 호칭 동적 변경으로 공감 능력 강화, 한국 직장 문화 존중 표현

조사 결과 (웹 검색)

한국어 호칭 원칙:

  • 친밀한 관계: 별명/애칭 사용
  • 공식적/부정적 상황: 정식 이름 사용
  • 출처: 한국어 호칭 연구, UX 라이팅 전략

AI 감정 반응:

  • 챗GPT emotional rebound 효과: 부정 → 위로, 긍정 → 친근
  • 출처: 프랑크 바르돌 연구 (m.etnews.com)

직장 문화: 직책 호칭 최우선 (대표님, 이사님)

설계 결정

방식: 휴리스틱 규칙 (Python)

이유: 일관성, 속도, 예측 가능성, 제어 용이
LLM 역할: 결정된 호칭 자연스럽게 사용만

호칭 결정 규칙 (v1 - 구현 완료)

조건 호칭
metadata->>'position' 있음 "대표님", "이사님"
긍정 감정 + position 없음 metadata->>'nickname' → "joann님"
부정 감정 + position 없음 user.name → "이고은님"
nickname 없음 user.name 성 제외 → "고은님"

긍정 감정: happiness, surprise, neutral
부정 감정: fear, anger, sadness, disgust
감정 소스: emotion_readings 최근 10분 평균 (현재 메시지 가중치 2배)

v1 문제점: 직책 있으면 감정 무관 → 상황별 미묘한 차이 표현 불가

구현 (계층 분리 원칙 준수)

계층 구조

router.py (감정 분석 후)
    ↓
services/addressing_service.py (신규, 호칭 결정 비즈니스 로직)
    ↓
state/database.py (DB CRUD만)

1. services/addressing_service.py (신규)

기능: 호칭 결정 비즈니스 로직

  • get_preferred_name(user_id: str, current_emotion: str) -> str
  • state 호출: user 정보, 최근 감정 조회
  • 호칭 규칙 적용 (직책 → 긍정감정=nickname → 부정감정=정식이름)
  • 약 100줄 예상

2. state/database.py

기존 함수 확인 후:

  • 없으면 추가: get_user_basic_info(user_id) - name, metadata 반환
  • 없으면 추가: get_recent_emotions(user_id, minutes=10) - 감정 평균
  • DB CRUD만, 비즈니스 로직 금지

3. router.py:264-283

수정: 감정 분석 후 addressing_service 호출

from app.services.addressing_service import get_preferred_name
preferred_name = await get_preferred_name(user_id, user_emotion)
context['preferred_name'] = preferred_name

4. llm_service.py:131-132

수정: system_instruction에 호칭 지시

preferred_name = enhanced_context.get('preferred_name', '사용자')
system_instruction += f"사용자를 '{preferred_name}'으로 호칭하세요. "

5. tables.md

추가: user.metadata 컬럼 문서화

| metadata | JSONB | YES | nickname, position, short_name, preferences |

테스트 시나리오

  1. 긍정+직책: "고마워요" (happiness) + position="대표" → "대표님"
  2. 긍정+no직책: "좋은 아침" (happiness) + nickname="joann" → "joann님"
  3. 부정+no직책: "힘들어요" (sadness) + name="이고은" → "이고은님"
  4. 중립: "날씨는?" (neutral) + name="김종태" → "종태님"

검증

로그:

docker logs rb8001 --tail 100 | grep "Preferred name"

DB:

-- 최근 10분 감정 평균
SELECT user_id, AVG((probs->>'happiness')::float) FROM emotion_readings
WHERE created_at > NOW() - INTERVAL '10 minutes' GROUP BY user_id;

API:

curl -X POST http://192.168.219.52:8001/api/message \
  -H "Authorization: Bearer $JWT" -d '{"text": "고마워요!"}'

v2 구현 완료 (복합 감정 기반)

변경 내용

  • addressing_service.py:200줄 - 5단계 호칭 로직, top_emotions + entropy 활용
  • database.py:+108줄 - get_recent_emotion_details() 추가
  • router.py:+2줄 - 현재 감정 결과 전달
  • llm_service.py:+1줄 - 호칭 남발 방지 (첫 문장 1회만)

최종 호칭 규칙

조건 호칭 예시
fear+sadness >= 0.6 김종태 이사님 "너무 힘들고 불안해요..."
anger/disgust 높음 이사님 "정말 화나네요!"
neutral 또는 entropy 높음 이사님 "좋긴 한데 걱정도..."
happiness >= 0.99, surprise < 0.02 종태님 "정말 감사합니다!"
기타 긍정 종태 이사님 (감정 분석 한계로 미작동)

테스트 결과: 6/8 성공 (75%)

성공: 매우 부정(김종태 이사님), 부정(이사님), 중립(이사님/종태 이사님), 매우 긍정(종태님)
실패: 중간 긍정(종태 이사님) - 감정 분석기가 "좋아요"도 0.99로 분석

Git 커밋

v1: a26e7b6, c8052f7
v2: 84b26b6, 52d906b, 71806b0, 41dcc0a

교훈

  1. 감정 분석 정확도가 호칭 품질 결정: 임계값 튜닝 한계, 모델 개선 필요
  2. TDD 효과: 10개 시나리오로 한계 조기 발견
  3. 실용적 타협: 75% 정확도로 3단계 호칭 실사용 가능
  4. 계층 분리 원칙: router → services → state 흐름 준수

관련 문서