LearnAIλ Model Control Protocol(MCP)μ νμ©νμ¬ μ¬μ©μμ κ΄μ¬ μ£Όμ μ λ§μΆ€ν νμ΅ μ»€λ¦¬νλΌμ μ 곡νκ³ , μΌλ³ νμ΅ κ³νμ κ΄λ¦¬νλ©°, AI λ©ν μν μ μννλ κ°μΈν νμ΅ μ§μ μμ€ν μ λλ€.
- μ¬μ©μλ³ λ§μΆ€ν νμ΅ μ»€λ¦¬νλΌ μμ±
- μΌλ³ νμ΅ κ³ν λ° μ§λ κ΄λ¦¬
- μ€μκ° AI λ©ν λ§ λ° νμ΅ μλ΄
- νμ΅ κΈ°λ‘ μΆμ λ° λΆμ
-
MCP Agent μμ€ν
- MCP μλ²μ LangGraph μμ΄μ νΈ ν΅ν©
- λͺ¨λνλ μμ΄μ νΈ κ΄λ¦¬ (
agent.py) - λμ μλ² μ ν κΈ°λ₯
-
μΉ κΈ°λ° μ±ν μΈν°νμ΄μ€
- FastAPI κΈ°λ° λ°±μλ API
- HTML/CSS/JavaScript νλ‘ νΈμλ
- μ€μκ° μ±ν κΈ°λ₯
-
κΈ°λ³Έ μΈνλΌ
- λ‘컬 λ° λ€νΈμν¬ μ κ·Ό μ§μ
- ν νλ¦Ώ κΈ°λ° UI ꡬ쑰
- λͺ¨λνλ μ½λ μν€ν μ²
- FastAPI: μΉ νλ μμν¬ λ° API μλ²
- Python 3.11: λ©μΈ κ°λ° μΈμ΄
- MCP (Model Control Protocol): AI μμ΄μ νΈ ν΅μ
- LangGraph: AI μν¬νλ‘μ° κ΄λ¦¬
- LangChain: AI μ ν리μΌμ΄μ νλ μμν¬
- HTML5/CSS3: κΈ°λ³Έ μΉ κ΅¬μ‘° λ° μ€νμΌλ§
- Vanilla JavaScript: ν΄λΌμ΄μΈνΈ μ¬μ΄λ λ‘μ§
- Jinja2: μλ²μ¬μ΄λ ν νλ¦Ώ μμ§
- Ollama: λ‘컬 LLM μ€ν νκ²½
- midm-2.0-base-q8: λ©μΈ μΈμ΄ λͺ¨λΈ
- ChatOpenAI: OpenAI API νΈν μΈν°νμ΄μ€
μ¬μ©μκ° μ²μ LearnAIμ μ μνλ©΄ AI μμ΄μ νΈμμ λνλ₯Ό ν΅ν΄ λ€μ μ 보λ₯Ό μμ§ν©λλ€:
- νμ΅ λͺ©ν: 무μμ λ°°μ°κ³ μΆμμ§, μ λ°°μ°λ €κ³ νλμ§
- νμ΅ μ μ½μ‘°κ±΄: μκ°, μμ°, νκ²½μ μ μ½
- μ΅μ’ λͺ©ν: ꡬ체μ μ΄κ³ μΈ‘μ κ°λ₯ν νμ΅ λͺ©ν μ€μ
1λ¨κ³μμ μμ§λ μ 보λ₯Ό λ°νμΌλ‘ κ°μΈνλ νμ΅ λ‘λλ§΅μ μμ±ν©λλ€.
νμ΅ μ§ν μν©μ λͺ¨λν°λ§νκ³ νμμ λ°λΌ κ³νμ μ‘°μ ν©λλ€.
learnai/
βββ main.py # FastAPI λ©μΈ μ ν리μΌμ΄μ
βββ agent.py # MCP μμ΄μ νΈ λͺ¨λ
βββ utils.py # κ°λ°/λλ²κΉ
μ νΈλ¦¬ν°
βββ templates/
β βββ index.html # λ©μΈ μ±ν
UI
βββ servers/ # MCP μλ²λ€
β βββ user_assessment.py # μ¬μ©μ μ§λ¨ μλ² (νμ¬: λ μ¨ λ°λͺ¨)
β βββ generate_curriculum.py # 컀리νλΌ μμ± μλ² (κ°λ° μμ )
β βββ evaluate_user.py # μ¬μ©μ νκ° μλ² (κ°λ° μμ )
βββ agent.ipynb # νλ‘ν νμ΄ν λ
ΈνΈλΆ
pip install fastapi uvicorn jinja2 python-multipart aiofiles
pip install langchain langchain-openai langgraph mcp langchain-mcp-adaptersollama serve
ollama pull midm-2.0-base-q8 # λͺ¨λΈ λ€μ΄λ‘λ (νμμ)python main.py- λ‘컬: http://127.0.0.1:8000
- λ€νΈμν¬: http://[νμλ_IP]:8000
GET /: λ©μΈ μ±ν UIPOST /chat: μ±ν λ©μμ§ μ²λ¦¬GET /docs: API λ¬Έμ (Swagger UI)
- PostgreSQL/SQLite λ°μ΄ν°λ² μ΄μ€ μ°λ
- μ¬μ©μ μΈμ¦ λ° νμκ°μ μμ€ν
- μΈμ κ΄λ¦¬ λ° λν κΈ°λ‘ μ μ₯
- μ¬μ©μ νλ‘ν κ΄λ¦¬
- μ¬μ©μ μ§λ¨ MCP μλ² (
user_assessment.py) - μ¬μ©μ νμ΅ μμ€ νκ° MCP μλ² (
evaluate_user.py) - λ§μΆ€ν 컀리νλΌ μμ± MCP μλ² (
generate_curriculum.py) - μΌλ³ νμ΅ κ³ν μμ± λ° κ΄λ¦¬
- νμ΅ μ§λ μΆμ μμ€ν
- λ°μν μΉ λμμΈ
- λμ보λ λ° νμ΅ νν© μκ°ν
- λͺ¨λ°μΌ μΉνμ μΈν°νμ΄μ€
- λ€ν¬λͺ¨λ μ§μ
- μ€μκ° μλ¦Ό μμ€ν
- νμ΅ λΆμ λ° λ¦¬ν¬νΈ
- μμ νμ΅ κΈ°λ₯ (μ€ν°λ κ·Έλ£Ή)
- μΈλΆ νμ΅ μλ£ μ°λ
- Docker 컨ν μ΄λν
- ν΄λΌμ°λ λ°°ν¬ (AWS/GCP/Heroku)
- CI/CD νμ΄νλΌμΈ ꡬμΆ
- λͺ¨λν°λ§ λ° λ‘κΉ μμ€ν
- μ±λ₯ μ΅μ ν λ° μ€μΌμΌλ§
- MCP μλ²λ³ λ 립μ μΈ κΈ°λ₯ ꡬν
- μμ΄μ νΈμ μΉ μλ²μ λͺ νν λΆλ¦¬
- μ¬μ¬μ© κ°λ₯ν μ νΈλ¦¬ν° ν¨μ
- μλ‘μ΄ MCP μλ² μΆκ° μ©μ΄
- μλ² νμ λ³ λμ μ ν μ§μ
- νλ¬κ·ΈμΈ λ°©μμ κΈ°λ₯ νμ₯
- ν« λ¦¬λ‘λ μ§μ (κ°λ° λͺ¨λ)
- API λ¬Έμ μλ μμ±
- νλ‘ν νμ΄νμ μν Jupyter λ ΈνΈλΆ μ§μ
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
MIT License
νλ‘μ νΈ κ΄λ ¨ λ¬Έμμ¬νμ΄λ λ²κ·Έ 리ν¬νΈλ μ΄μ νΈλ컀λ₯Ό μ΄μ©ν΄ μ£ΌμΈμ.
LearnAI System Architecture
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Web Interface (index.html) β
β μ¬μ©μκ° μ±ν
UIλ₯Ό ν΅ν΄ λ©μμ§ μ
λ ₯ β
βββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β POST /chat
βββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββ
β FastAPI Server (main.py) β
β β’ μΉ μλ² μν β
β β’ μ±ν
API μλν¬μΈνΈ μ 곡 β
β β’ ν
νλ¦Ώ λ λλ§ β
βββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β MultiMCPAgent.chat()
βββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββ
β Multi-Agent System (agent.py) β
β β’ μ¬λ¬ MCP μλ²λ₯Ό λμ κ΄λ¦¬ β
β β’ νμ΅ μλ κ°μ§ λ° λΌμ°ν
β
β β’ μΈμ
μν κ΄λ¦¬ β
β β’ Assessment vs General λν λΆκΈ° β
βββββββββββββββββββ¬ββββββββββββββββββ¬ββββββββββββββββββββββββββ
β β
Assessment Mode General Mode
β β
ββββββββββββββββββΌβββββββββββββββββ β
β User Assessment MCP Server β β
β (user_assessment.py) β β
β β β
β β’ Stateful μΈμ
κ΄λ¦¬ β β
β β’ LangGraph Multi-Agent β β
β β’ νμΌ κΈ°λ° μꡬ μ μ₯ β β
β β β
β βββββββββββββββββββββββββββββββ β β
β β LangGraph Workflow β β β
β β ββββββββββββββββββββββββββββ β β
β β β Extraction Agent ββ β β
β β β β’ μ 보 μΆμΆ (μ격) ββ β β
β β β β’ UserInfoSchema νμ© ββ β β
β β ββββββββββββββββββββββββββββ β β
β β β β β β
β β βββββββββββΌβββββββββββββββββββ β β
β β β Response Agent ββ β β
β β β β’ μλ£λ μ²΄ν¬ ββ β β
β β β β’ μ§λ¬Έ μμ± or μλ£ ββ β β
β β β β’ UI μ 리 μ²λ¦¬ ββ β β
β β ββββββββββββββββββββββββββββ β β
β βββββββββββββββββββββββββββββββ β β
βββββββββββββββββββββββββββββββββββ β
β
ββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββ
β General Conversation β
β β’ LangChain ReAct Agent β
β β’ μΌλ° λ©ν λ§ λν β
β β’ λ€λ₯Έ MCP λκ΅¬λ€ νμ© β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Session Management Flow
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Session Storage β
β sessions/ ν΄λ β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β abc123.json β β def456.json β β xyz789.json β ... β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β
β κ° νμΌ κ΅¬μ‘°: β
β { β
β "messages": [...], # λν κΈ°λ‘ β
β "topic": "νμ΄μ¬", # μΆμΆλ νμ΅ μ£Όμ β
β "constraints": "μ΄λ³΄μ, μ£Ό 2μκ°", # μ μ½ μ‘°κ±΄ β
β "goal": "μΉ κ°λ°", # ꡬ체μ λͺ©ν β
β "session_id": "abc123", β
β "completed": false, # νκ° μλ£ μ¬λΆ β
β "current_agent": "response" β
β } β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
User Assessment Workflow
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β μ¬μ©μ μ
λ ₯: "λ νμ΄μ¬ λ°°μ°κ³ μΆμ΄" β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββ
β Step 1: νμ΅ μλ κ°μ§ (_should_use_assessment_tool) β
β β’ ν€μλ λ§€μΉ: "λ°°μ°κ³ μΆμ΄", "곡λΆνκ³ μΆμ΄", "νμ΅" λ± β
β β’ assessment_in_progress μν μ²΄ν¬ β
β β Assessment Flow μ§μ
β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββ
β Step 2: μΈμ
κ΄λ¦¬ β
β β’ κΈ°μ‘΄ μΈμ
볡μ λλ μ μΈμ
μμ± β
β β’ sessions/μΈμ
ID.json νμΌμμ λ‘λ β
β β’ λν κΈ°λ‘μ μ¬μ©μ λ©μμ§ μΆκ° β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββ
β Step 3: LangGraph Workflow μ€ν β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Extraction Agent β β
β β β’ μ격ν μ 보 μΆμΆ (λͺ
μμ μΈκΈλ§) β β
β β β’ "νμ΄μ¬ λ°°μ°κ³ μΆμ΄" β topic: "νμ΄μ¬" β β
β β β’ constraints: "", goal: "" (λΉ κ° μ μ§) β β
β β β’ UserInfoSchemaλ‘ κ΅¬μ‘°ν β β
β βββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββ β
β β Response Agent β β
β β β’ μλ£λ 체ν¬: topic β, constraints β, goal β β β
β β β’ λ―Έμλ£ β λ€μ μ§λ¬Έ μμ± β β
β β β’ "νμ΄μ¬ νμ΅ μ‘°κ±΄μ μλ €μ£ΌμΈμ!" μμ± β β
β β β’ λ§ν¬λ€μ΄ μ κ±°, μΈμ
μ 보 μ¨κΉ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββ
β Step 4: μλ΅ μ²λ¦¬ β
β β’ μΈμ
λ°μ΄ν°λ₯Ό sessions/μΈμ
ID.jsonμ μ μ₯ β
β β’ UIμ© μλ΅ μ 리 (_clean_response_for_ui) β
β β’ μ¬μ©μμκ² λ€μ μ§λ¬Έ λ°ν β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Information Extraction Rules
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β μ
λ ₯: "λ νμ΄μ¬ 곡λΆνκ³ μΆμ΄" β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Extraction Prompt (λ§€μ° μ격ν κΈ°μ€) β β
β β β’ μ¬μ©μκ° μ§μ λ§ν λ¨μ΄λ§ μΆμΆ β β
β β β’ μ λ μΆλ‘ , μ μΆ, ν΄μ κΈμ§ β β
β β β’ μμΌλ©΄ λΉ λ¬Έμμ΄λ‘ μ μ§ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββ β
β β UserInfoSchema ꡬ쑰ν μΆλ ₯ β β
β β topic: "νμ΄μ¬" β λͺ
μμ μΌλ‘ μΈκΈλ¨ β β
β β constraints: "" β μΈκΈλμ§ μμ β β
β β goal: "" β μΈκΈλμ§ μμ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β μλͺ»λ μΆμΆ μμ (νμ§ μμ): β
β topic: "νμ΄μ¬ νμ΅" β β
β constraints: "μκ° μ 보 νμ" β β
β goal: "νλ‘κ·Έλλ°" β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Question Generation Logic
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Current Profile State: β
β topic: "νμ΄μ¬", constraints: "", goal: "" β
βββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββΌββββββββββββββ
β _generate_next_question β
βββββββββββββββ¬ββββββββββββββ
β
ββββββββββββββββββΌβββββββββββββββββ
β Missing Information Check β
βββ¬ββββββββββββββ¬ββββββββββββββββββ
β β
topic μμ constraints μμ
β β
ββββββββΌβββββββ ββββββΌββββββββββββββββββββββ
β "μ΄λ€ λΆμΌλ₯Όβ β "νμ΄μ¬ νμ΅ μ‘°κ±΄μ β
β νμ΅νκ³ β β μλ €μ£ΌμΈμ!" β
β μΆμΌμ κ°μ?"β β β’ νμ¬ μμ€ β
β β β β’ μκ° ν¬μ β
βββββββββββββββ ββββββββββββββββββββββββββββ
β
βββββββββββΌββββββββββββββββββ
β goal μμ β
β "νμ΄μ¬ νμ΅ λͺ©νλ₯Ό β
β μλ €μ£ΌμΈμ!" β
β β’ μ·¨μ
/μ΄μ§ β
β β’ μ
무 νμ© β
β β’ κ°μΈ νλ‘μ νΈ β
β β’ μ·¨λ―Έ/μκΈ°κ³λ° β
βββββββββββββββββββββββββββββ
UI Response Cleaning Process
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Raw Response: β
β π **νμ΄μ¬ νμ΅ λͺ©νλ₯Ό μλ €μ£ΌμΈμ!** β
β β
β **μ΄λ€ λͺ©μ μΌλ‘ νμ΄μ¬μ(λ₯Ό) λ°°μ°μλμ?** β
β - μ·¨μ
μ΄λ μ΄μ§μ μν΄μ β
β - νμ¬ μ
무μ νμ©νλ €κ³ β
β β
β _Session: abc123 | Status: In Progress_ β
βββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ
β _clean_response_for_ui()
βββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββ
β Cleaned Response: β
β π νμ΄μ¬ νμ΅ λͺ©νλ₯Ό μλ €μ£ΌμΈμ! β
β β
β μ΄λ€ λͺ©μ μΌλ‘ νμ΄μ¬μ(λ₯Ό) λ°°μ°μλμ? β
β β’ μ·¨μ
μ΄λ μ΄μ§μ μν΄μ β
β β’ νμ¬ μ
무μ νμ©νλ €κ³ β
β β
β ꡬ체μ μΈ λͺ©νλ₯Ό μλ©΄ λ λ§μΆ€ν λ‘λλ§΅μ μ μν μ μμ΄μ! β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
ββ ** λ§ν¬λ€μ΄ κ΅΅μκΈμ¨ μ κ±°
ββ - 리μ€νΈλ₯Ό β’ λΆλ¦ΏμΌλ‘ λ³κ²½
ββ μΈμ
μ 보 μμ μ κ±°
ββ μ¬λ¬ μ€λ°κΏ μ 리
Completion Status Check
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β _should_continue() ν¨μ β
β β
β topic_complete = bool(state.get("topic")) β True β
β constraints_complete = bool(state.get("constraints")) β False β
β goal_complete = bool(state.get("goal")) β False β
β β
β if all three are True: β
β return "complete" β μλ£ λ©μμ§ μμ± β
β else: β
β return "continue" β λ€μ μ§λ¬Έ μμ± β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
μ€μ λν νλ¦
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β User: "λ νμ΄μ¬ 곡λΆνκ³ μΆμ΄" β
β β Assessment: topic="νμ΄μ¬", constraints="", goal="" β
β β AI: "νμ΄μ¬ νμ΅ μ‘°κ±΄μ μλ €μ£ΌμΈμ! νμ¬ μμ€κ³Ό μκ°..." β
β β
β User: "μμ μ΄λ³΄μκ³ μ£Ό 2μκ° κ°λ₯ν΄" β
β β Assessment: topic="νμ΄μ¬", constraints="μμ μ΄λ³΄μ, μ£Ό 2μκ°", goal="" β
β β AI: "νμ΄μ¬ νμ΅ λͺ©νλ₯Ό μλ €μ£ΌμΈμ! μ·¨μ
, μ
무νμ©..." β
β β
β User: "μ·¨μ
μ€λΉνλ €κ³ " β
β β Assessment: topic="νμ΄μ¬", constraints="μμ μ΄λ³΄μ, μ£Ό 2μκ°", goal="μ·¨μ
" β
β β AI: "π― νμ΅ νλ‘ν λΆμ μλ£! [μλ£ λ©μμ§]" β
β β
β β assessment_in_progress = False μ ν β
β β μ΄ν μΌλ° λ©ν λ§ λͺ¨λλ‘ μ ν β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
μ΄ κ΅¬μ‘°λ₯Ό ν΅ν΄ Stateful Multi-Agent Assessment Systemμ΄ μ¬μ©μμ νμ΅ νλ‘νμ λ¨κ³μ μΌλ‘ μμ§νκ³ , μλ£ νμλ μΌλ° λ©ν λ§ λͺ¨λλ‘ μμ°μ€λ½κ² μ νλ©λλ€.