Edu-Sync AI — KDT 교육 운영을 위한 멀티에이전트 AI 시스템 개발기
FastAPI + React + GPT-4o-mini + FAISS 기반, 4개 역할(수강생·멘토·조교·관리자)을 하나의 AI 챗봇으로 통합한 프로젝트의 기획부터 완성까지.
1. 프로젝트 배경 — 왜 만들었는가
1-1. KDT 현장의 문제점
K-디지털 트레이닝(KDT) 국비지원 교육 과정을 운영하면서 반복적으로 마주치는 문제들이 있었다.
수강생 입장:
- 행정 관련 질문(출결, 수료 조건, NCS 기준 등)을 물어볼 곳이 분산되어 있다
- 24시간 질문이 필요한데, 업무 시간 외에는 답변을 받기 어렵다
- 조교 예약을 수동으로 잡아야 한다 (카카오톡 DM, 전화 등)
- 학습 자료가 여기저기 흩어져 있다
멘토 입장:
- 수강생 개개인의 학습 이력을 추적하기 어렵다
- 같은 공지를 반복적으로 전달해야 한다
- 슬럼프에 빠진 수강생을 사전에 파악하기 힘들다
조교(TA) 입장:
- 예약한 수강생이 어떤 질문을 할지 미리 알 수 없다
- 스케줄 관리가 수동적이다
관리자 입장:
- 매일 뉴스·채용공고·자격증 정보를 수집·배포하는 데 시간이 걸린다
이 모든 문제를 하나의 AI 챗봇 시스템으로 해결할 수 있다면?
1-2. 프로젝트 목표
"교육 운영의 모든 접점을 AI로 통합하되, 사람이 꼭 필요한 순간에는 사람에게 넘긴다."
- 수강생: AI 챗봇 하나로 행정 질문, 학습 질문, 조교 예약, 멘토 1:1 상담까지
- 멘토: 수강생 학습 타임라인, 자료 업로드, 상담 요청 알림을 대시보드에서 한눈에
- 조교: AI가 스케줄을 잡아주고, 예약 수강생의 학습 이력을 AI 브리핑으로 제공
- 관리자: 큐레이션 콘텐츠 등록만 하면 AI가 유사도 기반으로 수강생에게 전달
2. 기획 — 시스템 설계
2-1. 아키텍처 설계: 멀티에이전트 구조
단일 챗봇이 모든 질문을 처리하면 프롬프트가 비대해지고, 응답 품질이 떨어진다. 그래서 에이전트를 분리했다.
사용자 메시지
│
▼
┌──────────────┐
│ Agent Router │ ← GPT-4o-mini가 의도 분류 (3-way)
└──┬───┬───┬───┘
│ │ │
▼ ▼ ▼
Agent A Agent B Human Handoff
(행정·커리어) (학습·조교) (멘토 1:1 상담)
| 에이전트 | 담당 영역 | RAG 컨텍스트 |
|---|---|---|
| Router | 의도 분류 (agent_a / agent_b / human_handoff) | 없음 |
| Agent A | 행정, 커리어, 큐레이션, 인사말, 모호한 질문 | 공통지식 + 큐레이션 + 멘토자료 |
| Agent B | 학습 질문, 코딩 질문, 조교 예약/취소 | 공통지식 + 조교 스케줄 |
| Handoff | 슬럼프, 동기부여, 커리어 위기 | — (멘토에게 전달) |
핵심 설계 원칙:
- 모호하면 무조건 Agent A (안전한 쪽으로 폴백)
- Human Handoff는 신뢰도 ≥ 0.8일 때만 (오분류 방지)
- 각 에이전트는 독립적인 RAG 파이프라인 보유
2-2. 4개 독립 벡터스토어
RAG(Retrieval-Augmented Generation) 검색을 위해 4개의 독립 FAISS 벡터스토어를 설계했다.
vectorstore/ → 공통 지식 (학칙, NCS, 출결 규정 등)
vectorstore_curation/ → 큐레이션 (채용·뉴스·자격증)
vectorstore_mentor/{id}/ → 멘토별 최신 자료
vectorstore_mentor_basic/{id}/ → 멘토별 기초 자료
왜 하나로 합치지 않았는가?
- 큐레이션은 시간 범위 필터(오늘/이번주/최근)가 필요하다
- 멘토 자료는 멘토별로 격리되어야 한다 (A 멘토 수강생이 B 멘토 자료를 보면 안 된다)
- 공통 지식은 변경 빈도가 낮지만, 큐레이션은 매일 추가된다
2-3. 데이터베이스 설계 (12개 테이블)
| 테이블 | 용도 |
|---|---|
users |
4개 역할 사용자 (kakao_id, mentor_id 연결) |
sessions |
토큰 기반 세션 |
qr_sessions |
QR 코드 크로스디바이스 로그인 |
invite_codes |
멘토↔수강생 초대 코드 |
chat_messages |
전체 대화 이력 (channel, agent_type 추적) |
handoff_queue |
멘토 1:1 상담 요청 큐 |
schedules |
조교 시간표 + 예약 정보 + AI 브리핑 |
knowledge_docs |
공통 지식 문서 |
mentor_docs |
멘토 최신 자료 (LargeBinary 파일 저장) |
mentor_basic_docs |
멘토 기초 자료 |
curation_items |
요일별 큐레이션 콘텐츠 |
student_events |
수강생 활동 추적 (검색, 자료 접근, 큐레이션 조회) |
2-4. 인증 시스템
세 가지 로그인 방식을 지원한다:
- 데모 로그인 — 즉시 체험용 (수강생/멘토/조교/관리자 4개 버튼)
- 카카오 OAuth 2.0 — 실제 사용자 연동
- QR 코드 로그인 — PC 화면에 QR 표시 → 모바일에서 스캔·승인
PC 브라우저 모바일
│ │
│ QR 토큰 생성 │
│ ←────────────────────── │
│ QR 코드 표시 │
│ ──────────────────────→ │ 스캔
│ │ 카카오 로그인
│ │ POST /qr/approve
│ 폴링 GET /qr/check │
│ ←── status: approved ── │
│ 세션 획득 │
3. 기술 스택 선정 이유
3-1. 백엔드: FastAPI
# 비동기 + 타입 힌트 + 자동 Swagger 문서 = FastAPI
from fastapi import APIRouter, BackgroundTasks, File, Form, UploadFile
- 비동기(async): LLM API 호출이 수초 단위 → 동기 서버는 병목
- BackgroundTasks: 파일 업로드 후 무거운 AI 처리를 백그라운드로 분리
- 타입 안전성: Pydantic 스키마로 요청/응답 검증
- Swagger UI: 개발 중 API 테스트 즉시 가능
3-2. 프론트엔드: React 19 + Vite + Tailwind CSS
- React 19: 최신 Concurrent Features 활용
- Vite: 3초 빌드, HMR은 즉시 반영
- Tailwind CSS: 컴포넌트 단위 스타일링 — 디자인 시스템 없이 빠르게 구현
- Framer Motion: 챗봇 메시지 애니메이션 — 카카오톡 느낌
- Lucide React: 일관된 아이콘 시스템
3-3. AI/LLM: GPT-4o-mini + LangChain
- GPT-4o-mini: 비용 90%+ 절감 (GPT-4 대비), 응답 속도 빠름, 한국어 품질 Good
- LangChain: LLM 호출, RAG 체인, 프롬프트 템플릿 통합 관리
- FAISS: CPU 기반 벡터 검색 — GPU 없는 Render 무료 서버에서도 동작
- OpenAI text-embedding-3-small: 임베딩 모델
3-4. 인프라: Render + PostgreSQL
- Render: GitHub push만으로 자동 배포, 무료 티어로 MVP 검증
- PostgreSQL: JSON 스토어에서 마이그레이션 → 영속성 + 쿼리 성능
- 1GB 영속 디스크: FAISS 인덱스 파일 저장
4. 개발 과정 — 단계별 진행
Phase 1: 프로젝트 초안 (v1.0 ~ v2.0)
최초 목표는 단순한 FAQ 챗봇이었다. 학칙, 출결 규정 등을 PDF로 넣고 RAG로 검색하는 구조.
사용자 질문 → RAG 검색 → GPT 응답
하지만 실제 교육 현장의 니즈를 파악하면서 기능이 확장되었다:
- 조교 예약 기능 필요 → Agent B 분리
- 멘토 상담 연결 필요 → Handoff 메커니즘 추가
- 큐레이션 배포 필요 → 별도 벡터스토어 추가
- 역할별 대시보드 필요 → 4개 페이지 추가
Phase 2: v3.0 멀티에이전트 아키텍처
단일 에이전트의 한계를 느끼고, 의도 분류 → 전문 에이전트 라우팅 구조로 전면 개편했다.
# agent_router.py — 핵심 라우팅 로직
async def classify_intent(message: str, llm) -> dict:
"""
Returns:
agent_a — 행정/커리어/인사/모호한 질문
agent_b — 학습/코딩/조교 예약
human_handoff — 감정적 지원 필요 (confidence ≥ 0.8)
"""
Agent A는 트리플 RAG 검색을 수행한다:
Agent A
├─ ① 공통 지식 검색 (학칙, NCS 등) — k=4
├─ ② 큐레이션 검색 (시간 범위 필터링) — k=8
└─ ③ 멘토 자료 검색 (해당 멘토 것만) — k=3+3
Agent B는 예약 키워드를 감지하고, 예약/취소 플로우를 트리거한다:
Agent B
├─ "예약" 키워드 → 예약/취소 선택 메뉴 제공
├─ 학습 질문 → GPT 응답 + 가능한 조교 시간 안내
└─ 예약 확정 시 → AI 브리핑 리포트 자동 생성
Phase 3: 프론트엔드 구현

React Router를 사용하지 않고, 역할 기반 상태 라우팅으로 구현했다.
// App.jsx
if (user.role === "student") return <StudentChat />; // 전체화면 챗봇
if (user.role === "mentor") return <Layout><Page /></Layout>; // 사이드바 + 대시보드
if (user.role === "ta") return <Layout><TADashboard /></Layout>;
if (user.role === "admin") return <Layout><AdminDashboard /></Layout>;
수강생은 전체화면 카카오톡 스타일 챗봇만 보고, 나머지 역할은 사이드바가 있는 대시보드를 본다.
카카오톡 스타일 UI 구현:
┌─────────────────────────────┐
│ ← 코리아IT-AI챗봇 🔍 ≡ │ KakaoTalk 헤더
├─────────────────────────────┤
│ │
│ 🏫 코리아IT-AI챗봇 │ 봇 프로필 + 이름
│ ┌──────────────────┐ │
│ │ 안녕하세요! 무엇을│ │ 흰색 봇 버블
│ │ 도와드릴까요? │ │
│ └──────────────────┘ │
│ │
│ ┌─────────────┐ │
│ │ 질문합니다 │ │ 노란색(#FEE500) 유저 버블
│ └─────────────┘ │
│ │
│ [오늘의 큐레이션] [조교 연결]│ 퀵 액션 버튼
│ [학습 팁] [멘토 연결] │
├─────────────────────────────┤
│ [메시지 입력...] [전송]│ 입력창
└─────────────────────────────┘
Phase 4: 카카오톡 채널 연동
웹과 동일한 기능을 카카오톡 오픈빌더 스킬(Webhook)로 제공한다.
# kakao.py — 3개 웹훅 엔드포인트
POST /api/kakao/webhook # 메인 (라우팅)
POST /api/kakao/webhook/schedule # 조교 예약 전용
POST /api/kakao/webhook/curation # 큐레이션 전용
카카오톡에는 5초 타임아웃 제한이 있어서, LLM 응답이 길어지면 실패한다. 이 문제를 asyncio.wait_for()로 4.8초 타임아웃 래핑하여 해결했다 (자세한 내용은 블로그 2장에서 다룸).
Phase 5: 배포 및 DB 마이그레이션
초기에는 JSON 파일 기반 스토어를 사용했다. 배포 후 Render의 휘발성 파일시스템 때문에 PostgreSQL로 전면 마이그레이션했다.
# database.py — PostgreSQL + SQLite 듀얼 지원
if DATABASE_URL:
engine = create_engine(url, pool_size=10, max_overflow=20)
else:
engine = create_engine("sqlite:///./local.db")
마이그레이션 전략:
store.py의 API 인터페이스는 유지 (라우터 코드 변경 X)- 내부 구현만 JSON → SQLAlchemy ORM으로 교체
- 기존 JSON 데이터를 시드 데이터로 자동 변환
Phase 6: 성능 최적화
배포 후 발견된 성능 문제들을 개선했다:
- LLM 프롬프트 영어 전환: 한국어 프롬프트를 영어로 바꾸면서 응답을 한국어로 유지 → 토큰 수 30%+ 감소, 처리 속도 향상
- gpt-4o-mini로 복원: 실험적으로 다른 모델을 시도했다가 속도 문제로 복원
- 파일 업로드 백그라운드 처리: 업로드 시 PDF 추출, AI 요약, 벡터스토어 인덱싱을 전부
BackgroundTasks로 분리 → 응답 즉시 반환
# Before: 모든 처리 → 응답 (10초+)
payload = await file.read()
content_text = extract_pdf(stored_path) # 블로킹
title, summary = await build_ai_digest() # 5-10초
store.add_mentor_doc({..., file_data=payload}) # 대용량 INSERT
return {"status": "ok"} # 10초 후에야 응답
# After: 즉시 응답 → 나머지 백그라운드
store.add_mentor_doc({..., file_data=None}) # 최소 INSERT (빠름)
bg.add_task(bg_process, ...) # PDF + AI + file_data → 비동기
return {"status": "ok"} # 즉시 응답
- N+1 쿼리 최적화: 대시보드 활동 조회에서 학생별 쿼리를 배치 쿼리로 변경
5. 주요 기능 상세
5-1. AI 챗봇 — 수강생 대화 플로우

[웰컴 메시지]
├── 🗞 오늘의 큐레이션 → Agent A (큐레이션 RAG 검색)
├── 📅 조교 연결 → Agent B (예약 가능 날짜 → 시간대 → 설명 입력 → AI 브리핑)
├── 💡 학습 팁 → Agent A (멘토 최신/기초 자료 검색)
└── 🤝 멘토 연결 → Handoff (멘토 대시보드에 알림)
예약 플로우 예시:
수강생: "조교님 예약하고 싶어요"
봇: "예약 / 취소 중 선택해주세요" [예약] [취소]
수강생: [예약]
봇: "날짜를 선택해주세요" [4/14(월)] [4/15(화)] ...
수강생: [4/15(화)]
봇: "시간을 선택해주세요" [10:00~11:00] [14:00~15:00]
수강생: [14:00~15:00]
봇: "질문 내용을 입력해주세요"
수강생: "파이썬 함수 관련 질문이요"
봇: "예약이 완료되었습니다! ✅"
이때 AI 브리핑 리포트가 자동 생성되어 조교 대시보드에 표시된다:
{
"student_name": "수강생1",
"search_history": ["파이썬 함수", "리스트 컴프리헨션", "람다 표현식"],
"core_need": "파이썬 기초 문법 (함수, 리스트) 학습 지원",
"ai_recommendation": "함수 정의와 활용 위주로 설명하면 좋겠습니다"
}
5-2. 멘토 자료 관리

멘토는 두 종류의 자료를 업로드할 수 있다:
- 최신 자료: 수업 관련 최신 학습 자료 (14일 지나면 "오래된 자료"로 분류)
- 기초 자료: 반복적으로 참조되는 기본 학습 자료
업로드 형태: PDF 파일, 이미지, 외부 링크
업로드 프로세스 (백그라운드):
[파일 업로드] → [디스크 저장] → [DB 최소 INSERT] → [즉시 응답]
│
[백그라운드] ▼
PDF 텍스트 추출
AI 제목·요약 생성
file_data DB 저장
벡터스토어 인덱싱
5-3. 조교 스케줄 관리

조교 대시보드에서 3가지 방식으로 스케줄을 관리한다:
- AI 자연어 입력: "화요일, 목요일 10시~14시 2주간" → AI가 파싱하여 슬롯 생성
- 빠른 생성: 요일 + 시간대 선택 → 반복 슬롯 일괄 생성
- 날짜별 수정: 달력에서 특정 날짜 클릭 → 해당 날짜만 변경 (나머지 유지)
5-4. 큐레이션 시스템

요일별 카테고리 스케줄:
| 월 | 화 | 수 | 목 | 금 |
|---|---|---|---|---|
| 채용정보 | IT뉴스 | AI타임스 | 자격증·공모전 | 개발트렌드 |
관리자가 파일/링크를 등록하면:
- AI가 제목·요약 자동 생성
- 큐레이션 벡터스토어에 인덱싱
- 수강생이 "오늘의 큐레이션" 요청 시 RAG 검색으로 관련 콘텐츠 제공
5-5. 멘토 1:1 상담 핸드오프
수강생: "요즘 너무 힘들어서 포기하고 싶어요..."
│
▼ Agent Router (confidence ≥ 0.8 → human_handoff)
│
▼ handoff_queue에 등록
│
▼ 멘토 대시보드에 빨간 알림 뱃지 표시
│
▼ 멘토가 수강생 타임라인 확인 후 직접 상담
6. 배포 구성
Render 배포 아키텍처
# render.yaml
services:
- name: edu-sync-api # 백엔드 (Python)
type: web
runtime: python
buildCommand: pip install -r requirements.txt
startCommand: cd backend && uvicorn main:app --host 0.0.0.0 --port $PORT
disk:
name: data
mountPath: /data
sizeGB: 1
- name: edu-sync-frontend # 프론트엔드 (정적 사이트)
type: static
buildCommand: cd frontend && npm install && npm run build
staticPublishPath: frontend/dist
databases:
- name: edu-sync-db # PostgreSQL
plan: free
환경 변수:
OPENAI_API_KEY— GPT-4o-mini + 임베딩DATABASE_URL— PostgreSQL 연결 문자열KAKAO_REST_API_KEY,KAKAO_REDIRECT_URI— 카카오 OAuthSEED_DATA=1— 초기 데모 데이터 자동 생성
7. LLM 토큰 최적화 전략
비용과 속도를 동시에 잡기 위한 전략들:
| 전략 | 효과 |
|---|---|
| GPT-4o-mini 사용 | 비용 90%+ 절감 (GPT-4 대비) |
| 프롬프트 영어 작성, 응답 한국어 | 토큰 30%+ 절감 |
| JSON 응답 형식 강제 | 불필요한 토큰 생성 방지 |
| RAG 검색 결과 top-k 제한 (k=3~8) | 컨텍스트 토큰 제어 |
| 큐레이션 본문 400자 제한 | 불필요한 긴 텍스트 방지 |
| 카카오 응답 990자 제한 | 카카오톡 simpleText 제한 준수 |
# 영어 프롬프트 → 한국어 출력 예시
prompt = """
You are a study support AI for Korean vocational training.
Always reply in Korean.
Analyze the student's question and search results below.
Return JSON: {"content": "...", "choices": [...]}
"""
8. 프로젝트 회고
잘한 점
- 멀티에이전트 분리: 각 에이전트가 독립적으로 개선 가능 — 단일 챗봇보다 유지보수 용이
- LLM Provider 추상화: 나중에 온프레미스 LLM으로 교체해도 인터페이스 동일
- 백그라운드 처리 패턴: 사용자 경험(즉시 응답)과 기능(AI 요약)을 분리
- 4개 독립 벡터스토어: 역할별 데이터 격리 + 검색 정밀도 향상
아쉬운 점
- WebSocket 미도입 → 대시보드 실시간 업데이트 없음 (폴링)
- Render 무료 티어의 콜드 스타트 + PostgreSQL 레이턴시
- 카카오톡 채널 5초 타임아웃 제한 → Render 무료 DB에서는 구조적 한계
향후 개선 방향
- WebSocket 도입 (멘토 대시보드 실시간 알림)
- Redis 캐시 (자주 묻는 질문 캐싱)
- LLM 스트리밍 응답
- 온프레미스 LLM 전환 (보안이 중요한 교육 기관용)
9. 기술 스택 한눈에 보기
┌─── Frontend ────────────────────────────┐
│ React 19 · Vite 6 · Tailwind CSS 3 │
│ Framer Motion · Lucide React │
│ KakaoTalk-style Chat UI │
├─── Backend ─────────────────────────────┤
│ FastAPI · Python 3.11 · Uvicorn │
│ LangChain · FAISS · SQLAlchemy 2.0 │
│ OpenAI GPT-4o-mini │
│ BackgroundTasks (async processing) │
├─── Database ────────────────────────────┤
│ PostgreSQL (12 tables) │
│ FAISS Vectorstores (×4) │
├─── External ────────────────────────────┤
│ Kakao OAuth 2.0 · Kakao OpenBuilder │
│ OpenAI API │
├─── Infra ───────────────────────────────┤
│ Render (Web Service + Static Site) │
│ GitHub Actions (auto-deploy on push) │
│ 1GB Persistent Disk │
└─────────────────────────────────────────┘
다음 글(2장)에서는 프로젝트를 진행하면서 겪었던 트러블슈팅들을 다룹니다.
'5. [개인] 프로젝트 및 공모전 > 4-4 공모전' 카테고리의 다른 글
| [개인 공모전] DACON - ETRI 휴먼이해 인공지능 논문경진대회 (1) (0) | 2026.05.31 |
|---|---|
| [KDT 공모전] 멀티 에이전트 카카오톡 챗봇 플랫폼: 트러블 슈팅 (2) (0) | 2026.04.11 |