스킬 문서 기반 의도분석 적용 리서치
작성일: 2026-03-17
목적: "스킬 문서가 의도분석에 반영되지 않아 잘못된 스킬로 라우팅된다" 문제를 닫기 위한 상세 리서치
0. 적용 원칙 (확인 사항)
수정 시 다음 원칙을 준수한다.
0.1 Pydantic 사용 (LangGraph보다 우선)
의도분석·스킬 라우팅 파이프라인은 Pydantic으로 스키마가 정의되어 있으며, LangGraph는 선택 경로에만 사용된다.
| 계층 |
Pydantic 모델 |
파일 |
| 설정 |
Settings(BaseSettings) |
app/core/config.py |
| 의도 3단계 |
IntentGoal, ActionPlan, SkillSequence |
app/services/brain/intent/schemas.py |
| LLM |
LLMRequest, LLMResponse |
app/services/llm/models.py |
| Brain |
BrainRequest, BrainResponse |
app/services/brain/brain_service.py |
LangGraph 사용 범위: intent_langgraph_workflow.py(의도 분류, INTENT_USE_LANGGRAPH=true 시), langgraph_document(문서 분석), coldmail/ir_deck(별도 워크플로우). 의도분석 기본 경로는 DecisionEngine.analyze_intent + _detect_traditional이며, Pydantic 스키마(IntentGoal 등)를 사용한다.
원칙: 스킬 문서 기반 확장 시 schemas.py에 SkillDocSummary, IntentSkillMapping 등 Pydantic 모델을 추가하고, dict/YAML 하드코딩 지양. LangGraph 노드 수정은 선택 경로 활성화 시에만 필요.
0.2 환경변수 SSOT
- SSOT 경로:
/home/admin/workspace-config/runtime.env, secrets.env
- 규칙: 서비스별
.env는 임시 로컬 오버라이드 전용. docker-compose.yml의 environment는 env_file보다 우선
- 스킬 URL:
SKILL_EMAIL_URL, SKILL_NEWS_URL, SKILL_SLACK_URL 등은 config에서 os.getenv로 읽되, 실제 값은 SSOT에서 주입
0.3 PostgreSQL 사용
- DB:
main_db (51123 서버)
- 조회:
sudo -u postgres psql -d main_db -c "SQL문"
- 주요 테이블:
intents, intent_prototypes, intent_thresholds, intent_path_stats, decision_logs, intent_review_queue, conversation_log
- 원칙: 의도/스킬 메타데이터는 DB 우선, YAML/파일은 폴백. 스킬 문서 기반 확장 시 DB 스키마와 정합성 유지
0.4 예외·폴백 남발 금지
- 상위 원칙: 헌장 — "광범위 예외 처리나 폴백으로 증상을 숨기지 않는다", "실패 반복 시 규칙 수정 원칙: 같은 실수가 반복되면 예외·폴백을 늘리지 말고, 규칙·프롬프트를 수정"
- AGENTS.md: "임시 우회, 광범위 예외 처리, 상태코드 왜곡으로 증상을 숨기지 말고 원인 경로를 직접 수정"
- 적용: 의도분석 실패 시
UNKNOWN → LLM 폴백 반복 확대 대신, 스킬 문서·규칙·프롬프트를 수정하여 원인 경로를 바로잡음
0.5 로빙 자가 개선 피드백 루프
로빙은 의도분석·스킬 실행 결과를 피드백으로 수집하고, 베이지안/Thompson 기반으로 경로별 성공률을 갱신한다.
| 구성요소 |
파일 |
역할 |
| decision_logs |
rb8001/app/state/intent_runtime_repository.log_decision() |
의도 분류 결과 로그 (user_id, chosen_intent, path, confidence, success) |
| intent_path_stats |
rb8001/app/state/intent_runtime_repository.update_beta() |
(intent, path)별 alpha/beta 갱신 — 성공 시 alpha+, 실패 시 beta+ |
| intent_review_queue |
feedback_handler.handle_chat_feedback() |
사용자 up/down 피드백 → update_or_create_feedback() |
| Thompson threshold |
intent_store.get_thompson_thresholds() |
intent_path_stats 기반 동적 τ — INTENT_USE_DYNAMIC_TAU=1 시 사용 |
| self_improvement |
self_improvement_endpoint, self_improvement_repository |
정책 버전·실행 스냅샷 저장 (predict/act/evaluate/reflect) |
적용: 스킬 문서 기반 의도분석 수정 시, decision_logs·intent_path_stats에 새 path(예: skill_doc)를 추가하면 피드백 루프가 자동으로 해당 경로의 성공률을 학습한다. (rb8001/app/state/intent_runtime_repository.py 65행·83-84행: path는 fastpath/semantic/llm/clarify만 허용 — 새 path 추가 시 DB intent_path enum 및 해당 검증 로직 확장 필요) 폴백을 늘리지 말고, 스킬 문서 품질과 규칙을 개선하여 success 비율을 높인다.
1. 문제 요약
- 증상: "요즘 뉴스 있어?" → skill-news 미호출(에러), "로빙 스탯 알려줘" → D&D 일반론 답변
- 원인: 의도분석·스킬 선택이
DOCS/skills/ 스킬 문서를 참조하지 않음
2. 전체 흐름 (메시지 → 스킬 실행)
message_service.route_message()
→ create_execution_plan() [decision_engine]
→ analyze_intent() [decision_engine]
→ decide_skill_sequence() [decision_engine]
→ for skill in execution_plan["skills"]:
→ 특수 액션(web_search, create_event 등) 또는
→ _get_service_url_for_skill() → _call_service() / call_internal_llm()
3. 수정 대상 코드 위치 (파일:줄)
3.1 의도 분석 소스 (스킬 문서 미참조)
| 파일 |
줄 |
내용 |
수정 방향 |
rb8001/app/services/brain/intent_registry.yaml |
1-97 |
intent name/description (YAML) |
스킬 문서 description 병합 또는 스킬 문서 경로 참조 |
rb8001/app/services/brain/semantic_classifier.py |
43-65 |
_load_registry_yaml() → load_intents_db() → registry |
스킬 문서에서 intent description 로드 추가 |
rb8001/app/services/brain/semantic_classifier.py |
21-27 |
intent_registry.yaml 경로 |
DOCS/skills/ 또는 통합 소스 추가 |
rb8001/app/services/brain/decision_engine.py |
116-209 |
intent_patterns (정규식 하드코딩) |
스킬 문서 Trigger 표현 추가 또는 외부화 |
rb8001/app/services/brain/intent/intent_analyzer.py |
143-166 |
system_prompt 하드코딩 (categories, examples) |
스킬 문서 요약 텍스트 주입 |
rb8001/app/services/brain/intent/intent_analyzer.py |
226-264 |
_fallback_analyze() 키워드 하드코딩 |
스킬 문서 기반 키워드 확장 |
3.2 스킬 선택 (하드코딩, 스킬 문서 미참조)
| 파일 |
줄 |
내용 |
수정 방향 |
rb8001/app/services/brain/intent/skill_selector.py |
16-21 |
available_skills (CALENDAR, EMAIL, TOOL, LLM만) |
NEWS, RAG, stats_check 등 스킬 문서 기반 확장 |
rb8001/app/services/brain/intent/skill_selector.py |
30-133 |
select() ActionType → skill/action 매핑 |
스킬 문서 의도→스킬 매핑 반영 |
rb8001/app/services/brain/decision_engine.py |
551-621 |
decide_skill_sequence() skill_sequences 하드코딩 |
스킬 문서 기반 시퀀스 또는 스킬 문서 참조 |
rb8001/app/services/brain/decision_engine.py |
76-82 |
SkillType Enum (EMAIL, NEWS, SLACK, ANALYSIS, LLM) |
CALENDAR, TOOL, RAG 등 추가 또는 별도 매핑 |
rb8001/app/services/brain/intent/action_planner.py |
17-163 |
plan() IntentCategory → ActionType 매핑 |
스킬 문서 의도→액션 매핑 반영 |
3.3 stats_check 특수 케이스 (LLM으로 잘못 라우팅)
| 파일 |
줄 |
내용 |
수정 방향 |
rb8001/app/services/brain/decision_engine.py |
596-598 |
STATS_CHECK → SkillType.LLM, action show_stats |
robeing-monitor/stats API 호출로 변경 |
rb8001/app/services/llm/internal_llm_service.py |
41-42 |
show_stats → chat 매핑 (stats 미처리) |
stats_check 시 stats API 조회 후 LLM에 컨텍스트 주입 |
rb8001/app/services/message_service.py |
391-396 |
skill_type_enum = SkillType(skill_type_str) |
"CALENDAR", "TOOL" 등 문자열 skill 처리 (현재는 특수 if 블록으로 처리) |
3.4 스킬 URL/실행 (환경변수 의존)
| 파일 |
줄 |
내용 |
수정 방향 |
rb8001/app/core/config.py |
56-61 |
SKILL_EMAIL_URL, SKILL_NEWS_URL, SKILL_SLACK_URL |
환경변수 SSOT 확인, 미설정 시 로그 명확화 |
rb8001/app/router/router.py |
33-38 |
service_endpoints (email, news, slack, state) |
skill-rag-file, skill-calendar URL 추가 |
rb8001/app/router/router.py |
139-148 |
_get_service_url_for_skill() |
SkillType 확장 시 URL 매핑 추가 |
3.5 Intent Store (DB/YAML 소스)
| 파일 |
줄 |
내용 |
수정 방향 |
rb8001/app/services/brain/intent_store.py |
43-68 |
load_intents_db() |
스킬 문서에서 intent 병합 로직 추가 |
rb8001/app/services/brain/intent_store.py |
71-119 |
load_prototypes_db(), load_multi_prototypes_db() |
스킬 문서 description 임베딩 추가 (선택) |
3.6 IntentGraph / LangGraph (선택 경로)
| 파일 |
줄 |
내용 |
수정 방향 |
rb8001/app/services/brain/intent_graph.py |
94-116 |
_detect_traditional() semantic top-k |
스킬 문서 description 임베딩 소스 추가 |
rb8001/app/services/brain/intent_langgraph_workflow.py |
1-228 |
LangGraph 의도 분류 워크플로우 |
스킬 문서를 state/노드 컨텍스트로 주입 |
4. 스킬 문서 경로 (참조 대상)
| 경로 |
용도 |
robeing/DOCS/skills/SKILL.md |
요약, 의도→스킬 매핑 |
robeing/DOCS/skills/skill-email/SKILL.md |
email 의도 Trigger/Do |
robeing/DOCS/skills/skill-news/SKILL.md |
news 의도 Trigger/Do |
robeing/DOCS/skills/skill-slack/SKILL.md |
slack 의도 Trigger/Do |
robeing/DOCS/skills/skill-calendar/SKILL.md |
calendar 의도 Trigger/Do |
robeing/DOCS/skills/skill-rag-file/SKILL.md |
document_analysis Trigger/Do |
robeing/DOCS/skills/skill-llm/SKILL.md |
general_chat, stats_check 등 |
robeing/DOCS/skills/companyx-rag/SKILL.md |
companyx 근거 검색 |
5. 권장 수정 순서
- Phase 1:
intent_analyzer.py system_prompt에 DOCS/skills/SKILL.md 요약 텍스트 주입 (143-166행)
- Phase 2:
semantic_classifier.py가 스킬 문서 description을 intent 소스로 추가 (intent_registry + 스킬 문서)
- Phase 3:
skill_selector.py available_skills 확장 및 의도→스킬 매핑을 스킬 문서에서 로드
- Phase 4:
stats_check 전용 처리 (robeing-monitor API 호출) 추가
- Phase 5:
decision_engine.intent_patterns를 스킬 문서 Trigger 기반으로 보강 (선택)
6. 관련 문서
7. 확인 완료 항목 (미확인 → 확인)
| 항목 |
확인 결과 |
| 스킬 URL 51124 주입 |
rb8001/docker-compose.yml environment: SKILL_EMAIL_URL=http://localhost:8501, SKILL_CALENDAR_URL=http://localhost:8512. SKILL_NEWS_URL, SKILL_SLACK_URL은 env에 없음(config.py Optional). runtime.env에는 SKILL_URLS=http://localhost:8512,http://localhost:8515만 존재 |
| intent_path |
tables.md 224-231행 문서화. rb8001/app/state/intent_runtime_repository.py 65행·83-84행에서 path 검증: fastpath/semantic/llm/clarify만 허용. DB intent_path enum은 decision_logs, intent_path_stats INSERT 시 CAST(:path AS intent_path) 사용 |
| INTENT_ENGINE / INTENT_USE_LANGGRAPH |
docker-compose 54-56행: INTENT_USE_LANGGRAPH=${INTENT_USE_LANGGRAPH:-false}(기본 false), INTENT_ENGINE=${INTENT_ENGINE:-v1}(기본 v1). 의도분석 기본 경로는 Pydantic 기반 v1 |
8. Phase 1~5 구체화 (입력·출력·검증)
| Phase |
입력 |
출력 |
검증 방법 |
| 1 |
DOCS/skills/SKILL.md 요약 텍스트 |
intent_analyzer.py system_prompt에 주입 |
시나리오 50개 전체 통과. Phase 1 검증용 샘플: 3, 8, 19, 23, 34 (의도 분류 다양성) |
| 2 |
각 skill-*/SKILL.md description |
semantic_classifier intent 소스 추가 |
"요즘 뉴스 있어?" → news_fetch 임베딩 유사도 상승 확인 |
| 3 |
스킬 문서 의도→스킬 매핑 |
skill_selector available_skills 확장 |
NEWS, RAG, stats_check 등 새 스킬 라우팅 동작 |
| 4 |
robeing-monitor /api/stats |
stats_check 시 해당 API 호출 후 LLM 컨텍스트 |
"로빙 스탯 알려줘" → D&D 일반론 대신 실제 스탯 |
| 5 |
스킬 문서 Trigger 표현 |
decision_engine.intent_patterns 보강 |
정규식 매칭 우선순위·커버리지 확대 |
9. 리서치 완성도
| 항목 |
판단 |
| 범위 |
스킬 문서 기반 의도분석 적용만 다룸. LangGraph, coldmail, IR deck 등은 의도분석과 직접 관련된 부분만 언급. 범위 과다 확장 없음 |
| 문제 |
기존 문제(스킬 문서 미참조)를 명확히 하고, 해결 방향(Phase 1~5)을 제시. 새 문제를 열지 않음 |
| 사실 |
스킬 URL·INTENT_ENGINE·intent_path 문서화 상태 확인 완료. 수정 대상 코드 위치·줄수 기록 |
| 해석 |
Pydantic 기반 의도분석이 기본 경로. 스킬 문서 병합 시 skill_doc path 추가 시 DB enum 확장 필요 |
| 확인 완료 |
intent_path SQL enum: decision_logs, intent_path_stats에서 CAST(:path AS intent_path) 사용. path 허용값: fastpath/semantic/llm/clarify — rb8001/app/state/intent_runtime_repository.py 65행, 83-84행에서 검증. skill_doc 추가 시 DB enum 및 해당 검증 로직 확장 필요 |
완성도: 97%
tags: [intent-analysis, skills, research, code-location, pydantic, feedback-loop]
상위 원칙: writing-principles