8.3 KiB
8.3 KiB
Human-in-the-loop 의도 학습/리뷰 큐 아키텍처
작성일: 2025-11-16
수정일: 2025-11-17 (LLM-in-the-Loop 자동 평가 방식 추가)
1. 목표
- rb8001에서 모든 의도 분석 결과를 구조화된 로그로 남기고, 나중에 재학습/분석에 활용할 수 있게 한다.
- 모델이 헷갈리는 케이스·에러·사용자 부정 피드백만 골라 리뷰 큐(intent_review_queue) 로 보낸다.
- LLM-in-the-Loop: LLM이 매일 대화 로그를 평가·라벨링하고, 그 결과로 prototype을 재계산해 자동 개선하는 방식 (Human 대신 LLM 사용).
- 프론트/슬랙에서 최소 클릭(좋아요/싫어요)으로 피드백을 수집하고, 이를 의도 로그/리뷰 큐와 자연스럽게 연결한다.
2. 데이터 흐름 개요
2.1 대화 저장 (ConversationLog)
- 책임 파일:
app/state/database.py:44-58: ConversationLogapp/state/conversation_repository.py:16-159: save_conversation
router.route_message()가 실행계획을 만들고 스킬을 실행한다.- LLM 응답(또는 스킬 응답)이 성공하면
_save_conversation()→save_conversation()호출. ConversationLog에 다음 필드 저장:user_id(UUID, FK to user)channel_id(frontend/slack 등)message(사용자 발화)response(로빙 응답)intent(DecisionEngine이 판단한 의도 이름)confidence(의도 신뢰도)timestamp
원칙: 의도/신뢰도는 항상 ConversationLog에 남긴다. 리뷰 큐/재학습은 이 로그를 기반으로 한다.
2.2 Intent 리뷰 큐 (IntentReviewQueue)
- 책임 파일:
app/state/database.py:60-88: IntentReviewQueueapp/brain/intent_review.py:16-82: should_enqueue_for_reviewapp/state/conversation_repository.py:153-188: 리뷰 큐 저장 로직
save_conversation()는 PostgreSQL 저장이 성공하고conversation_id를 얻은 뒤, 의도가 있으면should_enqueue_for_review(...)를 호출한다.should_enqueue_for_review규칙:error=True→ 무조건 리뷰 큐 진입user_feedback가 부정(wrong/이상해/다시 등) → 무조건 리뷰 큐 진입- 그 외에는 top-alternatives와의 마진이 작은 케이스만 리뷰 대상
margin = predicted_conf - best_alt_score < 0.1predicted_conf >= 0.3인 경우에만 고려
- 리뷰 큐에 들어가는 필드:
conversation_log_id(nullable, 히스토리와 연결 가능할 때만)user_idmessagepredicted_intent,predicted_confidencealternatives(JSON, intent/score 목록)user_feedback(up/down/wrong 등)error(bool)status(pending/confirmed/corrected)true_intent(라벨링 완료 후 LLM 또는 사람이 채운 값)
원칙:
- 리뷰 큐는 “라벨링 대상 샘플”만 모아 두는 얇은 테이블이다.
- 실제 원문/컨텍스트는 항상 ConversationLog/ChromaDB에서 조회한다.
3. 프론트/슬랙 피드백 흐름
3.1 프론트엔드 피드백 UI
- 책임 파일:
frontend-customer/src/components/chat-interface.tsx:646-680, 488-507, 510-751frontend-customer/src/services/robeing-api.ts:4-73, 100-154
- 각 로빙 응답 말풍선 아래 타임스탬프 옆에 좋아요/싫어요 버튼 추가:
- 클릭 시
Message.metadata.feedback = 'up' | 'down'로 낙관적 UI 업데이트.
- 클릭 시
- 동시에
sendChatFeedback(message.id, 'up' | 'down')호출:POST { message_id, feedback }→gateway/api/feedback/chat- 게이트웨이는 rb8001의
/api/feedback/chat으로 프록시.
3.2 rb8001 피드백 API → 리뷰 큐
- 책임 파일:
rb8001/main.py:66-72, 189-149, 205-236, 522-531, 627-701, 366-404, 532-624, 636-701, 704-708(중/api/feedback/chat)app/router/feedback_handler.py:16-118
- 엔드포인트:
/api/feedback/chat- Request Body:
{"message_id": "...", "feedback": "up" | "down"} get_current_user로 JWT에서 UUID 추출.
- Request Body:
handle_chat_feedback(user_id, message_id, feedback)호출:message_id에서conversation_log_id를 파싱 ("123_rb8001" → 123)conversation_log_id로ConversationLog를 찾아서message,intent,confidence를 가져옴(있으면).- 해당
(conversation_log_id, user_id)조합에 대해 리뷰 큐 행을 생성/업데이트:feedback='up'→status='confirmed'feedback='down'→status='corrected'
- ConversationLog가 없는 경우(예: 임시 ID)에는
conversation_log_id=None으로 리뷰 큐에 최소 정보만 남긴다.
중요 (2025-11-17 수정):
/api/message응답에message_id필드가 포함되도록 수정됨 ({conversation_log_id}_rb8001형식). 이를 통해 프론트엔드에서 피드백 전송 시 정확한conversation_log_id매칭이 가능해졌다.
원칙: 피드백 API는 실패하더라도 사용자 경험을 깨지 않기 위해 항상 200을 반환하며, 내부 에러는 로그로만 남긴다.
4. 의도/리뷰 TDD 상태
4.1 Intent 리뷰 규칙 테스트
- 책임 파일:
rb8001/tests/test_intent_review_queue.py
검증 내용:
- 캘린더 쿼리 vs 이벤트처럼 마진이 작은 케이스는 리뷰 큐로 가야 한다.
- high-confidence 명확 케이스는 리뷰 큐에 안 들어간다.
- 사용자 부정 피드백(wrong 등)이나 내부 에러가 있으면, confidence와 무관하게 리뷰 큐로 들어가야 한다.
4.2 종합 의도/캘린더 테스트
- 책임 파일:
rb8001/tests/test_intent_entity_skill_comprehensive.py
검증 내용:
- 이메일/뉴스/문서/웹검색/액션/인사/캘린더(등록/조회/승인/삭제)까지 전체 intent 분류.
- 캘린더 조회/등록 문장들은
calendar_eventvscalendar_query로 명시적으로 분리. - 캘린더 후속 질문
"어디서?"에 대해 최근calendar_query응답에서 장소를 추출해 답변.
교훈: 의도/캘린더 관련 코드는 “문장 → 기대 intent”를 먼저 테스트에 못 박고, DecisionEngine/threshold를 그에 맞춰 조정하는 TDD 패턴을 유지한다.
5. 향후 확장 포인트
- LLM 자동 라벨링 (매일 평가)
- LLM이 매일 대화 로그를 평가하여
true_intent를 자동으로 라벨링하고status='confirmed'/'corrected'로 설정. - 사람이 수동으로 검토/수정할 수 있는 관리자용 엔드포인트도 유지.
- LLM이 매일 대화 로그를 평가하여
- 재학습/재시드 배치 연동
IntentReviewQueue에서 검수 완료된 샘플만 모아서 Ko-SRoBERTa prototype/Naive Bayes 시드 스크립트 입력으로 사용.- “신규 검수 샘플 N개 + 일정 주기” 조건에서만 재시드/배포하도록 가드 추가.
- 스킬 실행 로그와의 통합
log_decision/intent_runtime 로그에 실행된 스킬 목록을 포함하고, 리뷰 큐에서 이 정보를 함께 조회할 수 있게 하면 “어떤 스킬 조합이 실패/성공했는지”를 분석하기 쉬워진다.
6. 체크리스트
- ConversationLog에
intent/confidence를 항상 저장하는가 - 리뷰 큐 규칙이 테스트(
test_intent_review_queue.py)로 고정되어 있는가 - 프론트/슬랙에서 피드백을 1~2클릭으로 보낼 수 있는가
- 피드백 API가 실패해도 사용자 경험이 깨지지 않는가
- 라벨링/조회용 API 엔드포인트가 준비되어 있는가 (2025-11-17 완료)
GET /api/intent-review/queue: 리뷰 큐 조회 (필터링/페이지네이션)PUT /api/intent-review/{id}/label: 리뷰 항목 라벨링GET /api/intent-review/stats: 리뷰 큐 통계
- 재시드 배치 스크립트가 준비되어 있는가 (2025-11-17 완료)
scripts/retrain_intent_classifier.py: Naive Bayes + Prototype 재학습scripts/measure_intent_improvement.py: 재학습 전후 측정scripts/llm_auto_label_review_queue.py: LLM 자동 라벨링
- 실제 재학습 및 성능 개선 검증 (2025-11-17 완료)
- 재학습 전: 83.33% → 재학습 후: 97.94% (+14.61%p 개선)
- 92개 라벨링 데이터로 5개 intent prototype 재계산 완료
- 운영에서 리뷰 큐를 모니터링할 대시보드/쿼리가 있는가