ํ์ต์์ ํ์ด ์ด๋ ฅ๊ณผ ์ค๋ต ํจํด์ ๋ฐํ์ผ๋ก ๋ค์ ๋ฌธ์ ๋ฅผ ์ถ์ฒํ๊ณ , ํ์ต ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํด ๊ฐ์ธํ ๋ฆฌํฌํธ๋ฅผ ์์ฑํ๋ FastAPI ๊ธฐ๋ฐ AI ์๋ฒ์ ๋๋ค.
- ๋ฌธ์ ์ถ์ฒ : ์ฌ์ฉ์ ์ํ์ ํ์ด ์ด๋ ฅ์ ๋ฐํ์ผ๋ก ๋ค์ ๋ฌธ์ ์ถ์ฒ
- ๋ถ์ ๋ฆฌํฌํธ : ์ฃผ๊ฐ ํ์ต ๋ก๊ทธ์ ์ทจ์ฝ ํจํด์ ๋ฐํ์ผ๋ก ์ฑ์ฅ ๋ฆฌํฌํธ ์์ฑ
- ๋๋ง์ ๋ฌธ์ ๋ง๋ค๊ธฐ : ์ ๋ก๋๋ ๋ฌธ์ ์ด๋ฏธ์ง์์ ๋ฌธ์ ๋ฅผ ์ถ์ถํ๊ณ ์์ฝ์นด๋/ํด์ฆ ์์ฑ
ย
.
โโโ app # ์ ํ๋ฆฌ์ผ์ด์
๋ฉ์ธ ์์ค
โ โโโ main.py
โ โโโ core # ์ ์ญ ์ค์ /ํ๊ฒฝ๋ณ์ ๊ด๋ฆฌ
โ โ โโโ config.py
โ โโโ common # ๊ณตํต ์๋ต/์์ธ ์ฒ๋ฆฌ
โ โ โโโ api_response.py
โ โ โโโ exceptions # ์ปค์คํ
์์ธ ๋ฐ ์์ธ ํธ๋ค๋ฌ
โ โ โ โโโ base_exception.py
โ โ โ โโโ custom_exception.py
โ โ โ โโโ exception_handler.py
โ โ โโโ observability # ๋ก๊น
/๋ฉํธ๋ฆญ/ํธ๋ ์ด์ฑ
โ โ โโโ logging_config.py
โ โ โโโ metrics.py
โ โ โโโ tracing.py
โ โโโ domain # ๋น์ฆ๋์ค ๋๋ฉ์ธ ๋ก์ง
โ โ โโโ recommend # ๋ฌธ์ ์ถ์ฒ ๋๋ฉ์ธ
โ โ โ โโโ recommend_router.py # ์ถ์ฒ API ๋ผ์ฐํฐ
โ โ โ โโโ recommendation_schemas.py # ์ถ์ฒ ์์ฒญ/์๋ต ์คํค๋ง
โ โ โ โโโ recommend_usecase.py # ์ถ์ฒ ํ๋ฆ ์ค์ผ์คํธ๋ ์ด์
โ โ โ โโโ recommend_service.py # ์ ์ /ํ์
์ถ์ฒ ๊ณ์ฐ
โ โ โ โโโ recommend_llm_service.py # ์ถ์ฒ ์ฌ์ LLM ์์ฑ
โ โ โโโ report # ๋ถ์ ๋ฆฌํฌํธ ๋๋ฉ์ธ
โ โ | โโโ report_router.py # ๋ฆฌํฌํธ API ๋ผ์ฐํฐ
โ โ | โโโ report_schemas.py # ๋ฆฌํฌํธ ์์ฒญ/์๋ต ์คํค๋ง
โ โ | โโโ report_service.py # ์งํ ๊ณ์ฐ/๋ฆฌํฌํธ ์กฐ๋ฆฝ
โ โ | โโโ report_rag_service.py # RAG ๊ทผ๊ฑฐ ์กฐํ
โ โ | โโโ report_llm_service.py # ๋ฆฌํฌํธ ๋ฌธ๊ตฌ LLM ์์ฑ
โ โ โโโ workbook # ์ํฌ๋ถ OCR/์ฝํ
์ธ ์์ฑ ๋๋ฉ์ธ
โ โ โโโ workbook_service.py
โ โ โโโ workbook_llm_service.py
โ โ โโโ workbook_prompts.py
โ โ โโโ workbook_schemas.py
โ โโโ database # DB ํด๋ผ์ด์ธํธ/๋ฐ์ดํฐ์
โ โ โโโ vector_db.py
โ โ โโโ problem_dataset # ๋ฌธ์ ๋ฉํ/๊ฐ์ด๋ ์์ฒ ๋ฐ์ดํฐ
โ โ โโโ algo_concepts # ๋ฆฌํฌํธ RAG ๊ทผ๊ฑฐ ๋ฐ์ดํฐ
โ โ โโโ user_dataset # ํ์
์ถ์ฒ์ฉ ์ ์ ๋ฉ๋ชจ๋ฆฌ ๋ฐ์ดํฐ
โ โโโ services # ๊ณต์ฉ ์๋น์ค ๋ ์ด์ด
โ โ โโโ embedding_service.py
โ โโโ queue
โ โ โโโ constants.py # ํ/์ต์ค์ฒด์ธ์ง ์ด๋ฆ ์ ์
โ โ โโโ rabbitmq.py # RabbitMQ ์ฐ๊ฒฐ ๊ด๋ฆฌ
โ โโโ workers # ๋น๋๊ธฐ ์์
์๋น์
โ โโโ ai_worker.py # ์ถ์ฒ/๋ฆฌํฌํธ ๋น๋๊ธฐ ์์ปค
โ โโโ ocr_worker.py # ์ํฌ๋ถ OCR ๋น๋๊ธฐ ์์ปค
โโโ scripts # ์ด๊ธฐ ๋ฐ์ดํฐ ์ ์ฌ/์
์
์คํฌ๋ฆฝํธ
โ โโโ load_problem_dataset.py
โ โโโ load_algo_dataset.py
โ โโโ load_user_dataset.py
โ โโโ run_api_and_worker.sh # API + worker ๋์ ์คํ
โ โโโ monitoring
โ โโโ start_analysis_exporters.sh # analysis ์๋ฒ exporter ์คํ
โ โโโ stop_analysis_exporters.sh # analysis ์๋ฒ exporter ์ค์ง
โโโ monitoring # Prometheus/Grafana/Loki/Tempo/Alertmanager ๊ตฌ์ฑ
โ โโโ docker-compose.monitoring.yml
โ โโโ analysis-exporters.compose.yml
โ โโโ prometheus
โ โโโ alertmanager
โ โโโ loki
โ โโโ tempo
โ โโโ deploy-scripts
โโโ codedeploy # CodeDeploy ๋ฐฐํฌ ์คํฌ๋ฆฝํธ
โโโ docker-compose.yml # API ์ปจํ
์ด๋ ์คํ ์ ์
โโโ Dockerfile # API ์ด๋ฏธ์ง ๋น๋ ์ ์
โโโ pyproject.toml
โโโ requirements.txt # ํ์ด์ฌ ์์กด์ฑ ๋ชฉ๋ก
โโโ README.md
ย
๋ฌธ์ ์ถ์ฒ/ ๋ถ์ ๋ฆฌํฌํธ๋ HTTP ๋ผ์ฐํฐ๊ฐ ๋ ธ์ถ ๋์ด์์ง๋ง RabbitMQ ๊ธฐ๋ฐ ๋น๋๊ธฐ ์์ปค ํ์ดํ๋ผ์ธ์ผ๋ก ๋์
- ์ฌ์ฉ์ ๋ ๋ฒจ, ์๋๋ฆฌ์ค, ์ด๋ฏธ ํผ ๋ฌธ์ ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ฌธ์ ๋ฅผ ์ถ์ฒ
- ์ถ์ฒ ๊ฒฐ๊ณผ์๋ ๋จ์ ๋ฌธ์ ID๋ง์ด ์๋๋ผ ์ ์ด ๋ฌธ์ ๋ฅผ ์ง๊ธ ํ์ด์ผํ๋์ง์ ๋ํ ์ค๋ช ํฌํจ
์ถ์ฒ ํ๋ฆ ์์ฝ:
NEW์๋๋ฆฌ์ค: ๋ ๋ฒจ๋ณ ์ ์ ์ถ์ฒ ํ์์ 5๊ฐ ์ถ์ฒDAILY,ON_DEMAND: QdrantUser_memories๊ธฐ๋ฐ ํ์ ์ถ์ฒ- ํ์ ์ถ์ฒ ๊ฒฐ๊ณผ๊ฐ 5๊ฐ ๋ฏธ๋ง์ด๋ฉด ์ ์ ์ถ์ฒ์ผ๋ก ๋ถ์กฑ๋ถ ๋ณด์
- ๊ฐ ๋ฌธ์ ์ ๋ํด LLM์ผ๋ก
reason_msg์์ฑ
- ์ฃผ๊ฐ ํ์ต ๋ก๊ทธ์ ์ ๋ต/์ค๋ต ํต๊ณ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ฑ์ฅ ๋ฆฌํฌํธ๋ฅผ ์์ฑ
- ๋ฆฌํฌํธ๋ 'ํ์ฌ ํ์ต ์ํ ์์ฝ', '์ต๊ทผ ์ทจ์ฝ ์ง์ ๋ถ์', '์ฑ์ฅ ํฌ์ธํธ ์ง๋จ', '๋ค์ ํ์ต ๋ฐฉํฅ ์ ์'๊ณผ ๊ฐ์ ๋ด์ฉ ํฌํจ
๋ฆฌํฌํธ ํ๋ฆ ์์ฝ:
solved_problems_weekly < 3์ด๋ฉดWARM_UP- ์ ํ๋/๋ ๋ฆฝ์ฑ/ํจ์จ์ฑ/์ผ๊ด์ฑ ์งํ ๊ณ์ฐ
- ์ทจ์ฝ ํญ๋ชฉ์ ๋ง๋ ๊ทผ๊ฑฐ ๋ฌธ์๋ฅผ RAG๋ก ์กฐํ
- ๊ทผ๊ฑฐ + ์งํ๋ฅผ LLM์ ์ ๋ฌํด ์ต์ข ๋ฆฌํฌํธ ๋ฌธ๊ตฌ ์์ฑ
- ์ด๋ฏธ์ง URL ๋ชฉ๋ก์ ์ ๋ ฅ์ผ๋ก ์์
- vLM์ผ๋ก ์ด๋ฏธ์ง์์ ์๋ฌธ ํ ์คํธ ์ถ์ถ
- ์ฝ๋ฉํ ์คํธ ๋ฌธ์ ์ฌ๋ถ ํ๋จ ๋ฐ ๋ฌธ์ ๋ณธ๋ฌธ ๊ตฌ์กฐํ
- Gemini ๊ธฐ๋ฐ์ผ๋ก ์์ฝ ์นด๋์ ํด์ฆ ์์ฑ
- ๊ฒฐ๊ณผ๋ฅผ MQ ์๋ต ๋ฉ์์ง๋ก ๋ฐํ
- RabbitMQ ์์ฒญ ํ๋ฅผ ์๋นํด ์ถ์ฒ/๋ฆฌํฌํธ/OCR์ ๋น๋๊ธฐ๋ก ์ฒ๋ฆฌํฉ๋๋ค.
- ์์ฒญ ํ :
recommend.request.q,report.request.q,custom.problem.request - ์๋ต ํ :
recommend.response.q,report.response.q,custom.problem.response custom.problem.exchange
ย
- Backend :
FastAPI,Uvicorn - Queue :
RabbitMQ,aio-pika - Vector DB :
Qdrant - Embedding :
BAAI/bge-m3(FlagEmbedding) - LLM :
- ์ถ์ฒ/๋ฆฌํฌํธ :
Qwen-2.5-32B-Instruct - OCR :
Qwen2.5-VL-7B-Instruct - ์ํฌ๋ถ ์นด๋/ํด์ฆ ์์ฑ :
gemini-2.0-flash
- ์ถ์ฒ/๋ฆฌํฌํธ :
- Observability :
Prometheus,Grafana,Alertmanager,Loki,Tempo,OpenTelemetry
ย
- Python
3.12 - Qdrant, RabbitMQ, ์ถ์ฒ/๋ฆฌํฌํธ์ฉ LLM endpoint, OCR์ฉ Vision LLM endpoint, Gemini API Key
ํ ์คํธ์ฉ์ผ๋ก ๋น ๋ฅด๊ฒ ๋์ธ ๋:
# Qdrant (์ฑ ๊ธฐ๋ณธ ํฌํธ 6444์ ๋ง์ถฐ ๋งคํ)
docker run -d --name qdrant -p 6444:6333 -v "$(pwd)/qdrant_storage:/qdrant/storage" qdrant/qdrant
# RabbitMQ
docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-managementpython3.12 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt.env.template ์ฐธ๊ณ
๋ฐ์ดํฐ์ ์ ๋ณ๋๋ก ํ์
python -m scripts.load_problem_dataset
python -m scripts.load_algo_dataset
python -m scripts.load_user_datasetuvicorn app.main:app --host 0.0.0.0 --port 8000 --reloadpython -m app.workers.ai_worker
python -m app.workers.ocr_workerํ ๋ฒ์ ์คํ
sh scripts/run_api_and_worker.shGET /: ์๋ฒ ์ํGET /health/db: qdrant ์๋ฒ ์ฐ๊ฒฐ ์ํ
docker compose up --buildย
๊ธฐ๋ณธ ์๋ํฌ์ธํธ
GET /: ์๋ฒ ์ํ ํ์ธGET /health/db: Qdrant ์ฐ๊ฒฐ ์ํ ํ์ธGET /metrics: Prometheus ๋ฉํธ๋ฆญ ์์ง ์๋ํฌ์ธํธ
๊ณตํต ์๋ต ํฌ๋งท:
{
"code": "SUCCESS",
"message": "OK",
"data": {}
}POST /api/v2/recommend
์์ฒญ ์์:
{
"user_id": 1,
"user_level": "newbie",
"scenario": "NEW",
"filter_info": {
"solved_problem_ids": [1, 2],
"challenge_problem_ids": [3]
}
}์๋ต ์์:
{
"code": "SUCCESS",
"message": "OK",
"data": {
"user_id": 1,
"scenario": "NEW",
"recommendations": [
{
"problem_id": 22,
"reason_msg": "..."
}
]
}
}์ฃผ์:
scenario=NEW๋solved_problem_ids๊ฐ์ 3 ๋ฏธ๋ง์ผ ๋๋ง ํ์ฉ๋ฉ๋๋ค.
POST /api/v2/reports
์์ฒญ ์์:
{
"user_id": 1,
"user_level": "newbie",
"analysis_period": {
"start_date": "2026-03-01",
"end_date": "2026-03-07"
},
"raw_metrics": {
"chatbot_msg_history": [],
"total_chatbot_requests": 5,
"solve_duration_sec": 1800,
"solved_problems_weekly": 4
},
"paragraph_fail_stats": {
"GOAL": 2,
"CONSTRAINT": 1
},
"quiz_fail_stats": {
"TIME_COMPLEXITY": 2
}
}์์ฒญ ์์:
{
"customProblemId": 123,
"images": [
{
"order": 1,
"url": "https://example.com/problem-page-1.png"
},
{
"order": 2,
"url": "https://example.com/problem-page-2.png"
}
]
}์๋ต ์์:
{
"customProblemId": 123,
"response": {
"code": "SUCCESS",
"message": "๋ฌธ์ ๋ถ์์ด ์๋ฃ๋์์ต๋๋ค.",
"data": {
"problem_detail": {
"title": "๋ฌธ์ ์ ๋ชฉ",
"content": "## ๋ฌธ์ \n..."
},
"summary_card": [],
"quiz": []
}
}
}<๊ตฌ์ฑ ๋๋ ํฐ๋ฆฌ>
monitoring/: ๋ชจ๋ํฐ๋ง ์๋ฒ์ฉ compose ๋ฐ ์ค์ scripts/monitoring/: analysis ์๋ฒ exporter ์คํ/์ค์ง ์คํฌ๋ฆฝํธcodedeploy/monitoring/: ๋ฐฐํฌ ๋ฒ๋ค์ฉ ๋ชจ๋ํฐ๋ง ์ค์
๋ก์ปฌ์์ exporter ์คํ
./scripts/monitoring/start_analysis_exporters.shGPU ์๋ฒ๋ผ๋ฉด
./scripts/monitoring/start_analysis_exporters.sh --gpu์ค์ง
./scripts/monitoring/stop_analysis_exporters.sh- ์ถ์ฒ/๋ฆฌํฌํธ๋ FastAPI API๋ก ๋ ธ์ถ๋์ด ์์
- workbook ๊ธฐ๋ฅ์ ํ์ฌ ocr_worker ์ค์ฌ์ ๋น๋๊ธฐ ํ์ดํ๋ผ์ธ์ผ๋ก๋ง ๊ตฌํ๋์ด ์์
- main.py์ workbook ๋ผ์ฐํฐ ์ฐ๊ฒฐ ํ์ ์ ์์ง๋ง ํ์ฑํ๋์ด ์์ง๋ ์์