DOCS/journey/plans/251126_intent_3step_architecture_plan.md

390 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 의도 파악 3단계 아키텍처 전환 계획
**작성일**: 2025-11-26
**작성자**: Auto (Claude)
**상태**: 구현 완료 (2025-11-26)
**관련 문서**:
- `251017_intent_analysis_improvement_plan.md` - 의도 분석 개선 플랜
- `251023_happybell80_의도_런타임_하이브리드_임베딩_베이지안_동적학습.md` - 의도 런타임 설계
- `311_FastAPI_구조_원칙.md` - 코드 작성 원칙
---
## 1. 문제 발견
### 1.1 현재 구조의 근본적 문제
**발견된 문제**:
- IntentType이 스킬/액션과 직접 1:1 매핑되어 있음
- 의도 파악이 곧 스킬 선택으로 이어지는 구조
- 진정한 "의도 파악(무엇을 원하는가)" → "행동 계획(어떻게 할 것인가)" → "스킬 선택(어떤 도구를 쓸 것인가)"의 단계적 분리가 없음
**실제 문제 사례**:
```
사용자: "12월 10일 11시 종합운동장에서 뵙겠습니다. 준비물: 노트북,휴대폰 일정등록"
로빙: "네, 종합운동장 미팅 일정을 12월 10일 11시에 등록해 드릴게요. 구글 캘린더에 등록해드릴까요?"
사용자: "그래"
로빙: "안녕하세요! 무엇을 도와드릴까요? 😊" # ❌ 일반 인사로 돌아감
```
**원인 분석**:
- "구글 캘린더에 등록해드릴까요?" 응답이 `calendar_event` intent로 저장됨
- "그래" 같은 동의 메시지가 `_confirm`으로 끝나는 intent를 찾지 못함
- `calendar_event`는 approval 대상이 아니어서 `calendar_approval`로 변환되지 않음
### 1.2 아키텍처 구조적 문제
**현재 구조**:
```
IntentType (스킬/액션과 직접 매핑)
decide_skill_sequence() → 스킬 선택
```
**문제점**:
- 의도 파악이 스킬 선택에 가까움
- 새로운 의도 추가 시 스킬도 함께 정의해야 함
- 의도와 구현이 강하게 결합됨
---
## 2. 개선 방향
### 2.1 3단계 구조 설계
**목표**: 의도 파악 → 행동 계획 → 스킬 선택의 단계적 접근
```
1단계: 의도 파악 (IntentAnalyzer)
- 추상적 목표 파악 (일정 관리, 정보 검색, 커뮤니케이션 등)
- LLM 기반 제로샷 의도 분석 (무한한 의도 처리 가능)
- 사용자가 무엇을 원하는지 추상적 수준에서 이해
2단계: 행동 계획 (ActionPlanner)
- 구체적 행동 결정 (등록/조회/삭제/수정 등)
- 의도를 달성하기 위한 구체적 행동 계획
- 여러 행동이 필요한 경우 순서 및 우선순위 결정
3단계: 스킬 선택 (SkillSelector)
- 적절한 도구 선택 (calendar_skill.create_event 등)
- 행동을 수행할 적절한 스킬 선택
- 스킬 실행 가능 여부 확인
```
### 2.2 3단계 구조의 장점
- **의도와 구현의 분리**: 같은 의도라도 다른 행동/스킬로 구현 가능
- **확장성**: 새로운 스킬 추가 시 기존 의도 재사용 가능
- **유연성**: 행동 계획 단계에서 여러 대안 고려 가능
- **명확성**: 각 단계의 책임이 명확히 분리됨
- **무한한 의도 처리**: LLM 기반으로 아직 구현되지 않은 의도도 파악 가능
---
## 3. 구현 계획
### 3.1 폴더 구조
```
app/services/brain/
├── intent/ # 신규 폴더
│ ├── __init__.py
│ ├── schemas.py # IntentGoal, ActionPlan, SkillSequence
│ ├── intent_analyzer.py # 1단계: 의도 파악
│ ├── action_planner.py # 2단계: 행동 계획
│ ├── skill_selector.py # 3단계: 스킬 선택
│ ├── intent_graph.py # 기존 파일 이동
│ └── semantic_classifier.py # 기존 파일 이동
├── decision_engine.py # 래퍼로 유지 (하위 호환성)
├── brain_service.py # 3단계 파이프라인 호출
└── ...
```
### 3.2 데이터 구조 정의
**Pydantic 모델** (`app/services/brain/intent/schemas.py`):
```python
from pydantic import BaseModel
from typing import Optional, List, Dict, Any
from enum import Enum
class IntentCategory(str, Enum):
"""추상적 의도 카테고리"""
SCHEDULE_MANAGEMENT = "schedule_management" # 일정 관리
INFORMATION_RETRIEVAL = "information_retrieval" # 정보 검색
COMMUNICATION = "communication" # 커뮤니케이션
DOCUMENT_PROCESSING = "document_processing" # 문서 처리
TASK_EXECUTION = "task_execution" # 작업 실행
GENERAL_INQUIRY = "general_inquiry" # 일반 질의
UNKNOWN = "unknown"
class IntentGoal(BaseModel):
"""1단계: 의도 파악 결과"""
category: IntentCategory # 추상적 카테고리
description: str # LLM이 파악한 의도 설명
confidence: float # 신뢰도 (0.0 ~ 1.0)
raw_intent: Optional[str] = None # LLM 원본 출력 (디버깅용)
context_hints: Dict[str, Any] = {} # 컨텍스트 힌트
class ActionType(str, Enum):
"""구체적 행동 타입"""
CREATE_EVENT = "create_event"
QUERY_EVENTS = "query_events"
DELETE_EVENT = "delete_event"
UPDATE_EVENT = "update_event"
SEARCH_WEB = "search_web"
SEARCH_MEMORY = "search_memory"
SEND_EMAIL = "send_email"
READ_EMAIL = "read_email"
ANALYZE_DOCUMENT = "analyze_document"
CLARIFY = "clarify"
CHAT = "chat"
class ActionPlan(BaseModel):
"""2단계: 행동 계획 결과"""
actions: List[Dict[str, Any]] # 행동 목록
requires_clarification: bool = False
clarification_message: Optional[str] = None
class SkillSequence(BaseModel):
"""3단계: 스킬 선택 결과 (기존 execution_plan과 호환)"""
skills: List[Dict[str, Any]] # 스킬 목록
intent: Dict[str, Any] # 원본 의도 정보 (하위 호환성)
```
### 3.3 데이터 흐름
```
IntentAnalyzer.analyze() → IntentGoal
ActionPlanner.plan(IntentGoal) → ActionPlan
SkillSelector.select(ActionPlan) → SkillSequence
기존 execution_plan 형식으로 변환 (하위 호환성)
```
### 3.4 하위 호환성 유지
**기존 DecisionEngine 클래스는 래퍼로 유지**:
- 내부적으로 3단계 파이프라인 호출
- 기존 API 인터페이스 유지
- 점진적 마이그레이션 가능
---
## 4. TDD 시나리오
### 시나리오 1: 일정 등록 동의 처리 (현재 문제 해결)
```
사용자: "12월 10일 11시 종합운동장에서 뵙겠습니다. 준비물: 노트북,휴대폰 일정등록"
로빙: "네, 종합운동장 미팅 일정을 12월 10일 11시에 등록해 드릴게요. 구글 캘린더에 등록해드릴까요?"
사용자: "그래"
→ IntentGoal: {category: SCHEDULE_MANAGEMENT, description: "일정 등록 승인"}
→ ActionPlan: {actions: [{type: CREATE_EVENT, goal: "구글 캘린더에 일정 등록"}]}
→ SkillSequence: {skills: [{skill: "CALENDAR", action: "create_event"}]}
→ 성공: 일정 등록 완료
```
### 시나리오 2: 아직 구현되지 않은 의도 처리
```
사용자: "내일 오후 2시 회의실 예약해줘"
→ IntentGoal: {category: SCHEDULE_MANAGEMENT, description: "회의실 예약 요청"}
→ ActionPlan: {actions: [{type: CREATE_EVENT, goal: "회의실 예약"}]}
→ SkillSelector: 회의실 예약 스킬 없음 감지
→ 로빙: "죄송합니다. 회의실 예약 기능은 아직 준비 중입니다. 구글 캘린더에 일정만 등록해드릴까요?"
```
### 시나리오 3: 복합 의도 처리
```
사용자: "리버스마운틴 유사 기업 찾아서 가치평가 보고서 이메일로 보내줘"
→ IntentGoal: {category: INFORMATION_RETRIEVAL, description: "기업 검색 및 분석 후 이메일 발송"}
→ ActionPlan: {actions: [
{type: SEARCH_WEB, goal: "리버스마운틴 유사 기업 검색", priority: 1},
{type: ANALYZE_DOCUMENT, goal: "가치평가 분석", priority: 2},
{type: SEND_EMAIL, goal: "보고서 이메일 발송", priority: 3}
]}
→ SkillSequence: {skills: [
{skill: "TOOL", action: "web_search"},
{skill: "LLM", action: "analyze"},
{skill: "EMAIL", action: "compose"}
]}
```
### 시나리오 4: 맥락 기반 의도 파악
```
사용자: "아까 말한 그 기업 투자 단계는?"
→ IntentGoal: {category: INFORMATION_RETRIEVAL, description: "이전 대화에서 언급된 기업의 투자 단계 조회", context_hints: {reference: "previous_conversation"}}
→ ActionPlan: {actions: [{type: SEARCH_MEMORY, goal: "이전 대화에서 기업 정보 검색"}]}
→ SkillSequence: {skills: [{skill: "LLM", action: "search_memory"}]}
→ 성공: ChromaDB에서 관련 대화 검색 후 답변
```
### 시나리오 5: 모호한 의도 명확화
```
사용자: "이메일 보내줘"
→ IntentGoal: {category: COMMUNICATION, description: "이메일 발송 요청", confidence: 0.6}
→ ActionPlan: {
requires_clarification: True,
clarification_message: "누구에게 보내실까요? 어떤 내용을 보내실까요?"
}
→ SkillSequence: {skills: []}
→ 로빙: "누구에게 보내실까요? 어떤 내용을 보내실까요?"
```
---
## 5. 수정 범위
### 5.1 수정 필요한 부분
**백엔드 (rb8001)**:
- `app/services/brain/decision_engine.py` → 3단계 파이프라인으로 재구성
- `app/services/brain/intent/` 폴더 신규 생성
- `app/services/brain/brain_service.py` → 3단계 파이프라인 호출
### 5.2 수정 불필요한 부분
- **Gateway (robeing-gateway)**: 변경 불필요, JWT 검증/프록시 역할 유지
- **프론트엔드**: 변경 불필요, API 인터페이스 동일
- **DB 스키마**: 변경 불필요, 의도/행동 계획은 런타임 처리
---
## 6. 구현 순서
### Phase 1: 구조 설계 및 스키마 정의 (1일)
1. `app/services/brain/intent/` 폴더 생성
2. `schemas.py` 작성 (IntentGoal, ActionPlan, SkillSequence)
3. 기존 파일 이동 (intent_graph.py, semantic_classifier.py)
### Phase 2: IntentAnalyzer 구현 (2일)
1. LLM 기반 제로샷 의도 분석
2. IntentCategory 분류
3. TDD 테스트 작성
### Phase 3: ActionPlanner 구현 (2일)
1. IntentGoal → ActionPlan 변환 로직
2. 복합 행동 처리
3. Clarify 로직
### Phase 4: SkillSelector 구현 (2일)
1. ActionPlan → SkillSequence 변환
2. 기존 execution_plan 형식으로 변환
3. 하위 호환성 유지
### Phase 5: 통합 및 테스트 (2일)
1. DecisionEngine 래퍼 구현
2. 기존 테스트 통과 확인
3. TDD 시나리오 검증
---
## 7. 참고 사항
### 7.1 코드 작성 원칙 준수
- 계층 분리: router → services → state
- 파일 크기: 한 파일 최대 300줄
- 의존성 방향: 단방향 흐름
### 7.2 하위 호환성
- 기존 DecisionEngine API 유지
- 기존 execution_plan 형식 유지
- 점진적 마이그레이션 가능
---
**작성 완료**: 2025-11-26
**다음 단계**: Phase 1 구현 시작
---
## 8. 구현 완료 (2025-11-26)
### 8.1 구현 내용
**완료된 작업**:
1. ✅ IntentAnalyzer 구현 (`app/services/brain/intent/intent_analyzer.py`)
- LLM 기반 제로샷 의도 분석 (async)
- 키워드 기반 폴백 분석 (sync)
- IntentCategory 분류 지원
2. ✅ ActionPlanner 확장 (`app/services/brain/intent/action_planner.py`)
- 모든 IntentCategory에 대한 ActionType 매핑
- SCHEDULE_MANAGEMENT: CREATE_EVENT, QUERY_EVENTS, DELETE_EVENT, UPDATE_EVENT
- INFORMATION_RETRIEVAL: SEARCH_WEB, SEARCH_MEMORY
- COMMUNICATION: SEND_EMAIL, READ_EMAIL
- DOCUMENT_PROCESSING: ANALYZE_DOCUMENT
- TASK_EXECUTION, GENERAL_INQUIRY: CHAT
- UNKNOWN: CLARIFY
3. ✅ SkillSelector 확장 (`app/services/brain/intent/skill_selector.py`)
- 모든 ActionType에 대한 스킬 매핑
- CALENDAR, EMAIL, TOOL, LLM 스킬 지원
4. ✅ DecisionEngine 통합 (`app/services/brain/decision_engine.py`)
- `_build_intent_pipeline_sync`: 동기 버전 (폴백 분석)
- `_build_intent_pipeline`: 비동기 버전 (LLM 기반)
- `create_execution_plan``intent_pipeline` 메타데이터 추가
5. ✅ 테스트 통과
- ActionPlanner 테스트 통과
- SkillSelector 테스트 통과
- DecisionEngine 통합 테스트 통과
### 8.2 배포 상태
- **커밋**: `1b57c86` - "feat: 3단계 의도 파악 아키텍처 구현"
- **배포 완료**: 2025-11-26 19:17
- **컨테이너 상태**: 정상 (healthy)
### 8.3 하위 호환성
- 기존 `decide_skill_sequence` 메서드 유지 (하위 호환성)
- 새로운 3단계 파이프라인은 `execution_plan["intent_pipeline"]` 메타데이터로 제공
- 점진적 마이그레이션을 위해 두 시스템 병행
### 8.4 중복 코드 확인
- `decide_skill_sequence``SkillSelector` 모두 IntentType/ActionType → Skill 매핑 포함
- 의도적 중복: 하위 호환성 및 점진적 마이그레이션을 위해 병행 유지
- 주석 추가로 의도 명확화
---
## 9. DB/베이지안 방법 통합 방안
### 9.1 문제
5가지 TDD 시나리오 테스트 결과 시나리오 2~5가 미비:
- 시나리오 2: 미구현 의도 처리 - clarify 없음
- 시나리오 3: 복합 의도 처리 - 단일 액션만 생성
- 시나리오 4: 맥락 기반 의도 파악 - UNKNOWN 분류
- 시나리오 5: 모호한 의도 명확화 - clarify 없음
### 9.2 해결 방안
기존 DB/베이지안 방법(`intent_prototypes`, `intent_thresholds`, `intent_path_stats`)을 3단계 아키텍처에 통합:
- **IntentAnalyzer**: `SemanticIntentClassifier` 재사용, 임베딩 기반 후보 축소
- **ActionPlanner**: `intent_path_stats`의 Beta(α,β)로 액션 우선순위 조정, 복합 의도 파싱
- **SkillSelector**: 스킬별 실행 성공률 추적, 미구현 스킬 감지
**상세 내용**: `251126_intent_3step_db_bayesian_integration.md` 참고
---
## 10. 리스크 및 추가 고려사항
- **회귀 및 승인/컨펌 흐름 붕괴 리스크**
- 기존 DecisionEngine이 암묵적으로 처리하던 승인/취소/컨펌, 예외 케이스들이 IntentGoal → ActionPlan → SkillSequence 분리 과정에서 깨질 수 있음 (예: 같은 입력인데 캘린더/이메일 오작동).
- 실제 서비스 대화 로그를 기반으로 한 리플레이 테스트 세트, A/B 플래그(구 구조/신 구조 토글), 빠른 롤백 전략을 설계한 뒤 단계적으로 트래픽을 전환해야 함.
- **LLM 기반 1단계 도입에 따른 비용/레이턴시/안정성 이슈**
- 모든 발화가 최소 1회 LLM을 타면 레이턴시·비용·비결정성이 커지므로, 고빈도·단순 패턴(“그래”, “응”, 일정 단문 등)은 규칙/통계 모델로 단축 경로를 두고, 각 단계별 confidence 기준과 실패 시 폴백 전략(UNKNOWN → 안전한 일반 대화/질문 재확인)을 명시적으로 정의해야 함.
- LLM 프롬프트/파라미터 변경에 따른 드리프트를 감시할 수 있도록, IntentAnalyzer 입력/출력(카테고리, 설명, confidence)을 구조화된 로그로 남기고 모니터링 지표(오탐/미탐 비율, 평균 응답 시간 등)를 운영 레벨에서 관리해야 함.
- **학습·개선 루프까지 포함한 설계**
- 3단계 분리는 파일 구조 정리가 아니라, 각 단계에서 생성되는 신호를 intent_review/active_learning과 연결해 시간이 지날수록 의도→행동→스킬 품질이 자동 개선되도록 만드는 것이 핵심.
- IntentGoal/ActionPlan/SkillSequence 및 실제 실행 결과(성공/실패, 사용자 피드백)를 표준 스키마로 저장하고, 이를 기반으로 한 오프라인 평가·액티브 러닝·온라인 튜닝 루프를 설계해야 함.