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

5.3 KiB

type, tags, last_updated, upper_principle
type tags last_updated upper_principle
workflow
workflow
message-flow
rb8001
intent
skill
executor
2026-04-06
/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로 완전 전환되면 삭제 가능.

관련 문서