diff --git a/journey/plans/251117_short_followup_context_3phase_plan.md b/journey/plans/251117_short_followup_context_3phase_plan.md new file mode 100644 index 0000000..610c371 --- /dev/null +++ b/journey/plans/251117_short_followup_context_3phase_plan.md @@ -0,0 +1,124 @@ +# 짧은 후속 질문 컨텍스트 유실 개선 3단계 계획 + +**날짜**: 2025-11-17 +**작성자**: Claude Code +**관련 파일**: +- rb8001/app/brain/decision_engine.py +- rb8001/tests/test_intent_entity_skill_comprehensive.py +- DOCS/journey/plans/251017_intent_analysis_improvement_plan.md +- DOCS/journey/troubleshooting/251117_human_in_the_loop_intent_learning.md + +--- + +## 1. 문제 요약 + +- 사용자: "11월 18일 오전 6시 40분에 검진이 있습니다" → RoBeing 응답 OK +- 이어서 사용자: "어디서?" +- 실제 동작: 짧은 질문이 UNKNOWN → understand 액션으로 전달 → LLM이 "오늘 일정 정리해 드릴까요?"처럼 **새 대화로 오인** +- 근본 원인: 짧은 후속 질문에 대한 별도 Intent/처리 경로가 없어서, **직전 발화/대화 맥락을 강제 참조하지 못하는 구조** + +--- + +## 2. 목표 + +1. "어디서?", "언제?", "누구랑?" 같은 **짧은 후속 질문**이 항상 직전 발화/대화 맥락과 연결되도록 한다. +2. 비용 제약 없이, **정규식 FastPath → 임베딩 기반 의도 분류 → 멀티턴/슬롯필링**까지 단계적으로 설계한다. +3. 기존 DecisionEngine/테스트 구조를 유지하면서, 점진적으로 확장 가능한 형태로 설계한다. + +--- + +## 3. 1단계: 짧은 후속 질문 전용 Intent 추가 (FastPath) + +### 3.1 설계 + +- 새 IntentType 추가: `CONTEXT_FOLLOWUP` (이름은 구현 시 팀 합의) +- intent_patterns에 짧은 후속 질문 패턴 추가 (예시): + - `r"^어디서[요]?$"` + - `r"^언제[요]?$"` + - `r"^누구(랑|하고)?[요]?$"` + - `r"^뭐[야|였어]?$"` +- 규칙: + - 이 패턴이 매칭되면 **무조건 CONTEXT_FOLLOWUP** 으로 분류 (UNKNOWN으로 보내지 않음). + - 현재 발화만으로 판단하지 않고, **직전 1~3턴의 메시지**를 강제 참조하도록 DecisionEngine에 후속 처리 경로 추가. + +### 3.2 처리 흐름 + +1. DecisionEngine에서 CONTEXT_FOLLOWUP 감지. +2. 대화 로그/메모리에서 **가장 최근의 "장소/시간/대상"이 포함된 발화**를 검색. +3. LLM 프롬프트에 아래 정보를 함께 전달: + - 현재 질문: "어디서?" + - 직전 발화: "11월 18일 오전 6시 40분에 검진이 있습니다" + - 관련 메모리(예: 병원명, 의료기관 기록 등) +4. LLM에게 **"후속 질문으로, 위 직전 발화를 기준으로 답하라"** 는 제약을 명시. + +### 3.3 테스트 전략 + +- `rb8001/tests/test_intent_entity_skill_comprehensive.py` 또는 별도 테스트 파일에 케이스 추가: + - 대화 시나리오: ["내일 아침에 건강검진 있어", "어디서?"] → 장소가 포함된 응답 기대. + - ["내일 오전 10시에 미팅 있어", "언제?"] → 시간 재응답. +- 기대 행동: + - Intent: `CONTEXT_FOLLOWUP` + - UNKNOWN 비율 감소, understand 액션 호출 없이도 적절한 핸들링 가능. + +--- + +## 4. 2단계: 임베딩 기반 의도/맥락 분류 + LLM 폴백 + +### 4.1 설계 + +- 251017 문서에서 제안한 **정규식 FastPath + 임베딩 + LLM 3단계 구조**를, CONTEXT_FOLLOWUP에도 확장. +- 핵심 아이디어: + - "어디서?" 자체만 보면 모호하지만, + - 직전/과거 발화와의 **임베딩 유사도**로 "장소 관련 후속 질문"임을 더 강하게 판단. + +### 4.2 처리 흐름 (의사 단계) + +1. 정규식 FastPath에서 패턴 매칭 실패 또는 확신도 낮음. +2. 임베딩 엔진으로 현재 발화 + 최근 N턴 발화를 임베딩. +3. 후보 의도들(예: `calendar_query`, `context_followup`, `general_chat` 등)의 description 임베딩과 유사도 비교. +4. 상위 3개 의도 + 유사도 스코어를 계산: + - 확신도 ≥ 0.8 → 해당 의도로 결정. + - 0.5 ≤ 확신도 < 0.8 → LLM에게 top-3 후보와 함께 전달, 최종 선택 요청. + - 확신도 < 0.5 → LLM general understand로 폴백. + +### 4.3 기대 효과 + +- 짧은 질문이라도, **직전 발화와의 관계**를 임베딩 수준에서 반영. +- DecisionEngine의 UNKNOWN 경로 유입을 줄이고, LLM 호출도 불필요하게 늘리지 않도록 제어. +- 향후 Human/LLM-in-the-loop 라벨링과 결합 시, 의도 prototype 업데이트로 정밀도 향상. + +--- + +## 5. 3단계: 멀티턴/슬롯필링 기반 대화 관리 + +### 5.1 설계 + +- Redis 등 외부 스토리지를 사용해 **세션 단위로 3~5턴 대화 상태를 유지**. +- 각 세션에 대해 **슬롯 구조**를 정의: + - 예: `calendar_event` → {날짜, 시간, 장소, 대상, 목적} +- 사용자의 후속 질문은, 이 슬롯 구조를 기반으로 해석: + - "어디서?" → `장소` 슬롯 재질문/확인 + - "언제?" → `시간` 슬롯 재질문/확인 + +### 5.2 처리 흐름 + +1. 사용자가 "검진 일정 잡아줘" → Phase 1/2의 의도 분석을 거쳐 `calendar_event`로 분류. +2. 시스템이 슬롯 채우기 진행 (날짜, 시간, 장소 등). +3. 후속 질문 발생 시, 현재 세션의 슬롯 상태를 조회: + - 이미 채워진 값이 있으면, 그 값을 기준으로 답변. + - 값이 없으면, LLM이 추가 질문 또는 기본값 제안. + +### 5.3 비용 및 운영 관점 + +- LLM 호출 횟수는 증가하지만, **세션/슬롯 상태 관리를 통해 재질문/중복 호출을 줄일 수 있음**. +- Redis 세션 TTL, 슬롯 수 제한 등을 통해 메모리/비용 관리 가능. +- 사람 개입(Human-in-the-loop) 또는 LLM-in-the-loop 리뷰 큐와 결합해, 자주 틀리는 패턴을 우선적으로 보완. + +--- + +## 6. 정리 + +1. 1단계: CONTEXT_FOLLOWUP Intent + 패턴 추가로, 짧은 후속 질문을 UNKNOWN에서 분리. +2. 2단계: 임베딩 기반 의도/맥락 분류와 LLM 폴백으로, "어디서?" 같은 질문도 직전 발화와 안정적으로 연결. +3. 3단계: 멀티턴/슬롯필링 구조를 도입해, 일정/검진/회의 등 복합 작업 흐름에서 자연스러운 후속 질문 처리를 지원. +