이 내용은 팀프로젝트 진행하는데 필요했던 내용을 스터디하면서 내가 한땀한땀 노션에 정리했던 자료로,
정리하게 된 배경은
팀원분이 FastAPI + SQLite 기반으로 구조를 제안하셨는데
우리가 하고자 하는 게 LLM 기반 서비스여서 내가 확장성과 검색 기능이 강화된 RAG 기반 구조를 제안했기 때문..
생각보다 의견 조율이 쉽지 않아서 각각이 어떤 것이고 왜 필요한지 이해를 돕고 설명을 하기 위함이라 다소 중복되는 내용이 있을 수 있다.
: FastAPI가 중심이 되어, 사용자 질문을 임베딩 + Weaviate로 의미 기반 검색 + LLM 답변 생성 + DB 저장, React 프론트와 통신하는 구조
LLM에서는 단순히 모델 구조뿐 아니라 "사용자 입력 → 내부 처리 → 출력 → 학습 데이터"가 유기적으로 설계되어야 함
| 단계 | 구성 요소 | 설명 | 왜 중요한가 |
|---|---|---|---|
| 1단계 | 사용자 입력 | ||
| (User Prompt) | 사용자가 실제로 입력하는 문장이나 질문 | 잘 설계되지 않으면 모델이 오작동하거나 의미를 제대로 이해 못 함 | |
| 2단계 | 내부 처리 | ||
| (Internal Prompt Handling / Preprocessing) | 입력을 토큰화, 전처리하거나 시스템 프롬프트/컨텍스트를 설정하는 부분 | 컨텍스트가 모델의 "생각 흐름"을 결정함 | |
| 3단계 | 출력 (Model Output) | LLM이 생성한 응답, 요약, 분류 결과 등 | 응답의 신뢰도와 일관성 확보가 필요 |
| 4단계 | 학습 데이터 | ||
| (Training/Fine-tuning Data) | 모델이 학습하거나 미세 조정할 때 사용한 데이터 | 도메인 특화 성능은 여기에 달려 있음 |
"문장을 숫자로 바꿔주는 모델"
사용 예시)
"딸이 부모를 부양 안 하면 상속 못 받나요?"
→ 이 문장은 LLM이 쓰기엔 너무 추상적이니까
숫자 벡터(768차원짜리 벡터 등)로 바꿔서 Weaviate에 넣음
이렇게 바꾸는 일을 하는 모델이 바로 임베딩 모델
📌 HuggingFace에서는 sentence-transformers/paraphrase-MiniLM-L6-v2 같은 모델이 이 역할을 함
사전 학습용, 즉 baseline 언어모델을 직접 처음부터 학습시키려면 수십억~수천억 토큰 단위의 데이터가 필요
: 이미 사전학습된 LLM (예: LLaMA, GPT2, Mistral 등)에 도메인 지식을 주입
| 데이터 양 (텍스트 쌍 기준) | 기대 수준 |
|---|---|
| ~1만 개 | 소규모 실험용, 빠른 프로토타입 가능 |
| 1만~5만 개 | 적응 시작, 특정 태스크 성능 향상 |
| 5만~10만 개 | 도메인에 꽤 잘 적응, 실제 서비스 적용 가능 |
| 10만~50만 개 | 일반적 파인튜닝 상한선, 고품질이면 LLM이 도메인 전문가처럼 동작함 |
| 100만 개 이상 | 특수 대규모 서비스나 논문 연구 수준, 많은 비용/시간 필요 |
ERT, RoBERTa, T5, KoBERT 등에 텍스트 분류, 요약, QA 태스크 적용
| 데이터 양 | 기대 성능 |
|---|---|
| 5천 개 이하 | overfitting 주의, baseline 모델용 |
| 1만~5만 개 | 꽤 괜찮은 성능, Kaggle 수준 대회 가능 |
| 5만~10만 개 | 업계 실무 기준, 모델 안정성↑ |
| 10만 개 이상 | 확실한 성능 확보, 다양한 조건 대응 가능 |
문서를 임베딩해 검색 가능한 DB 구축 (예: 판례, 논문, 블로그 등)
중요한 건 데이터 “양”보다 “질” + 문서 길이와 다양성
예: 짧은 Q&A만 있는 10만 개보단, 풍부한 문맥을 담은 3만 개 판례
| 문서 수 (텍스트 단위) | 용도 |
|---|---|
| 1천~5천 개 | 테스트 및 데모 수준 |
| 5천~2만 개 | 소규모 서비스 가능 |
| 2만~10만 개 | 일반적인 프로덕션 수준 |
| 10만~100만 개 이상 | 대규모 서비스 또는 기업 내부 지식관리 |
GPT 추천 수준
| 상황 | 적절한 데이터 양 |
|---|---|
| 시니어 법률 자문 서비스 Instruction 튜닝 | 5만~10만 개 질문-답변 쌍 (도메인 맞춤형) |
| 판례 벡터 DB 구축 (RAG용) | 2만~10만 개 판례 또는 문단 수준 문서 |
| 법률분야 분류 모델 | 1만~5만 개 라벨링 텍스트 |
| 구성 | FastAPI + SQLite 구조 | 제안하는 구조 |
|---|---|---|
| API 서버 | FastAPI 단독 | FastAPI (역할 분리) |
| DB | SQLite | Supabase(PostgreSQL) + Weaviate |
| AI 모델 | FastAPI에서 로딩 | HuggingFace LLM + 벡터 검색(RAG) |
| 문서 검색 | ❌ 불가 | ✅ Weaviate (의미기반 검색) |
| 정형 정보 조회 | SQL 직접 쿼리 | ✅ GraphQL API로 빠르게 조회 |
| 히스토리 저장 | SQLite 파일 | ✅ 실시간 저장 + 조회 (Supabase) |
| 문서 의미 검색 | 불가 | Weaviate로 RAG 구현 |
|---|---|---|
| AI 모델 추론 | 로딩 가능하나 컨텍스트 제한 | 문서 + 질문 기반 고도화 |
| 데이터 저장 | 단일 파일, 병렬 처리 어려움 | Supabase로 실시간 + 안정 저장 |
| 사용자 경험 | 직접 SQL만 가능 | GraphQL + React 최적화 |
| 확장성 | 단일 개발/로컬 테스트용 | 팀 개발, MVP, 서비스 확장까지 가능 |
[사용자 화면]
↓ 질문 입력
[React + TypeScript + Docker] 프론트
↓ FastAPI 백엔드에 요청 (REST 스타일) (예: `/recommend`, `/history`, `/query`)
────────────────────────────────────
[FastAPI 백엔드 서버]
├─ `/recommend` → LLM 기반 판례 추천 : [FastAPI → Weaviate + LLM → 답변 생성]
│ ├─ HuggingFace sentence-transformers → 질문 임베딩
│ ├─ Weaviate 벡터 DB → 유사 판례 문서 검색
│ ├─ HuggingFace LLM → 검색 문서 + 질문으로 답변 생성
│ ├─ Supabase PostgreSQL → 질문/답변 기록 저장
│ └─ 결과 응답 → 프론트로 반환
├─ `/history` → 사용자 히스토리 불러오기 : [FastAPI → Supabase → 기록 조회]
│ └─ Supabase PostgreSQL에서 사용자 질문/답변 이력 조회
├─ `/query` → 판례 목록 등 정형 정보 요청 : [프론트 or FastAPI → Supabase GraphQL → PostgreSQL]
│ └─ Supabase GraphQL API 호출 → 판례 제목, 날짜 등 조건 필터 조회
────────────────────────────────────
[외부 구성 요소]
├─ HuggingFace 모델
│ ├─ 문장 임베딩 모델 (예: `sentence-transformers`)
│ └─ LLM 모델 (예: GPT2, Mistral, Falcon 등)
├─ Weaviate (벡터 DB)
│ └─ 임베딩된 문서 저장 + 의미기반 검색
├─ Supabase (PostgreSQL)
│ └─ 사용자, 질문, 답변, 히스토리 저장
├─ Supabase GraphQL API
│ └─ 판례 제목, 날짜 등 정형 데이터 조회용 API
사용자가 입력한 질문은 React 프론트에서
REST API를 통해 FastAPI 서버로 전달
FastAPI는 그 질문을 먼저 문장 임베딩 모델(HuggingFace)에 넣어서
숫자 벡터로 바꿈
그 벡터를 가지고 Weaviate(벡터 DB)에 요청을 보냄
Weaviate가 관련 문서 여러 개를 찾아서 FastAPI에 넘김
FastAPI는
모델은 “문서들을 참고해서 질문에 대한 답변”을 생성
FastAPI는 이 답변을 다시 React 프론트에 보냠
동시에 사용자의 질문/답변/시간 같은 기록을
Supabase(PostgreSQL)에 저장
프론트는 그 답변을 사용자한테 보여줌
| 구성 요소 | 정확한 정체 | 역할 설명 | 비유 (쉽게 풀어 쓴 표현) |
|---|---|---|---|
| FastAPI | 백엔드 서버 프레임워크 | REST API 서버. 프론트 요청을 받아 LLM 호출, DB 저장 등 모든 처리 담당 | 손님 요청을 받고 주방(모델/DB)과 연결해주는 종업원 |
| HuggingFace 임베딩 | 문장 임베딩 모델 | 질문을 벡터로 변환하여 Weaviate에서 의미기반 검색할 수 있게 처리 | 질문을 수치화해 검색할 수 있도록 가공하는 벡터 번역기 |
| Weaviate | 벡터 DB 시스템 | 의미기반 문서 검색. 질문과 유사한 판례를 벡터 공간에서 찾아 반환 | AI 전용 검색 창고 |
| HuggingFace LLM | AI 답변 생성기 (LLM) | 질문 + 유사 문서를 받아 자연어 답변 생성 (GPT2, Mistral 등 사용) | 문서들을 읽고 답장을 써주는 AI 작가 |
| PostgreSQL | 관계형 데이터베이스 | 사용자 정보, 질문/답변 히스토리 등 정형 데이터를 저장 | 칸칸이 잘 정리된 엑셀 표 창고 |
| Supabase | PostgreSQL 관리 플랫폼 | PostgreSQL을 쉽게 쓰게 해주는 도구. 인증, GraphQL API, 실시간 기능까지 포함 | DB, 로그인, API까지 관리해주는 올인원 매니저 |
| GraphQL API | 데이터 통신 방식 (API 스타일) | 프론트에서 원하는 필드만 요청 가능. 판례 제목, 날짜, 카테고리 등 정형 데이터 조회용 | “이름만 주세요!” 하고 정확한 항목만 뽑아주는 스마트 요청 창구 |
| React + TypeScript | 프론트엔드 (사용자 인터페이스) | 사용자 입력을 받고, FastAPI 또는 GraphQL로 요청 후 응답을 화면에 출력 | 사용자가 직접 만지는 화면, 버튼, 입력창 등 |
FastAPI는 LLM 추론, Weaviate 검색, 히스토리 저장 같은 비정형 고처리 로직을 맡고, Supabase의 GraphQL API는 단순한 정형 정보(판례 목록 등)를 가볍게 조회할 수 있게 분리한 구조
실제로 이 구조를 많이 사용한다고 함
[React]
├─ /recommend 요청 → [FastAPI → Weaviate + LLM → 답변]
├─ /history 요청 → [FastAPI → Supabase → 기록 조회]
└─ GraphQL 요청 → [Supabase GraphQL 엔진 → 판례 목록/필터링]
Weaviate는 언제 필요해지냐
사용자의 질문에 대해
“내가 미리 저장해둔 문서 중에서 관련된 걸 먼저 검색하고” →
“그걸 참고해서 LLM이 답변하도록 만들고 싶을 때”
즉, RAG 구조일 때 필요
사용자가 “상속세율”이라고 물었을 때
→ 모델이 직접 생성하는 게 아니라,
→ “내가 저장한 법률 문서 중에서 ‘상속세율’ 관련 내용을 먼저 검색”
→ 그걸 컨텍스트로 모델에 넣고
→ 모델이 그걸 바탕으로 답변 생성
이 구조를 가능하게 해주는 게 바로 Weaviate (벡터 DB)
| 항목 | Weaviate (벡터 DB) | PostgreSQL (일반 DB) |
|---|---|---|
| 목적 | "비슷한 의미" 찾기 | "정확한 조건"으로 찾기 |
| 저장하는 것 | 임베딩된 숫자 벡터 (ex: 문장의 의미) | 테이블/행/열로 구성된 일반 데이터 |
| 예시 질문 | “이와 비슷한 판례는 뭐야?” | “2023년 이후 민법 판례 중 상속 관련된 것만 줘” |
| 사용 위치 | RAG 검색 (GPT가 참고할 자료) | 일반 정보/조건 조회 (목록, 히스토리 등) |
| 검색 방식 | 의미 기반 근접 검색 (semantic search) | SQL 조건 검색 (WHERE절) |
| 연동 방식 | REST API / GraphQL (Weaviate 자체 API) | GraphQL API (Supabase 또는 Hasura) |
"딸이 부모 부양을 안 하면 상속 못 받나요?"
→ 이 문장을 벡터화해서, 유사한 판례 문장을 의미기반으로 검색
SELECT * FROM 판례 WHERE category='상속' AND year >= 2020이건 그냥 참고용
| 기능 | Weaviate | SQLite |
|---|---|---|
| 의미 기반 검색 | 내장 벡터 검색 (HNSW) | 없음 |
| 문서 분류 없이 유사도 검색 | 지원 | 불가능 |
| RAG 필수 요소 | HuggingFace와 연동 쉬움 | 구조 자체가 안 맞음 |
| 특징 | GraphQL | SQL 직접 호출 (SQLite 등) |
|---|---|---|
| 필요한 필드만 조회 | 지원 | 전부 조회 후 필터링 |
| 조건별 조합 쿼리 | 유연함 | 직접 JOIN, WHERE 처리 필요 |
| 프론트와 연동 | React + Apollo 등과 궁합 좋음 | REST만 가능 |
| 실시간 구독 | 가능 (Supabase) | 안됨 |
| 특징 | GraphQL | SQL 직접 호출 (SQLite 등) |
|---|---|---|
| 필요한 필드만 조회 | 지원 | 전부 조회 후 필터링 |
| 조건별 조합 쿼리 | 유연함 | 직접 JOIN, WHERE 처리 필요 |
| 프론트와 연동 | React + Apollo 등과 궁합 좋음 | REST만 가능 |
| 실시간 구독 | 가능 (Supabase) | 안됨 |