# πŸŽ‰ MarketSync (λ§ˆμΌ“μ‹±ν¬) ### Agentic RAG 기반 μ†Œμƒκ³΅μΈ λ§žμΆ€ν˜• μ§€μ—­ μΆ•μ œ μΆ”μ²œ & λ§ˆμΌ€νŒ… AI μ»¨μ„€ν„΄νŠΈ μ‹ ν•œμΉ΄λ“œ 빅데이터와 μ „κ΅­ μΆ•μ œ 정보λ₯Ό 톡합 λΆ„μ„ν•˜μ—¬, **AI μ—μ΄μ „νŠΈ**κ°€ κ°€κ²Œλ³„λ‘œ μ°Έμ—¬ν•  λ§Œν•œ μ§€μ—­ μΆ•μ œλ₯Ό μΆ”μ²œν•˜κ³  졜적의 λ§ˆμΌ€νŒ… μ „λž΅ λ³΄κ³ μ„œλ₯Ό μžλ™ μƒμ„±ν•©λ‹ˆλ‹€. πŸ€– --- ## 🧭 ν”„λ‘œμ νŠΈ κ°œμš” MarketSyncλŠ” **Streamlit μ›Ή μΈν„°νŽ˜μ΄μŠ€, FastAPI 데이터 μ„œλ²„, LangChain μ—μ΄μ „νŠΈ**λ₯Ό κ²°ν•©ν•˜μ—¬ μ†Œμƒκ³΅μΈμ„ μœ„ν•œ AI μ»¨μ„€νŒ… μ„œλΉ„μŠ€λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€. μ‚¬μš©μžλŠ” μžμ‹ μ˜ κ°€κ²Œλ₯Ό μ„ νƒν•˜μ—¬ 상세 ν”„λ‘œν•„κ³Ό 뢄석 κ·Έλž˜ν”„λ₯Ό ν™•μΈν•œ λ’€, "10월에 μ—΄λ¦¬λŠ” μΆ•μ œ μΆ”μ²œν•΄μ€˜", "μΆ”μ²œλœ μΆ•μ œλ“€μ˜ λ§ˆμΌ€νŒ… μ „λž΅ μ•Œλ €μ€˜" 와 같은 μžμ—°μ–΄ μ§ˆλ¬Έμ„ 톡해 λ§žμΆ€ν˜• μ»¨μ„€νŒ…μ„ 받을 수 μžˆμŠ΅λ‹ˆλ‹€. **핡심 μ•„ν‚€ν…μ²˜λŠ” Agentic RAG**μž…λ‹ˆλ‹€. AI μ—μ΄μ „νŠΈ(`Orchestrator`)λŠ” μ‚¬μš©μžμ˜ 질문과 κ°€κ²Œμ˜ 상세 ν”„λ‘œν•„(JSON)을 λ°”νƒ•μœΌλ‘œ 상황에 λ§žλŠ” **도ꡬ(Tool)**λ₯Ό 자율적으둜 μ„ νƒν•˜κ³ , μ‚¬μš©μžμ˜ μ§ˆλ¬Έμ— 따라 ν•„μš”ν•˜λ‹€λ©΄ μ—¬λŸ¬ 도ꡬλ₯Ό 순차적으둜 ν˜ΈμΆœν•˜μ—¬ μ΅œμ’… μ»¨μ„€νŒ… λ³΄κ³ μ„œλ₯Ό μƒμ„±ν•©λ‹ˆλ‹€. --- ## πŸ› οΈ 핡심 도ꡬ 및 μž‘λ™ 방식 AI μ—μ΄μ „νŠΈκ°€ μ‚¬μš©ν•˜λŠ” μ£Όμš” 도ꡬ와 λ‚΄λΆ€ 처리 과정은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€. | κΈ°λŠ₯ λΆ„λ₯˜ | 도ꡬ ν•¨μˆ˜λͺ… (`tools/`) | μ£Όμš” 처리 κ³Όμ • (`modules/`) | | :--------------- | :------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **μΆ•μ œ μΆ”μ²œ** | `recommend_festivals` (festival\_recommender.py) | **ν•˜μ΄λΈŒλ¦¬λ“œ 5단계 νŒŒμ΄ν”„λΌμΈ (`filtering.py`)**:
1. LLM 쿼리 μž¬μž‘μ„±
2. FAISS 벑터 검색 (μœ μ‚¬ μΆ•μ œ 후보 μ„ μ •)
3. LLM 동적 속성 평가 (κ°€κ²Œ λ§žμΆ€μ„±)
4. ν•˜μ΄λΈŒλ¦¬λ“œ 점수 계산
5. μ΅œμ’… Top3 κ²°κ³Ό ν¬λ§·νŒ… (2026 예츑 포함) | | **λ§ˆμΌ€νŒ… (RAG)** | `search_contextual_marketing_strategy` (marketing\_strategy.py) | **μ»¨ν…μŠ€νŠΈ 기반 RAG (`knowledge_base.py`)**:
1. κ°€κ²Œ ν”„λ‘œν•„ + 질문 β†’ LLM 검색 쿼리 생성
2. FAISS 벑터 검색 (κ΄€λ ¨ μ „λž΅ λ¬Έμ„œ μΆ”μΆœ)
3. LLM λ‹΅λ³€ 생성 (μΆ”μΆœλœ λ‚΄μš©μ„ λ°”νƒ•μœΌλ‘œ μžμ—°μŠ€λŸ¬μš΄ μ „λž΅ μ œμ•ˆ) | | **λ§ˆμΌ€νŒ… (생성)** | `create_festival_specific_marketing_strategy` (marketing\_strategy.py) | **LLM 기반 μ „λž΅ 생성**:
1. μΆ•μ œ ν”„λ‘œν•„ 쑰회 (`profile_analyzer.py`)
2. κ°€κ²Œ ν”„λ‘œν•„ + μΆ•μ œ ν”„λ‘œν•„ + RAG 검색 β†’ LLM ν”„λ‘¬ν”„νŠΈ ꡬ성
3. LLM이 νŠΉμ • μΆ•μ œ 맞좀 μ „λž΅ 생성 | | **λ§ˆμΌ€νŒ… (생성)** | `create_marketing_strategies_for_multiple_festivals` (marketing\_strategy.py) | **LLM 기반 μ „λž΅ 생성 (λ‹€μˆ˜)**:
1. μ—¬λŸ¬ μΆ•μ œ 이름 μž…λ ₯λ°›μŒ
2. 각 μΆ•μ œλ³„λ‘œ `create_festival_specific_marketing_strategy` 반볡 호좜
3. λͺ¨λ“  μ „λž΅μ„ ν•˜λ‚˜μ˜ λ³΄κ³ μ„œλ‘œ μ·¨ν•© | | **κ°€κ²Œ 뢄석** | `analyze_merchant_profile` (profile\_analyzer.py) | **LLM 기반 뢄석**:
κ°€κ²Œ ν”„λ‘œν•„(JSON) μž…λ ₯ β†’ LLM이 SWOT 뢄석 및 핡심 고객 νŠΉμ„± μš”μ•½ λ³΄κ³ μ„œ 생성 | | **μΆ•μ œ 뢄석** | `analyze_festival_profile` (profile\_analyzer.py) | **LLM 기반 뢄석**:
μΆ•μ œ ν”„λ‘œν•„(JSON) μž…λ ₯ β†’ LLM이 μΆ•μ œμ˜ 핡심 νŠΉμ§• 및 μ£Όμš” 방문객 νŠΉμ„± μš”μ•½ λ³΄κ³ μ„œ 생성 | | **μΆ•μ œ 쑰회** | `get_festival_profile_by_name` (profile\_analyzer.py) | **λ‹¨μˆœ 데이터 쑰회**: μΆ•μ œ 이름 μž…λ ₯ β†’ `festival_df.csv`μ—μ„œ ν•΄λ‹Ή μΆ•μ œ 정보(JSON) λ°˜ν™˜ (캐싱 ν™œμš©) | --- ## πŸ“‚ ν”„λ‘œμ νŠΈ ꡬ쑰 및 μ½”λ“œ μ„€λͺ… ```plaintext MarketSync/ β”œβ”€β”€ streamlit_app.py # Streamlit μ›Ή μΈν„°νŽ˜μ΄μŠ€ (UI) β”œβ”€β”€ orchestrator.py # AI μ—μ΄μ „νŠΈ: LangChain AgentExecutor, 도ꡬ λΌμš°νŒ…, μ΅œμ’… λ‹΅λ³€ 생성 둜직 β”œβ”€β”€ config.py # μ„€μ • 쀑앙화: 경둜, API ν‚€, λͺ¨λΈλͺ…, λ‘œκΉ… μ„€μ • λ“± β”‚ β”œβ”€β”€ api/ # 데이터 제곡 및 μ „μ²˜λ¦¬ μ„œλ²„ β”‚ β”œβ”€β”€ server.py # FastAPI μ„œλ²„: /profile, /merchants μ—”λ“œν¬μΈνŠΈ 제곡 β”‚ └── data_loader.py # 데이터 λ‘œλ”© 및 μ „μ²˜λ¦¬ (final_df.csv, festival_df.csv) β”‚ β”œβ”€β”€ tools/ # LangChain @tool 도ꡬ μ •μ˜ λ ˆμ΄μ–΄ β”‚ β”œβ”€β”€ festival_recommender.py # [Tool] recommend_festivals 도ꡬ μ •μ˜ (filtering.py 호좜) β”‚ β”œβ”€β”€ marketing_strategy.py # [Tool] λ§ˆμΌ€νŒ… μ „λž΅ κ΄€λ ¨ 도ꡬ 3개 μ •μ˜ (knowledge_base.py, profile_analyzer.py λ“± 호좜) β”‚ β”œβ”€β”€ profile_analyzer.py # [Tool] κ°€κ²Œ/μΆ•μ œ 뢄석 및 μΆ•μ œ ν”„λ‘œν•„ 쑰회 도ꡬ 3개 μ •μ˜ (LLM 호좜, 데이터 쑰회) β”‚ └── tool_loader.py # λͺ¨λ“  도ꡬ(@tool)λ₯Ό 리슀트둜 λ¬Άμ–΄ Orchestrator에 제곡 β”‚ β”œβ”€β”€ modules/ # 핡심 둜직 κ΅¬ν˜„ λͺ¨λ“ˆ β”‚ β”œβ”€β”€ filtering.py # [μΆ•μ œ μΆ”μ²œ] FestivalRecommender 클래슀 (5단계 νŒŒμ΄ν”„λΌμΈ κ΅¬ν˜„) β”‚ β”œβ”€β”€ knowledge_base.py # [RAG] FAISS 벑터 μŠ€ν† μ–΄ λ‘œλ”© (μΆ•μ œ, λ§ˆμΌ€νŒ…), μž„λ² λ”© λͺ¨λΈ 관리 β”‚ β”œβ”€β”€ llm_provider.py # LLM μΈμŠ€ν„΄μŠ€ 관리 (μ „μ—­ 곡유 및 Temperature 쑰절) β”‚ β”œβ”€β”€ profile_utils.py # κ°€κ²Œ ν”„λ‘œν•„ JSON 가곡 μœ ν‹Έλ¦¬ν‹° (μ±„νŒ…μš©/λΆ„μ„μš©) β”‚ └── visualization.py # Streamlit μ‹œκ°ν™”: Matplotlib κ·Έλž˜ν”„ 생성 ν•¨μˆ˜ β”‚ β”œβ”€β”€ utils/ # 곡톡 μœ ν‹Έλ¦¬ν‹° β”‚ └── parser_utils.py # LLM μ‘λ‹΅μ—μ„œ JSON μΆ”μΆœ νŒŒμ„œ β”‚ β”œβ”€β”€ data/ # 원본 데이터 β”‚ β”œβ”€β”€ final_df.csv # μ‹ ν•œμΉ΄λ“œ 가맹점 데이터 β”‚ └── festival_df.csv # μ „κ΅­ μΆ•μ œ 정보 데이터 β”‚ └── vectorstore/ # FAISS 벑터 λ°μ΄ν„°λ² μ΄μŠ€ μ €μž₯ 폴더 β”œβ”€β”€ faiss_festival # μΆ•μ œ 정보 벑터 DB └── faiss_marketing # λ§ˆμΌ€νŒ… μ „λž΅ 벑터 DB ``` ------------------------------------------------------------------------ ## πŸ”„ μ•„ν‚€ν…μ²˜ 및 데이터 흐름 이 μ‹œμŠ€ν…œμ€ **μ—μ΄μ „νŠΈ μ€‘μ‹¬μ˜ 도ꡬ 호좜 (Tool-Calling)** μ•„ν‚€ν…μ²˜λ₯Ό 기반으둜 μž‘λ™ν•©λ‹ˆλ‹€. μ‚¬μš©μžμ˜ μžμ—°μ–΄ μ§ˆλ¬Έμ€ `Orchestrator`λΌλŠ” AI μ—μ΄μ „νŠΈμ— μ˜ν•΄ ν•΄μ„λ˜λ©°, μ—μ΄μ „νŠΈλŠ” 제곡된 `[κ°€κ²Œ ν”„λ‘œν•„]` μ»¨ν…μŠ€νŠΈμ™€ **μ‹œμŠ€ν…œ ν”„λ‘¬ν”„νŠΈ**의 지침에 따라 κ°€μž₯ μ μ ˆν•œ 도ꡬλ₯Ό μ„ νƒν•˜κ³  μ‹€ν–‰ν•©λ‹ˆλ‹€. ν•„μš”ν•˜λ‹€λ©΄ μ—¬λŸ¬ 도ꡬλ₯Ό 순차적으둜 ν˜ΈμΆœν•˜μ—¬ 얻은 정보λ₯Ό μ’…ν•©ν•œ λ’€, μ΅œμ’… μ»¨μ„€νŒ… 닡변을 μƒμ„±ν•©λ‹ˆλ‹€. --- ## 🧩 μ‹œμŠ€ν…œ ꡬ성도 ### (1) 전체 κ°œμš”: UI - μ—μ΄μ „νŠΈ - API μƒν˜Έμž‘μš© μ‚¬μš©μžκ°€ UIλ₯Ό 톡해 μ§ˆλ¬Έν•˜λ©΄, **μ—μ΄μ „νŠΈ(Orchestrator)** κ°€ μž‘λ™ν•˜κ³ , ν•„μš” μ‹œ FastAPI μ„œλ²„λ‚˜ **μ—¬λŸ¬ 도ꡬ(Tool)** 와 μƒν˜Έμž‘μš©ν•©λ‹ˆλ‹€. ```mermaid graph TD %% ======================== %% AI μ»¨μ„€νŒ… μ—”μ§„ (μ΅œμƒλ‹¨) %% ======================== subgraph SG_Engine ["🧠 AI μ»¨μ„€νŒ… μ—”μ§„"] direction TB C["πŸ€– Orchestrator (핡심 μ—μ΄μ „νŠΈ)\n(orchestrator.py)\nAgentExecutor (LangChain)"] D{"🚦 Tool Routing\nLLM μ˜λ„ 뢄석 & 도ꡬ 선택"} subgraph SG_Tools ["πŸ”§ λ“±λ‘λœ 도ꡬ λͺ©λ‘ (tools/)"] T1["recommend_festivals\n(μΆ•μ œ μΆ”μ²œ)"] T2["search_contextual_marketing_strategy\n(RAG λ§ˆμΌ€νŒ… μ „λž΅)"] T3["create_festival_specific_marketing_strategy\n(단일 μΆ•μ œ μ „λž΅)"] T3_multi["create_marketing_strategies_for_multiple_festivals\n(λ‹€μˆ˜ μΆ•μ œ μ „λž΅)"] T4["analyze_merchant_profile\n(κ°€κ²Œ 뢄석)"] T5["analyze_festival_profile\n(μΆ•μ œ 뢄석)"] T6["get_festival_profile_by_name\n(μΆ•μ œ ν”„λ‘œν•„ 쑰회)"] end LLM_Final["πŸͺ„ LLM (Final Report Generation)\nμ΅œμ’… λ³΄κ³ μ„œ 생성"] end %% ======================== %% μ‚¬μš©μž μΈν„°νŽ˜μ΄μŠ€ & 데이터 μ„œλ²„ (ν•˜λ‹¨) %% ======================== subgraph SG_UserServer ["πŸ’» μ‚¬μš©μž μΈν„°νŽ˜μ΄μŠ€ & 데이터 μ„œλ²„"] direction LR A["πŸ–₯️ Streamlit UI\n(streamlit_app.py)\nμ‚¬μš©μž μƒν˜Έμž‘μš©"] <--> B["πŸš€ FastAPI Server\n(api/server.py)\nπŸ“Š κ°€κ²Œ ν”„λ‘œν•„ / λͺ©λ‘ 쑰회"] end %% ======================== %% μ—°κ²° 관계 (μˆ˜μ •) %% ======================== A -- "μžμ—°μ–΄ 질문 μž…λ ₯" --> C C -- "μ˜λ„ 뢄석 μš”μ²­" --> D D -- "적합 도ꡬ 선택/μ‹€ν–‰" --> SG_Tools SG_Tools -- "도ꡬ μ‹€ν–‰ κ²°κ³Ό" --> C C -- "μ΅œμ’… λ³΄κ³ μ„œ 생성 μš”μ²­" --> LLM_Final LLM_Final -- "μ΅œμ’… κ²°κ³Ό 전달" --> A %% ======================== %% μŠ€νƒ€μΌ μ§€μ • (GitHub ν˜Έν™˜) %% ======================== style A fill:#4CAF50,color:#fff,stroke:#388E3C,stroke-width:2px style B fill:#FF9800,color:#fff,stroke:#EF6C00,stroke-width:2px style C fill:#E91E63,color:#fff,stroke:#C2185B,stroke-width:2px style D fill:#9C27B0,color:#fff,stroke:#7B1FA2,stroke-width:2px,shape:diamond style SG_Tools fill:#E1F5FE, stroke:#0277BD,color:#000 style T1,T2,T3,T3_multi,T4,T5,T6 fill:#03A9F4,color:#fff,stroke:#0288D1,stroke-width:2px,shape:hexagon style LLM_Final fill:#BA68C8,color:#fff,stroke:#8E24AA,stroke-width:2px ``` --- ### (2) μΆ•μ œ μΆ”μ²œ 도ꡬ 상세 β€” `recommend_festivals` LLM 기반 **ν•˜μ΄λΈŒλ¦¬λ“œ 5단계 νŒŒμ΄ν”„λΌμΈ**을 톡해, κ°€κ²Œ λ§žμΆ€ν˜• μΆ•μ œλ₯Ό μΆ”μ²œν•©λ‹ˆλ‹€. ```mermaid graph TD %% ======================== %% Orchestrator μš”μ²­ %% ======================== subgraph SG_Orchestrator_Req ["🧠 Orchestrator μš”μ²­"] Agent["πŸ€– AgentExecutor"] -- "μΆ•μ œ μΆ”μ²œ μš”μ²­" --> Tool_Rec["🧩 Tool: recommend_festivals"] end %% ======================== %% 지식 베이슀 (μˆ˜μ •) %% ======================== subgraph SG_KnowledgeBase ["πŸ“š 지식 베이슀 (modules/knowledge_base.py)"] direction LR EM["🧬 Embedding Model\n(HuggingFace)"] VSF["πŸ“‚ FAISS (μΆ•μ œ DB)"] EM -- "μž„λ² λ”© 생성 (Offline)" --> VSF end %% ======================== %% Filtering Pipeline %% ======================== subgraph SG_Filtering_Pipeline ["πŸ” Filtering Pipeline (modules/filtering.py)"] Tool_Rec --> Step1["1️⃣ LLM 쿼리 μž¬μž‘μ„±"] Step1 --> Step2["2️⃣ FAISS 벑터 검색\n(μœ μ‚¬ μΆ•μ œ 후보 탐색)"] %% RAG 흐름 λͺ…ν™•ν™” (μˆ˜μ •) Step2 -- "쿼리 μž„λ² λ”©" --> EM Step2 -- "μœ μ‚¬λ„ 검색" --> VSF Step2 --> Step3["3️⃣ LLM 동적 속성 평가\n(κ°€κ²Œ λ§žμΆ€μ„± νŒλ‹¨)"] Step3 --> LLM1["πŸ€– LLM (Dynamic Evaluation)"] Step3 --> Step4["4️⃣ ν•˜μ΄λΈŒλ¦¬λ“œ 점수 계산\n(μœ μ‚¬λ„ + λ§žμΆ€μ„±)"] Step4 --> Step5["5️⃣ μ΅œμ’… κ²°κ³Ό ν¬λ§·νŒ…\n(Top3 + 2026 예츑 포함)"] end %% ======================== %% κ²°κ³Ό λ°˜ν™˜ %% ======================== subgraph SG_Result_Return ["πŸ“¦ κ²°κ³Ό λ°˜ν™˜"] Step5 -- "Top3 μΆ•μ œ μΆ”μ²œ κ²°κ³Ό" --> Agent end %% ======================== %% μŠ€νƒ€μΌ %% ======================== style Agent fill:#E91E63,color:#fff style Tool_Rec fill:#03A9F4,color:#fff style Step1,Step2,Step3,Step4,Step5 fill:#81D4FA,color:#000 style VSF fill:#FFC107,color:#000 style EM fill:#4DD0E1,color:#000 style LLM1 fill:#BA68C8,color:#fff style SG_KnowledgeBase fill:#F5F5F5,stroke:#9E9E9E ``` --- ### (3) λ§ˆμΌ€νŒ… μ „λž΅ (RAG) 도ꡬ 상세 β€” `search_contextual_marketing_strategy` **RAG** 기반으둜 **κ°€κ²Œ ν”„λ‘œν•„ + 질문 μ»¨ν…μŠ€νŠΈ**λ₯Ό μ΄μš©ν•΄ κ°€μž₯ κ΄€λ ¨μ„± 높은 λ§ˆμΌ€νŒ… μ „λž΅ λ¬Έμ„œλ₯Ό κ²€μƒ‰ν•˜κ³ , LLM이 μžμ—°μŠ€λŸ½κ²Œ μš”μ•½/μ œμ•ˆν•©λ‹ˆλ‹€. ```mermaid graph TD %% ======================== %% Orchestrator μš”μ²­ %% ======================== subgraph SG_Orchestrator_Req_RAG ["🧠 Orchestrator μš”μ²­"] Agent["πŸ€– AgentExecutor"] -- "λ§ˆμΌ€νŒ… μ „λž΅ (RAG) μš”μ²­" --> Tool_RAG["🧩 Tool: search_contextual_marketing_strategy"] end %% ======================== %% 지식 베이슀 (μˆ˜μ •) %% ======================== subgraph SG_KnowledgeBase_RAG ["πŸ“š 지식 베이슀 (modules/knowledge_base.py)"] direction LR EM["🧬 Embedding Model\n(HuggingFace)"] VSM["πŸ“‚ FAISS (λ§ˆμΌ€νŒ… DB)"] EM -- "μž„λ² λ”© 생성 (Offline)" --> VSM end %% ======================== %% RAG Logic %% ======================== subgraph SG_RAG_Logic ["βš™οΈ RAG Logic (tools/marketing_strategy.py)"] Tool_RAG --> Step1["1️⃣ LLM 검색 쿼리 생성\n(κ°€κ²Œ ν”„λ‘œν•„ + 질문 기반)"] Step1 --> Step2["2️⃣ FAISS 벑터 검색\n(λ§ˆμΌ€νŒ… DB 탐색)"] %% RAG 흐름 λͺ…ν™•ν™” (μˆ˜μ •) Step2 -- "쿼리 μž„λ² λ”©" --> EM Step2 -- "μœ μ‚¬λ„ 검색" --> VSM Step2 --> Step3["3️⃣ LLM λ‹΅λ³€ 생성\n(κ²€μƒ‰λœ μ»¨ν…μŠ€νŠΈ 기반)"] Step3 --> LLM2["πŸ€– LLM (Answer Synthesis)"] end %% ======================== %% κ²°κ³Ό λ°˜ν™˜ %% ======================== subgraph SG_Result_Return_RAG ["πŸ“¦ κ²°κ³Ό λ°˜ν™˜"] Step3 -- "μƒμ„±λœ λ§ˆμΌ€νŒ… μ „λž΅ ν…μŠ€νŠΈ" --> Agent end %% ======================== %% μŠ€νƒ€μΌ %% ======================== style Agent fill:#E91E63,color:#fff style Tool_RAG fill:#03A9F4,color:#fff style Step1,Step2,Step3 fill:#81D4FA,color:#000 style VSM fill:#FFC107,color:#000 style EM fill:#4DD0E1,color:#000 style LLM2 fill:#BA68C8,color:#fff style SG_KnowledgeBase_RAG fill:#F5F5F5,stroke:#9E9E9E ``` --- ### (4) LLM 기반 뢄석 도ꡬ 상세 β€” `analyze_merchant_profile` / `analyze_festival_profile` κ°€κ²Œ λ˜λŠ” μΆ•μ œμ˜ ν”„λ‘œν•„(JSON)을 μž…λ ₯λ°›μ•„ LLM이 **SWOT 뢄석 / μ£Όμš” νŠΉμ§• μš”μ•½**을 μˆ˜ν–‰ν•©λ‹ˆλ‹€. ```mermaid graph TD %% ======================== %% Orchestrator μš”μ²­ %% ======================== subgraph SG_Orchestrator_Req_Analyze ["🧠 Orchestrator μš”μ²­"] Agent["πŸ€– AgentExecutor"] -- "κ°€κ²Œ/μΆ•μ œ 뢄석 μš”μ²­" --> Tool_Analyze["🧩 Tool: analyze_merchant_profile / analyze_festival_profile"] end %% ======================== %% LLM 뢄석 %% ======================== subgraph SG_LLM_Analysis ["πŸ“Š LLM 뢄석 (tools/profile_analyzer.py)"] Tool_Analyze -- "ν”„λ‘œν•„(JSON) 전달" --> LLM_Analyze["πŸ€– LLM (SWOT / μš”μ•½ 뢄석)"] end %% ======================== %% κ²°κ³Ό λ°˜ν™˜ %% ======================== subgraph SG_Result_Return_Analyze ["πŸ“¦ κ²°κ³Ό λ°˜ν™˜"] LLM_Analyze -- "뢄석 λ³΄κ³ μ„œ ν…μŠ€νŠΈ" --> Agent end %% ======================== %% μŠ€νƒ€μΌ %% ======================== style Agent fill:#E91E63,color:#fff style Tool_Analyze fill:#03A9F4,color:#fff style LLM_Analyze fill:#BA68C8,color:#fff ``` ------------------------------------------------------------------------ ## πŸ“ 데이터 흐름 상세 1. **초기 μ„€μ • (UI β†’ API β†’ UI)** * `streamlit_app.py` μ‹€ν–‰ μ‹œ `load_data()` ν•¨μˆ˜κ°€ FastAPI μ„œλ²„(`api/server.py`)의 `/merchants` μ—”λ“œν¬μΈνŠΈλ₯Ό ν˜ΈμΆœν•˜μ—¬ 전체 가맹점 λͺ©λ‘(ID, 이름)을 λ°›μ•„μ˜΅λ‹ˆλ‹€. * μ‚¬μš©μžκ°€ Streamlit λ“œλ‘­λ‹€μš΄ λ©”λ‰΄μ—μ„œ μžμ‹ μ˜ κ°€κ²Œλ₯Ό μ„ νƒν•©λ‹ˆλ‹€. * μ„ νƒλœ κ°€κ²Œ ID둜 FastAPI μ„œλ²„μ˜ `/profile` μ—”λ“œν¬μΈνŠΈλ₯Ό ν˜ΈμΆœν•˜μ—¬ ν•΄λ‹Ή κ°€κ²Œμ˜ 상세 ν”„λ‘œν•„(JSON)κ³Ό μƒκΆŒ/μ—…μ’… 평균 데이터λ₯Ό λ°›μ•„μ˜΅λ‹ˆλ‹€. * λ°›μ•„μ˜¨ ν”„λ‘œν•„ λ°μ΄ν„°λŠ” `modules/visualization.py`λ₯Ό 톡해 κ·Έλž˜ν”„μ™€ ν‘œλ‘œ μ‹œκ°ν™”λ˜μ–΄ μ‚¬μš©μžμ—κ²Œ 보여지고, `st.session_state.profile_data`에 μ €μž₯λ©λ‹ˆλ‹€. 2. **μ»¨μ„€νŒ… μš”μ²­ (UI β†’ Orchestrator)** * μ‚¬μš©μžκ°€ Streamlit μ±„νŒ… μž…λ ₯창에 μ§ˆλ¬Έμ„ μž…λ ₯ν•©λ‹ˆλ‹€. * `streamlit_app.py`λŠ” `orchestrator.invoke_agent()` ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•©λ‹ˆλ‹€. * μ΄λ•Œ **μ‚¬μš©μž 질문(Query)**, **μ±„νŒ…μš©μœΌλ‘œ κ°€κ³΅λœ κ°€κ²Œ ν”„λ‘œν•„(JSON λ¬Έμžμ—΄)**, **이전 λŒ€ν™” 기둝(History)**, **λ§ˆμ§€λ§‰ μΆ”μ²œ μΆ•μ œ λͺ©λ‘(선택적)**이 `Orchestrator`둜 μ „λ‹¬λ©λ‹ˆλ‹€. 3. **μ˜λ„ 뢄석 및 도ꡬ λΌμš°νŒ… (Orchestrator β†’ LLM β†’ Tool)** * `orchestrator.py`의 `AgentExecutor`λŠ” μ‹œμŠ€ν…œ ν”„λ‘¬ν”„νŠΈμ™€ μ „λ‹¬λœ μ»¨ν…μŠ€νŠΈ(κ°€κ²Œ ν”„λ‘œν•„, 질문 λ“±)λ₯Ό μ‘°ν•©ν•˜μ—¬ **첫 번째 LLM(도ꡬ μ„ νƒμš©)**을 ν˜ΈμΆœν•©λ‹ˆλ‹€. * LLM은 질문의 μ˜λ„λ₯Ό λΆ„μ„ν•˜κ³ , μ‹œμŠ€ν…œ ν”„λ‘¬ν”„νŠΈμ˜ κ°€μ΄λ“œλΌμΈμ— 따라 `tools/tool_loader.py`에 μ •μ˜λœ **도ꡬ λͺ©λ‘ 쀑 κ°€μž₯ μ ν•©ν•œ 도ꡬλ₯Ό 선택**ν•˜κ³  ν•„μš”ν•œ μž…λ ₯κ°’(Arguments)을 κ²°μ •ν•©λ‹ˆλ‹€. 4. **도ꡬ μ‹€ν–‰ (Tool β†’ Modules/API/VectorDB/LLM)** * μ„ νƒλœ 도ꡬ ν•¨μˆ˜(`tools/*.py`)κ°€ μ‹€ν–‰λ©λ‹ˆλ‹€. * λ„κ΅¬λŠ” ν•„μš”μ— 따라 `modules/*.py`의 핡심 둜직(예: `FestivalRecommender`), μ™ΈλΆ€ API(날씨 λ“±), VectorDB(`modules/knowledge_base.py` 경유), λ˜λŠ” λ³„λ„μ˜ LLM(`modules/llm_provider.py` 경유)을 ν˜ΈμΆœν•˜μ—¬ μž‘μ—…μ„ μˆ˜ν–‰ν•©λ‹ˆλ‹€. 5. **κ²°κ³Ό μ·¨ν•© 및 반볡 (Tool β†’ Orchestrator β†’ LLM β†’ Tool ...)** * 도ꡬ μ‹€ν–‰ κ²°κ³Ό(Observation)λŠ” λ‹€μ‹œ `AgentExecutor`둜 λ°˜ν™˜λ©λ‹ˆλ‹€. * μ—μ΄μ „νŠΈλŠ” 이 κ²°κ³Όλ₯Ό λ°”νƒ•μœΌλ‘œ **λ‹€μŒ 행동을 κ²°μ •**ν•©λ‹ˆλ‹€. (예: μΆ”κ°€ 정보가 ν•„μš”ν•˜λ©΄ λ‹€λ₯Έ 도ꡬλ₯Ό ν˜ΈμΆœν•˜κ±°λ‚˜, λͺ¨λ“  정보가 λͺ¨μ˜€λ‹€κ³  νŒλ‹¨λ˜λ©΄ μ΅œμ’… λ‹΅λ³€ 생성을 μ€€λΉ„) * 이 "LLM νŒλ‹¨ β†’ 도ꡬ 호좜 β†’ κ²°κ³Ό 확인" 과정은 μ‚¬μš©μžμ˜ μš”μ²­μ΄ μ™„μ „νžˆ 해결될 λ•ŒκΉŒμ§€ **μ—¬λŸ¬ 번 반볡**될 수 μžˆμŠ΅λ‹ˆλ‹€ (Agentic νŠΉμ„±). 6. **μ΅œμ’… λ‹΅λ³€ 생성 및 좜λ ₯ (Orchestrator β†’ LLM β†’ UI)** * `AgentExecutor`κ°€ μ΅œμ’…μ μœΌλ‘œ λ„μΆœν•œ κ²°κ³Ό(`response['output']`) λ˜λŠ” ν•„μš” μ‹œ `orchestrator.py`κ°€ 직접 **두 번째 LLM(λ‹΅λ³€ μƒμ„±μš©)**을 ν˜ΈμΆœν•˜μ—¬, λͺ¨λ“  쀑간 결과와 μ»¨ν…μŠ€νŠΈλ₯Ό μ’…ν•©ν•œ **μ΅œμ’… μ»¨μ„€νŒ… λ³΄κ³ μ„œ(μžμ—°μ–΄)**λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€. * μƒμ„±λœ λ³΄κ³ μ„œλŠ” `streamlit_app.py`둜 λ°˜ν™˜λ˜μ–΄ μ‚¬μš©μž 화면에 좜λ ₯λ©λ‹ˆλ‹€. --- ## βš™οΈ μ£Όμš” νŠΉμ§• μš”μ•½ | κΈ°λŠ₯ | μ„€λͺ… | | :--------------------- | :------------------------------------------------------------------------------------------- | | **Agentic RAG** | LLM μ—μ΄μ „νŠΈκ°€ κ°€κ²Œ ν”„λ‘œν•„ μ»¨ν…μŠ€νŠΈλ₯Ό λ°”νƒ•μœΌλ‘œ 슀슀둜 도ꡬλ₯Ό μ„ νƒν•˜κ³ , λ™μ μœΌλ‘œ RAG 검색 쿼리λ₯Ό μƒμ„±ν•˜μ—¬ μ‹€ν–‰ | | **Tool Calling Agent** | LangChain의 `create_tool_calling_agent`λ₯Ό μ‚¬μš©ν•˜μ—¬ μ—¬λŸ¬ 도ꡬλ₯Ό 자율적으둜 호좜 및 연계 | | **ν•˜μ΄λΈŒλ¦¬λ“œ μΆ”μ²œ** | FAISS 벑터 검색(μœ μ‚¬λ„) + LLM 동적 평가(λ§žμΆ€μ„±) 점수λ₯Ό κ²°ν•©ν•˜μ—¬ μΆ•μ œ μΆ”μ²œ 정확도 ν–₯상 | | **μ»¨ν…μŠ€νŠΈ 기반 뢄석** | λͺ¨λ“  도ꡬ 호좜 및 μ΅œμ’… λ‹΅λ³€ 생성 μ‹œ, ν˜„μž¬ 뢄석 쀑인 κ°€κ²Œμ˜ ν”„λ‘œν•„(JSON)을 핡심 μ»¨ν…μŠ€νŠΈλ‘œ ν™œμš© | | **λͺ¨λ“ˆν™”λœ ꡬ쑰** | κΈ°λŠ₯별(UI, API, Orchestrator, Modules, Tools)둜 μ½”λ“œλ₯Ό λΆ„λ¦¬ν•˜μ—¬ μœ μ§€λ³΄μˆ˜μ„± 및 ν™•μž₯μ„± μ¦λŒ€ | | **데이터 캐싱** | Streamlit의 `@st.cache_data` / `@st.cache_resource`λ₯Ό ν™œμš©ν•˜μ—¬ 데이터 및 λͺ¨λΈ λ‘œλ”© 속도 μ΅œμ ν™” | --- ## πŸ’‘ 기술 μŠ€νƒ * **Frontend:** Streamlit * **Backend (Data API):** FastAPI * **LLM:** Google Gemini 2.5 Flash (`gemini-2.5-flash`) * **AI Framework:** LangChain (Agents, Tool Calling, Prompts) * **VectorStore:** FAISS (Facebook AI Similarity Search) * **Embedding model:** HuggingFace `dragonkue/BGE-m3-ko` (ν•œκ΅­μ–΄ νŠΉν™” λͺ¨λΈ) * **Data Handling:** Pandas, NumPy * **Visualization:** Matplotlib --- ## πŸš€ μ‹€ν–‰ 방법 ### 1️⃣ 사전 μ€€λΉ„ * Python 3.11 이상 μ„€μΉ˜ * `uv` (Python νŒ¨ν‚€μ§€ μ„€μΉ˜ 도ꡬ) μ„€μΉ˜ (`pip install uv`) * Google API Key λ°œκΈ‰ (Gemini λͺ¨λΈ μ‚¬μš©) ### 2️⃣ FastAPI μ„œλ²„ μ‹€ν–‰ FastAPI μ„œλ²„λŠ” 가맹점 데이터(`final_df.csv`)λ₯Ό λ‘œλ“œν•˜κ³ , `/profile` (κ°€κ²Œ 상세 정보), `/merchants` (κ°€κ²Œ λͺ©λ‘) μ—”λ“œν¬μΈνŠΈλ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€. ```bash # 1. ν”„λ‘œμ νŠΈ 루트 ν΄λ”λ‘œ 이동 cd C:(λ‹€μš΄λ°›μ€ 폴더 μœ„μΉ˜) # 2. κ°€μƒν™˜κ²½ 생성 및 ν™œμ„±ν™” (졜초 1회) uv venv # 3. κ°€μƒν™˜κ²½ ν™œμ„±ν™” (Windows) .\.venv\Scripts\activate.bat # (macOS/Linux: source .venv/bin/activate) # 4. ν•„μš”ν•œ 라이브러리 μ„€μΉ˜ uv pip install -r requirements.txt # 5. FastAPI μ„œλ²„ μ‹€ν–‰ (api ν΄λ”μ˜ server.pyλ₯Ό λͺ¨λ“ˆλ‘œ μ‹€ν–‰) python -m api.server ### 3️⃣ Streamlit μ•± μ‹€ν–‰ Streamlit 앱은 μ‚¬μš©μž μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ œκ³΅ν•˜κ³ , FastAPI μ„œλ²„μ—μ„œ 데이터λ₯Ό κ°€μ Έμ˜€λ©°, `Orchestrator`λ₯Ό 톡해 AI μ»¨μ„€νŒ…μ„ μˆ˜ν–‰ν•©λ‹ˆλ‹€. ```bash # 1. (FastAPI μ„œλ²„μ™€ λ‹€λ₯Έ ν„°λ―Έλ„μ—μ„œ) ν”„λ‘œμ νŠΈ 루트 ν΄λ”λ‘œ 이동 cd C:\(λ‹€μš΄λ°›μ€ 폴더 μœ„μΉ˜) # 2. κ°€μƒν™˜κ²½ ν™œμ„±ν™” (Windows) .\.venv\Scripts\activate.bat # (macOS/Linux: source .venv/bin/activate) # 3. Streamlit secrets 파일 생성 (졜초 1회) # - .streamlit 폴더λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€. mkdir .streamlit # μ•„λž˜ λͺ…λ Ήμ–΄μ˜ "(λ°œκΈ‰λ°›μ€ gemini API key)" 뢀뢄을 μ‹€μ œ ν‚€λ‘œ λŒ€μ²΄ν•˜μ„Έμš”. echo GOOGLE_API_KEY="(λ°œκΈ‰λ°›μ€ gemini API key)" > .streamlit\secrets.toml # 4. Streamlit μ•± μ‹€ν–‰ uv run streamlit run streamlit_app.py ``` 이제 μ›Ή λΈŒλΌμš°μ €μ—μ„œ Streamlit μ•± μ£Όμ†Œ(보톡 http://localhost:8501)둜 μ ‘μ†ν•˜μ—¬ MarketSyncλ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. ------------------------------------------------------------------------ ## πŸ“ˆ μ˜ˆμ‹œ μ‹œλ‚˜λ¦¬μ˜€ | μ‚¬μš©μž μž…λ ₯ | μ£Όμš” μ‹€ν–‰ 도ꡬ | μ˜ˆμƒ κ²°κ³Ό | | :---------------------------------- | :------------------------------------------------------ | :-------------------------------------- | | "우리 κ°€κ²Œ λΆ„μ„ν•΄μ€˜" | `analyze_merchant_profile` | κ°€κ²Œ SWOT 뢄석 및 핡심 고객 리포트 | | "주말 방문객 늘릴 λ§Œν•œ μΆ•μ œ μΆ”μ²œν•΄μ€˜" | `recommend_festivals` | Top 3 맞좀 μΆ•μ œ μΆ”μ²œ 리슀트 | | "`μ„œμšΈλ””μ €νŠΈνŽ˜μ–΄` λ§ˆμΌ€νŒ… μ „λž΅ μ•Œλ €μ€˜" | `create_festival_specific_marketing_strategy` | ν•΄λ‹Ή μΆ•μ œ λ§žμΆ€ν˜• λ§ˆμΌ€νŒ… μ „λž΅ μ œμ•ˆ | | "μΆ”μ²œλœ μΆ•μ œλ“€ λ§ˆμΌ€νŒ… 방법 μ•Œλ €μ€˜" | `create_marketing_strategies_for_multiple_festivals` | μ—¬λŸ¬ μΆ•μ œμ— λŒ€ν•œ 톡합 λ§ˆμΌ€νŒ… μ „λž΅ μ œμ•ˆ | | "μš”μ¦˜ λœ¨λŠ” 홍보 방법 μ•Œλ €μ€˜" | `search_contextual_marketing_strategy` (RAG) | κ°€κ²Œ νŠΉμ„± 기반 μ΅œμ‹  λ§ˆμΌ€νŒ… νŠΈλ Œλ“œ/팁 | --- ## 🧠 핡심 아이디어 > "LLM이 슀슀둜 도ꡬλ₯Ό μ„ νƒν•˜κ³  μ‹€ν–‰ν•˜λŠ” **Agentic RAG**" * **LangChain의 Tool-Calling Agent ꡬ쑰**: LLM이 μ‚¬μš©μžμ˜ λ³΅μž‘ν•œ μš”μ²­μ„ μ΄ν•΄ν•˜κ³ , ν•„μš”ν•œ κΈ°λŠ₯(도ꡬ)을 자율적으둜 ν˜ΈμΆœν•˜λ©° μž‘μ—…μ„ μˆ˜ν–‰ν•©λ‹ˆλ‹€. * **μ»¨ν…μŠ€νŠΈ 기반 μ˜μ‚¬κ²°μ •**: κ°€κ²Œ ν”„λ‘œν•„(JSON) 데이터λ₯Ό 핡심 μ»¨ν…μŠ€νŠΈλ‘œ ν™œμš©ν•˜μ—¬, λͺ¨λ“  뢄석과 μΆ”μ²œμ΄ ν˜„μž¬ 뢄석 쀑인 κ°€κ²Œμ— 맞좰 μ΄λ£¨μ–΄μ§‘λ‹ˆλ‹€. * **ν•˜μ΄λΈŒλ¦¬λ“œ μΆ”μ²œ μ—”μ§„**: FAISS 벑터 검색(μœ μ‚¬λ„ 기반)κ³Ό LLM μž¬ν‰κ°€(κ°€κ²Œ λ§žμΆ€μ„± 기반)λ₯Ό κ²°ν•©ν•˜μ—¬ μΆ”μ²œμ˜ μ •ν™•μ„±κ³Ό 관련성을 κ·ΉλŒ€ν™”ν•©λ‹ˆλ‹€. "# MarketSync"