DOCS/workflow/01_conversation/message_flow_v2.md
happybell80 9cb0145a4e docs: 01_conversation + 02_skills 워크플로우 문서 현행화 — n8n 제거, SKILL.md+executor 기준 재작성
- coldmail_ir_notification_sync: LangGraph+APScheduler 기반으로 전면 재작성
- slack_action_extractor_request: v2 IntentClassifier→executor 흐름 기준 재작성
- slack_thread_summary_request: 동일
- message_flow_v2: _format_as_robeing() 해석 단계 보완
- skill_calendar/email/news_request: SKILL.md→executor 직접 호출 기준 재작성
- skill_slack_send_message_bridge: slack_sdk 직접 호출 + skill-slack HTTP 이중 경로 기술
- slack_direct_api_send: grounding 개선 사항 반영

Refs: DOCS#8

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 07:57:58 +09:00

126 lines
5.3 KiB
Markdown

---
type: workflow
tags: [workflow, message-flow, rb8001, intent, skill, executor]
last_updated: 2026-04-06
upper_principle:
- /home/admin/0_VALUE/20_Governance/coding-principles.md
- /home/admin/0_VALUE/20_Governance/work-system-principle.md
---
# message_flow_v2 워크플로우
## 목적
사용자 발화가 로빙(rb8001)에 도착해서 응답으로 돌아가기까지의 전체 흐름. SKILL.md 기반 동적 라우팅(M0~M5 완료) 현행 기준. v1(message_service.py 1409줄, decide_skill_sequence, route_with_tools, tool_registry)은 전부 삭제됨.
## 흐름
```
사용자 발화 (Slack/웹)
→ [수신] message_endpoint — 채널 정규화, user_id 추출
→ [컨텍스트] 대화이력(DB 24h) + 감정상태 + 파일첨부 조립
→ [이해] IntentClassifier — SKILL.md 본문을 LLM에 주입, IntentResult(skill, action, slots) 반환
→ [실행] executor — registry에서 URL 해소, external=HTTP POST / internal=직접 호출
→ [응답] 결과 조립 → 채널 어댑터 → 사용자
```
## 단계별 상세
### 1. 수신
| 항목 | 내용 |
|------|------|
| 진입점 | `app/router/message_endpoint.py` |
| 입력 | message, user_id, channel, thread_ts, file_inputs |
| 책임 | 채널별 차이를 정규화하여 내부 형식으로 변환 |
### 2. 컨텍스트 조립
| 항목 | 내용 |
|------|------|
| 대화이력 | DB에서 최근 24h 대화 로드 (최근 5건) |
| 감정상태 | EmotionEngine 현재 상태 |
| 파일 | 첨부파일 요약 (있는 경우) |
| 현재시각 | Asia/Seoul 기준 주입 (요일 포함) |
### 3. 이해 (IntentClassifier)
| 항목 | 내용 |
|------|------|
| 코드 | `app/services/brain/intent_classifier.py` |
| SSOT | `DOCS/skills/*/SKILL.md` — 스킬 목록과 트리거 조건 |
| 입력 | 사용자 메시지 + 컨텍스트 |
| 출력 | `IntentResult(skill, action, endpoint, slots, confidence, reasoning)` |
| 방식 | SKILL.md 본문을 시스템 프롬프트에 주입 → LLM이 판단 → Pydantic 검증 |
| 실패 시 | 에러 raise. 폴백 없음 |
### 4. 실행 (executor)
| 항목 | 내용 |
|------|------|
| 코드 | `app/services/skills/executor.py` |
| URL 해소 | `registry.py`가 SKILL.md의 `runtime.service_url_env`를 읽어 환경변수에서 URL 해소 |
| external_http | `httpx.AsyncClient`로 스킬 서비스에 POST |
| internal_python | 내부 handler 함수 직접 호출 |
| 미등록 스킬 | `{"success": false, "error": "미등록"}` 반환 |
### 5. 해석 (_format_as_robeing)
| 항목 | 내용 |
|------|------|
| 코드 | `app/services/message_service_v2.py:_format_as_robeing()` |
| 입력 | 사용자 원문, IntentResult, executor 실행 결과(JSON) |
| 방식 | DB 프롬프트(`response_formatter_system`) + LLM 호출 (model: `settings.DEFAULT_LLM_MODEL`, temp: 0.3, max_tokens: 200) |
| 출력 | 자연어 문자열. 스킬 결과를 로빙의 말투로 변환 |
| 실패 시 | 원본 JSON 문자열 그대로 반환 |
| 근거 | coding-principles "응답 형식은 접속 대상이 결정한다" — 사람이 대상이므로 문자열 |
### 6. 응답
| 항목 | 내용 |
|------|------|
| 대화 저장 | `_save_conversation()` — DB에 user/assistant 메시지 저장 |
| 채널 전달 | Slack reply / 웹 응답 |
## 스킬 참여 예시
| 사용자 발화 | skill | action | 실행 |
|------------|-------|--------|------|
| "내일 2시 미팅 잡아줘" | skill-calendar | create_event | POST SKILL_CALENDAR_URL/api/events |
| "메일 확인해줘" | skill-email | fetch | POST SKILL_EMAIL_URL/api/emails |
| "로빙아 안녕" | general_chat | chat | 내부 LLM 호출 |
| "삼성전자 뉴스 검색" | web-search | web_search | 내부 웹검색 호출 |
## 코드에 분기문 없음
- 스킬 추가 시 `DOCS/skills/{name}/SKILL.md` 1개 + `runtime.env` URL 1개만 추가
- if/elif 매핑표, IntentType→skill 변환 계층 없음
- 근거: coding-principles §질문별 특례 하드코딩 금지, §식별자 변환 계층 금지
## M0~M5 완료로 삭제된 v1 코드
| 삭제 대상 | 줄 수 | 이유 |
|-----------|-------|------|
| message_service.py | 1409 | v2(137줄)로 완전 대체 |
| decision_engine.decide_skill_sequence + create_execution_plan + route_with_tools | 571 | v2에서 미사용 |
| tool_registry.py | 775 | route_with_tools 전용, import 0건 |
| brain_service.py | 158 | import 0건 |
| v1 전용 테스트 5파일 | ~1100 | 삭제된 코드 테스트 |
## 아직 남아있는 v1 잔재 (의존 살아있음)
| 코드 | 이유 |
|------|------|
| DecisionEngine.classify(), analyze_intent_async() | slack_handler 파일 컨텍스트 주입, intent_classifier 폴백 |
| IntentType enum | slack_handler, slack/message_service 분기 |
| intent_graph, semantic_classifier, skill_doc_loader | router 초기화 체인 |
이들은 Slack 경로가 v2로 완전 전환되면 삭제 가능.
## 관련 문서
- [slack_basic_dialogue.md](./slack_basic_dialogue.md) — v1 (n8n + decision_engine 경로, 레거시)
- [work-system-principle.md](/home/admin/0_VALUE/20_Governance/work-system-principle.md) — 스킬과 워크플로우 구분
- [coding-principles.md](/home/admin/0_VALUE/20_Governance/coding-principles.md) — 입력→판단→출력 3단계 분리
- [로빙_smoke_test_워크플로우.md](/mnt/nas/workspace/shared-editing/workflows/로빙_smoke_test_워크플로우.md) — 배포 후 검증 절차