시스템을 계층으로 분리. 어디에 어떤 컴포넌트가 사는 보여줌
시스템을 계층으로 분리. 어디에 어떤 컴포넌트가 사는 보여줌.
💡 핵심 개념: 좋은 아키텍처는 관심사 분리(SoC). "UI 코드"와 "DB 쿼리"가 한 함수에 섞이면 안 됨. LLM 앱에선 특히 프롬프트 조립을 도메인 로직에서 분리하는 게 핵심.
flowchart TB
subgraph CL["🖥️ 클라이언트 레이어"]
U[👤 사용자]
end
subgraph AL["🌐 API 레이어"]
A["FastAPI 서버"]
end
subgraph RL["📦 RAG 레이어"]
RP["RAG Pipeline"]
RT["Retriever"]
RD["Indexer"]
end
subgraph LL["🧠 LLM 레이어"]
LP["LLM Provider"]
end
subgraph SL["💾 스토리지 레이어"]
VDB[("Vector DB")]
MDB[("Metadata DB")]
end
subgraph XL["🔁 횡단 관심사"]
AG["🤖 Agent"]
PO["✨ Prompt Opt"]
TS["🛡️ Type Safety"]
end
U <--> A
A --> RP
RP --> RD
RP --> RT
RD --> VDB
RT <--> VDB
RT --> A
A --> LP
LP --> A
RD <--> MDB
AG -.도구.-> LP
PO -.최적화.-> LP
TS -.검증.-> A
🔧 레이어별 책임 + 추천 폴더 구조
- 클라이언트 — 웹/모바일 UI. 서버 호출만.
- API — 인증·rate limit·요청 검증·응답 직렬화.
app/api/
- RAG — 인덱싱·검색 로직.
app/rag/ (loader.py, splitter.py, retriever.py)
- LLM — 모델 호출 추상화.
app/llm/ (providers/openai.py, anthropic.py)
- 스토리지 — Vector DB + metadata DB.
app/db/
- 횡단 관심사 — Agent / Prompt Opt / Type Safety는 어디서나 쓰임.
app/core/
📋 FastAPI 기준 폴더 예시:
app/
├── api/
│ ├── chat.py # POST /chat 엔드포인트
│ └── admin.py # 문서 업로드
├── rag/
│ ├── loader.py # PDF/HTML → Document
│ ├── splitter.py # Document → Chunk[]
│ ├── embedder.py # Chunk → Embedding
│ ├── indexer.py # Embedding → Vector DB
│ └── retriever.py # Query → RetrievedChunk[]
├── llm/
│ ├── providers/
│ │ ├── openai.py
│ │ └── anthropic.py
│ └── prompts/ # prompt templates
├── core/
│ ├── agent.py # Agent orchestration
│ ├── prompt_opt.py # DSPy integration
│ └── types.py # Pydantic models
└── db/
├── vector.py # Pinecone client
└── metadata.py # Postgres session
⚠️ 흔한 함정:
- 모든 로직을 api/chat.py에 다 넣음 — 파일 1개에 2000줄. 테스트·재사용 불가
- LLM Provider 교체 시 import 100개 수정 — 추상화 레이어(
LLMProvider 인터페이스) 필수
- 스토리지 인터페이스 없이 직접 Pinecone 호출 — 테스트 시 mock 어려움.
VectorStore 추상화 권장
🛠️ 아키텍처 지원: FastAPI(API), LangGraph(에이전트), Pydantic AI(타입), Prefect/Airflow(인덱싱 워크플로우).