스크립트에서 웹서비스로
박수현 · (사)한국정보공학기술사회 · 2026
🎯 목표: 코드 작성에 앞서 각 구성 요소의 위치와 역할을 정리한다.

RAG 웹서비스 3계층 · 브라우저(fetch/SSE) ↔ Flask(/upload·/files·/ask) ↔ Chroma(영속)+OpenAI API
💡 핵심 원칙: 라우트(HTTP)는 얇게, 로직은 서비스 계층에. 화면과는 JSON 으로만 통신한다.
화면(GET /) · 문서 리소스(/upload·/files) · 질문 리소스(/ask) 세 그룹으로 설계
| 메서드 · 경로 | 역할 | CRUD |
|---|---|---|
GET / |
화면(HTML) 서빙 | — |
POST /upload |
문서 업로드 + 색인 | C |
GET /files |
문서 목록 | R |
DELETE /files/<source> |
문서 삭제 | D |
POST /ask |
질의응답 | — |
🔑 같은
/files경로라도 메서드가 동작을 결정한다(GET 조회·DELETE 삭제). 응답을 JSON 으로 통일하면 curl·모바일 앱 등 모든 클라이언트에서 호출 가능하다.
project/
├─ app.py ← create_app() 앱 팩토리
├─ routes/ ← Flask Blueprint
│ ├─ page_bp.py ← GET / (화면 서빙)
│ ├─ files_bp.py ← 업로드·목록·삭제
│ └─ qa_bp.py ← 질의응답
├─ services/
│ ├─ vectorstore.py ← 색인·목록·삭제
│ └─ qa_service.py ← 검색·답변
├─ uploads/ ← 원본 파일
├─ chroma_db/ ← 벡터 영속
└─ templates/ ← 프론트(index.html)
create_app() 으로 Blueprint 조립 전담📁 참고:
8.web_app/4.refactor_with_score/(routes·services 분리 버전)
persist_directory 로 디스크에 저장Chroma(
persist_directory="./chroma_db",
embedding_function=emb,
)
| 폴더 | 저장 내용 |
|---|---|
uploads/ |
원본 파일 (재다운로드·재색인용) |
chroma_db/ |
벡터 + 메타데이터 |
🔑 원본과 벡터를 함께 보관해야 삭제·재색인이 가능하다.
💡 route 는 수신·위임·응답만 담당한다. 무거운 작업(파싱·임베딩)은 서비스 계층이 처리한다.
/upload·/files(CRUD) · /ask(질의) · /(화면)