Spring Boot 개발자의 로컬 RAG 파이프라인 구축기
2주마다 발행할 개발 블로그 시리즈 기획안
주제: 외부 API 비용 없이, 로컬 오픈소스 기반으로 한국어 RAG 파이프라인 만들기
서브주제: 현재 회사에서 AI 활용능력을 중요하게 보고 있어, 모든것을 AI를 활용하여 진행하기
글 발행 정보
추천 카테고리
개발 / AI / RAG
추천 태그
RAG, 로컬LLM, Ollama, Qdrant, FastAPI, SpringBoot, bge-m3, 한국어RAG, 오픈소스, 벡터DB
시리즈 제목 후보
Spring Boot 개발자의 로컬 RAG 파이프라인 구축기
또는
돈 안 쓰고 만드는 사내 문의응대 RAG 시스템
개인적으로는 아래 제목을 추천한다.
Spring Boot 개발자의 로컬 RAG 파이프라인 구축기
이 제목은 다음 내용을 자연스럽게 담을 수 있다.
- Spring Boot 기반 업무 시스템
- Python FastAPI 기반 RAG 서버
- 로컬 오픈소스 기반 구성
- 한국어 문의응대 시스템
- 나중에 직접 만드는 비개발자용 관리 화면
1. 왜 이 시리즈를 쓰는가?
요즘 사내 문의응대나 운영 지식 검색에 RAG를 적용하는 사례가 많아지고 있다.
나 역시 기존 문의/답변 데이터와 운영 매뉴얼을 활용해서, 사용자가 질문하면 관련 답변 후보와 근거 문서를 찾아주는 시스템을 만들어보고 싶었다.
처음에는 Dify나 RAGFlow 같은 도구를 검토했다. 이런 도구들은 빠르게 시작할 수 있다는 장점이 있지만, 나중에 사내 권한 체계, 문의 이력, 답변 피드백, 문서 승인 프로세스와 연결하려면 직접 제어할 수 있는 구조가 더 적합하다고 판단했다.
그래서 이번 시리즈에서는 외부 API 비용 없이, 로컬 오픈소스 기반으로 한국어 RAG 파이프라인을 직접 구축해보려고 한다.
최종 목표는 다음과 같다.
Spring Boot
- 사용자 화면
- 권한
- 질문/답변 로그
- 나중에 비개발자 관리 화면
↓ HTTP API
Python FastAPI RAG Server
- 문서 색인
- 검색
- reranking
- 로컬 LLM 답변 생성
↓
Qdrant Local
- 벡터 저장
- 메타데이터 저장
↓
Ollama
- 로컬 LLM 실행
처음부터 완성형 시스템을 만들지는 않는다.
우선 문의/답변 CSV 데이터를 수동으로 색인하고, 사용자 질문에 대해 관련 문서 top 5를 반환하는 API부터 만드는 것이 목표다.
2. 전체 방향
이번 시리즈의 기준은 다음과 같다.
1. 외부 API 비용은 최대한 0원
2. 로컬/오픈소스 기반
3. 개발속도 중요
4. Spring Boot와 나중에 연동
5. 비개발자 화면은 나중에 직접 개발 가능
6. 한국어 업무 문의응대에 적합해야 함
그래서 최종적으로 선택한 방향은 다음과 같다.
Dify 중심 구조 ❌
RAGFlow 중심 구조 ❌
처음부터 거대한 프레임워크 중심 구조 ❌
FastAPI 기반 Headless RAG API 구조 ✅
여기서 Headless RAG API란, RAG 기능은 API 서버로만 제공하고 화면은 별도로 만드는 구조를 의미한다.
[Spring Boot 화면]
↓
[FastAPI RAG API]
↓
[Qdrant + Ollama]
이렇게 구성하면 나중에 화면을 직접 만들 수 있다.
3. 추천 기술 스택
1차 MVP 스택
API 서버:
FastAPI
임베딩:
BAAI/bge-m3
벡터DB:
Qdrant Local Docker
키워드 검색:
rank_bm25, 선택사항
재정렬:
BAAI/bge-reranker-v2-m3
LLM:
Ollama
LLM 모델:
EXAONE, Qwen, Gemma 계열 중 로컬 사양에 맞게 선택
메타데이터/로그:
처음엔 SQLite 또는 PostgreSQL
회사 시스템 연동 후에는 기존 DB 또는 PostgreSQL
Spring Boot 역할
- 사용자 문의 화면
- 질문 입력
- RAG API 호출
- 추천 답변 표시
- 근거 문서 표시
- 답변 사용/수정/피드백 저장
- 나중에 문서 관리 화면
Python RAG 서버 역할
- CSV/Excel 읽기
- 문서 정제
- chunk 생성
- 임베딩 생성
- Qdrant 저장
- 검색
- reranking
- Ollama 호출
- 답변 생성
4. 최종 RAG 파이프라인
추천하는 전체 파이프라인은 다음과 같다.
문의/답변 CSV, Excel
↓
문서 정제
↓
Q/A 단위 chunk 생성
↓
bge-m3 임베딩
↓
Qdrant 저장
↓
질문 입력
↓
Qdrant vector search
↓
BM25 키워드 검색, 선택사항
↓
결과 병합
↓
bge-reranker-v2-m3 재정렬
↓
Ollama 로컬 LLM 답변 생성
↓
근거 문서와 함께 반환
실제 실행 흐름은 다음과 같다.
[CSV/Excel 문의답변]
↓
[indexer.py]
↓
[Qdrant Local]
[사용자 질문]
↓
[FastAPI /rag/query]
↓
[검색 + 재정렬]
↓
[Ollama LLM]
↓
[답변 + 근거 반환]
↓
[Spring Boot 화면]
5. 처음 만들 API
처음에는 API를 많이 만들 필요가 없다.
MVP 기준으로는 아래 2개면 충분하다.
POST /rag/index
POST /rag/query
/rag/index
CSV나 Excel 데이터를 읽어서 Qdrant에 저장한다.
입력 데이터 예시는 다음과 같다.
질문
답변
카테고리
시스템명
메뉴명
태그
등록일
/rag/query
질문을 받아서 답변과 근거를 반환한다.
응답 예시는 다음과 같다.
{
"question": "TID 일괄등록에서 site_cd 오류가 나요",
"answer": "site_cd 형식이 맞지 않을 가능성이 있습니다. site_cd는 5byte이며 영문 대문자와 숫자만 허용됩니다.",
"sources": [
{
"docId": "DOC_001",
"chunkId": "CHUNK_001",
"title": "TID 일괄등록 검증 기준",
"score": 0.92,
"content": "site_cd는 5byte이며 영문 대문자와 숫자만 허용됩니다."
}
]
}
처음에는 문서 업로드 화면, 승인 화면, 비개발자 관리 화면은 만들지 않는다.
우선 질문했을 때 관련 문서가 잘 검색되는지를 확인한다.
6. Chunk 설계
한국어 문의응대 데이터는 일반 문서처럼 단순히 500자씩 자르는 것보다, Q/A 한 건을 하나의 chunk로 저장하는 것이 좋다.
예시는 다음과 같다.
[시스템] 파트너 관리자
[메뉴] 단말기 일괄등록
[문의유형] CSV 업로드 오류
[태그] TID, site_cd, 사이트코드, 단말기, 일괄등록
[질문]
TID 일괄등록 시 site_cd 오류가 발생합니다.
[답변]
site_cd는 5byte이며 영문 대문자와 숫자만 허용됩니다.
CSV 업로드 전 site_cd 값에 공백, 소문자, 특수문자가 포함되어 있는지 확인해야 합니다.
이렇게 저장해야 사용자가 다른 표현으로 질문해도 검색이 잘 된다.
예를 들어 다음 질문들은 같은 답변 문서로 연결될 수 있다.
사이트코드 오류 나는데 왜 그런가요?
TID 업로드가 실패합니다.
단말기 일괄등록 CSV 검증 오류가 납니다.
site_cd 형식이 뭔가요?
문서 종류별 chunk 전략은 다음처럼 나눌 수 있다.
문의/답변 데이터:
Q/A 한 건 = chunk 하나
운영 매뉴얼:
제목/소제목 기준 chunk
PDF:
페이지/섹션/표 구조 보존 후 chunk
7. 한국어 업무 RAG에서 주의할 점
한국어 업무 RAG에서는 벡터 검색만으로는 부족할 수 있다.
특히 다음과 같은 업무 용어는 정확한 키워드 매칭이 중요하다.
TID
MID
site_cd
VAN
정산
매입
취소
상점ID
터미널ID
단말기
일괄등록
벡터 검색은 의미적으로 비슷한 문서를 찾는 데 좋다. 하지만 site_cd 같은 정확한 필드명이나 코드성 키워드는 키워드 검색이 더 잘 맞을 수 있다.
따라서 검색 구조는 단계적으로 개선하는 것이 좋다.
1차 MVP:
Qdrant vector search + reranker
1.5차 개선:
로컬 BM25 추가
2차 고도화:
OpenSearch 또는 Elasticsearch 기반 hybrid search
개발속도 기준으로는 처음부터 OpenSearch까지 붙이지 않는다.
초반에는 Python에서 rank_bm25 같은 가벼운 키워드 검색을 붙이는 정도면 충분하다.
추천 검색 구조는 다음과 같다.
Qdrant top 30
+
BM25 top 30
+
중복 제거
+
reranker top 5
8. DB 구조 초안
비개발자 화면을 나중에 만들 생각이라면, DB 구조는 초반부터 최소한으로 잡아두는 것이 좋다.
TB_RAG_DOCUMENT
- DOC_ID
- TITLE
- CATEGORY
- SYSTEM_NAME
- SOURCE_TYPE
- STATUS
- FILE_HASH
- REG_ID
- REG_DT
- UPD_DT
TB_RAG_CHUNK
- CHUNK_ID
- DOC_ID
- CHUNK_NO
- CONTENT
- VECTOR_ID
- TOKEN_COUNT
- REG_DT
TB_RAG_QUERY_LOG
- QUERY_ID
- QUESTION
- ANSWER
- USED_CHUNK_IDS
- USER_ID
- REG_DT
TB_RAG_FEEDBACK
- FEEDBACK_ID
- QUERY_ID
- SCORE
- COMMENT
- REG_ID
- REG_DT
문서 상태값은 처음부터 넣어두는 것이 좋다.
DRAFT : 등록됨
INDEXED : 색인 완료
APPROVED : 서비스 반영
DISABLED : 비활성화
MVP에서는 APPROVED 상태의 문서만 검색 대상으로 사용하면 된다.
9. 2주 단위 블로그 시리즈 목차
1편. 왜 로컬 RAG를 직접 만들기로 했나
제목
Spring Boot 개발자의 로컬 RAG 파이프라인 구축기 1편: 왜 Dify가 아니라 직접 만들기로 했나
핵심 내용
- RAG를 만들게 된 배경
- 비개발자도 언젠가 쓸 수 있는 구조가 필요함
- 하지만 Dify 중심으로 가면 나중에 커스터마이징이 걱정됨
- 외부 API 비용 없이 로컬에서 돌리고 싶음
- 그래서 Headless RAG API 구조를 선택함
이 편의 결론
지금은 Dify 같은 완성형 도구보다,
FastAPI 기반 Headless RAG API를 만들고
Spring Boot에서 호출하는 구조가 더 적합하다고 판단했다.
2편. 전체 아키텍처 설계
제목
로컬 오픈소스 RAG 아키텍처 설계하기: Spring Boot + FastAPI + Qdrant + Ollama
핵심 내용
- Spring Boot와 FastAPI의 역할 분리
- Qdrant의 역할
- Ollama의 역할
- 나중에 비개발자 화면을 직접 붙일 수 있는 구조
아키텍처
[Spring Boot]
- 문의 화면
- 권한
- 사용자 관리
- 질문/답변 로그
↓ HTTP API
[FastAPI RAG Server]
- 문서 색인
- 질문 검색
- reranking
- 답변 생성
↓
[Qdrant]
- 벡터 저장
- 메타데이터 필터링
↓
[Ollama]
- 로컬 LLM 답변 생성
3편. 문의/답변 데이터를 RAG용으로 바꾸기
제목
한국어 문의/답변 데이터를 RAG용 Chunk로 설계하기
핵심 내용
- RAG 품질은 모델보다 데이터 구조가 중요함
- 문의/답변 데이터는 Q/A 단위 chunk가 적합함
- 업무 맥락을 chunk 안에 같이 넣어야 함
예시
[시스템] 파트너 관리자
[메뉴] 단말기 일괄등록
[문의유형] CSV 업로드 오류
[태그] TID, site_cd, 사이트코드, 단말기
[질문]
TID 일괄등록 시 site_cd 오류가 발생합니다.
[답변]
site_cd는 5byte이며 영문 대문자와 숫자만 허용됩니다.
CSV 업로드 전 site_cd 값에 공백, 소문자, 특수문자가 포함되어 있는지 확인해야 합니다.
4편. bge-m3로 한국어 임베딩하기
제목
bge-m3로 한국어 문의 데이터를 임베딩해보기
핵심 내용
- sentence-transformers 설치
- bge-m3 모델 로드
- 문의/답변 텍스트 임베딩
- 임베딩 벡터 차원 확인
- 샘플 데이터 100건 임베딩
예시 코드
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("BAAI/bge-m3")
texts = [
"TID 일괄등록 시 site_cd 오류가 발생합니다.",
"정산 내역이 조회되지 않습니다.",
]
embeddings = model.encode(texts, normalize_embeddings=True)
print(embeddings.shape)
이 편의 포인트
로컬에서 외부 API 비용 없이 한국어 문장을 벡터로 바꿀 수 있다.
5편. Qdrant에 벡터 저장하기
제목
Qdrant Local에 한국어 문의 데이터를 저장하고 검색하기
핵심 내용
- Docker로 Qdrant 실행
- collection 생성
- vector 저장
- payload에 문서 메타데이터 저장
- 질문 임베딩 후 유사 문서 검색
payload 예시
{
"doc_id": "DOC_001",
"chunk_id": "CHUNK_001",
"title": "TID 일괄등록 site_cd 오류",
"category": "단말기",
"system_name": "파트너관리자",
"status": "APPROVED",
"content": "site_cd는 5byte이며 영문 대문자와 숫자만 허용됩니다."
}
이 편의 포인트
벡터만 저장하지 말고,
검색 결과를 업무 화면에서 보여줄 수 있도록 메타데이터를 같이 저장해야 한다.
6편. FastAPI로 RAG 검색 API 만들기
제목
FastAPI로 /rag/query API 만들기
핵심 내용
- POST /rag/query API 생성
- 질문 입력
- 질문 임베딩
- Qdrant 검색
- 관련 문서 top 5 반환
입력 예시
{
"question": "TID 일괄등록에서 site_cd 오류가 나요"
}
출력 예시
{
"question": "TID 일괄등록에서 site_cd 오류가 나요",
"results": [
{
"docId": "DOC_001",
"title": "TID 일괄등록 site_cd 오류",
"score": 0.91,
"content": "site_cd는 5byte이며 영문 대문자와 숫자만 허용됩니다."
}
]
}
이 편의 포인트
처음부터 AI 답변을 만들지 말고,
관련 문서가 제대로 검색되는지 먼저 확인한다.
7편. 검색 품질 평가하기
제목
RAG 답변 생성 전에 검색 품질부터 평가해야 하는 이유
핵심 내용
- 답변 생성 전에 검색 품질을 먼저 확인해야 함
- LLM 문제가 아니라 검색 문제일 수 있음
- 테스트 질문 세트를 만들어 top-k 결과를 평가함
평가 기준
Top 1에 정답 문서가 있는가?
Top 3 안에 정답 문서가 있는가?
Top 5 안에 정답 문서가 있는가?
아예 못 찾는 질문은 무엇인가?
테스트 질문 예시
1. TID 일괄등록에서 site_cd 오류가 납니다.
2. 사이트코드 형식이 뭐예요?
3. 단말기 CSV 업로드가 실패합니다.
4. 정산 내역이 조회되지 않습니다.
5. 매입 취소는 언제 반영되나요?
8편. Reranker로 검색 정확도 높이기
제목
bge-reranker로 RAG 검색 결과 재정렬하기
핵심 내용
- Qdrant에서 top 30 검색
- reranker로 질문과 문서 쌍 점수화
- top 5만 LLM에 전달
구조
질문
↓
Qdrant top 30
↓
Reranker
↓
top 5
이 편의 포인트
벡터 검색은 후보를 많이 가져오는 역할,
reranker는 그중 진짜 근거 문서를 고르는 역할을 한다.
9편. BM25 키워드 검색 추가하기
제목
한국어 업무 RAG에서 Vector Search만 쓰면 부족한 이유
핵심 내용
- 한국어 업무 시스템에서는 정확한 용어 검색이 중요함
- TID, site_cd 같은 필드는 의미 검색만으로 부족할 수 있음
- BM25 키워드 검색을 같이 사용함
검색 구조
Qdrant vector search top 30
+
BM25 keyword search top 30
+
중복 제거
+
reranker top 5
이 편의 포인트
한국어 업무 시스템에서는 의미 검색뿐 아니라
정확한 필드명과 업무 용어 검색이 중요하다.
10편. Ollama로 로컬 LLM 답변 생성하기
제목
Ollama로 외부 API 비용 없이 RAG 답변 생성하기
핵심 내용
- Ollama 설치
- 로컬 LLM 모델 실행
- FastAPI에서 Ollama API 호출
- 검색된 문서를 context로 전달
- 답변 형식 고정
프롬프트 예시
너는 PG 운영 문의를 돕는 assistant다.
규칙:
1. 제공된 참고문서에 근거해서만 답변한다.
2. 참고문서에 없는 내용은 추측하지 않는다.
3. 답변은 원인, 확인방법, 조치방법 순서로 작성한다.
4. 마지막에 참고한 문서 제목을 표시한다.
사용자 질문:
{question}
참고문서:
{context}
이 편의 포인트
로컬 LLM에게 새로운 지식을 기대하지 말고,
검색된 문서를 정리해서 답변하게 만들어야 한다.
11편. Spring Boot에서 RAG API 호출하기
제목
Spring Boot에서 FastAPI RAG 서버 호출하기
핵심 내용
- Spring Boot Controller
- RestTemplate 또는 WebClient
- /rag/query 호출
- 추천 답변 표시
- 근거 문서 표시
화면 구성 예시
[사용자 질문]
[AI 추천 답변]
[근거 문서]
- TID 일괄등록 site_cd 오류
- 단말기 CSV 업로드 검증 기준
[이 답변 사용]
[수정하기]
[별로예요]
이 편의 포인트
RAG는 별도 Python 서버가 담당하고,
Spring Boot는 업무 화면과 사용자 흐름을 담당한다.
12편. 비개발자 관리 화면을 위한 설계
제목
나중에 비개발자도 쓰게 하려면 RAG 관리 화면은 어떻게 설계해야 할까?
핵심 내용
- 문서 업로드
- 문서 승인
- 문서 비활성화
- 답변 피드백
- 질문/답변 로그
- 검색 실패 케이스 관리
상태값 설계
DRAFT : 등록됨
INDEXED : 색인 완료
APPROVED : 서비스 반영
DISABLED : 비활성화
이 편의 포인트
비개발자가 쓰게 하려면 단순 업로드 화면보다
승인, 비활성화, 피드백, 로그 관리가 더 중요하다.
10. 글마다 사용할 고정 템플릿
2주마다 글을 쓰려면 글 구조를 고정하는 것이 좋다.
매번 아래 구조를 사용한다.
1. 이번 글에서 만들 것
2. 왜 이 기능이 필요한가
3. 설계
4. 구현
5. 실행 결과
6. 문제점
7. 다음 글에서 할 것
예를 들어 Qdrant 편은 다음처럼 구성할 수 있다.
1. 이번 글에서 만들 것
- Qdrant에 문의 데이터 저장하기
2. 왜 필요한가
- 임베딩만 만들면 검색할 수 없고, 저장소가 필요하다.
3. 설계
- collection 구조
- vector
- payload
4. 구현
- Docker 실행
- collection 생성
- upsert
5. 실행 결과
- 질문 입력 시 관련 문서 top 5 반환
6. 문제점
- site_cd 같은 정확한 키워드는 벡터 검색만으로 부족했다.
7. 다음 글
- 검색 품질 평가하기
11. 2주 단위 개발/발행 로드맵
1~2주차
목표:
전체 구조 정리, 기술 선택
블로그:
왜 로컬 오픈소스 RAG를 직접 만들기로 했나
3~4주차
목표:
데이터 구조 정리, Q/A chunk 설계
블로그:
문의/답변 데이터를 RAG용 chunk로 바꾸기
5~6주차
목표:
bge-m3 임베딩, Qdrant 저장
블로그:
bge-m3와 Qdrant로 한국어 문의 검색하기
7~8주차
목표:
FastAPI /rag/query API 개발
블로그:
FastAPI로 Headless RAG API 만들기
9~10주차
목표:
검색 품질 평가, 실패 케이스 분석
블로그:
RAG에서 답변보다 검색 품질을 먼저 봐야 하는 이유
11~12주차
목표:
reranker 추가
블로그:
Reranker로 한국어 RAG 검색 정확도 높이기
13~14주차
목표:
Ollama 답변 생성 추가
블로그:
외부 API 없이 로컬 LLM으로 RAG 답변 생성하기
15~16주차
목표:
Spring Boot 연동
블로그:
Spring Boot에서 로컬 RAG API 호출하기
12. 첫 번째 글 초안
아래는 1편에 바로 사용할 수 있는 초안이다.
Spring Boot 개발자의 로컬 RAG 파이프라인 구축기 1편: 왜 Dify가 아니라 직접 만들기로 했나
요즘 사내 문의응대나 운영 지식 검색에 RAG를 적용하는 사례가 많아지고 있다.
나 역시 기존 문의/답변 데이터와 운영 매뉴얼을 활용해서, 사용자가 질문하면 관련 답변 후보와 근거 문서를 찾아주는 시스템을 만들어보고 싶었다.
처음에는 Dify나 RAGFlow 같은 도구를 검토했다.
이런 도구들은 빠르게 시작할 수 있다는 장점이 있다. 문서 업로드 화면, 지식베이스 관리, 챗봇 화면, 워크플로우 구성 등을 비교적 빠르게 사용할 수 있기 때문이다.
하지만 나중에 사내 권한 체계, 문의 이력, 답변 피드백, 문서 승인 프로세스와 연결하려면 직접 제어할 수 있는 구조가 더 적합하다고 판단했다.
그래서 이번 시리즈에서는 외부 API 비용 없이, 로컬 오픈소스 기반으로 한국어 RAG 파이프라인을 직접 구축해보려고 한다.
최종 목표는 다음과 같다.
Spring Boot는 사용자 화면과 업무 흐름을 담당한다.
Python FastAPI 서버는 RAG 검색과 답변 생성을 담당한다.
벡터 저장소는 Qdrant를 사용한다.
임베딩 모델은 bge-m3를 사용한다.
로컬 LLM은 Ollama를 사용한다.
처음부터 완성형 시스템을 만들지는 않는다.
우선 문의/답변 CSV 데이터를 수동으로 색인하고, 사용자 질문에 대해 관련 문서 top 5를 반환하는 API부터 만드는 것이 목표다.
왜 Dify를 메인으로 쓰지 않기로 했나?
Dify는 비개발자가 바로 쓸 수 있는 화면이 있고, 빠르게 RAG 기반 애플리케이션을 만들 수 있다는 장점이 있다.
하지만 이번 프로젝트의 목표는 단순한 문서 챗봇이 아니다.
내가 원하는 구조는 다음과 같다.
- 사내 문의 화면과 연결
- 사용자 권한과 연결
- 질문/답변 로그 저장
- 답변 피드백 저장
- 문서 승인 프로세스 관리
- 나중에 비개발자 관리 화면 직접 개발
이런 요구사항이 있다면, 처음부터 RAG 기능을 독립적인 API 서버로 분리하는 편이 낫다고 판단했다.
선택한 구조
이번 시리즈에서 사용할 구조는 다음과 같다.
[Spring Boot]
- 사용자 화면
- 권한
- 질문/답변 로그
- 피드백 저장
↓ HTTP API
[FastAPI RAG Server]
- 문서 색인
- 질문 검색
- reranking
- 답변 생성
↓
[Qdrant Local]
- 벡터 저장
- 메타데이터 저장
↓
[Ollama]
- 로컬 LLM 실행
이 구조의 장점은 다음과 같다.
1. 외부 API 비용을 최소화할 수 있다.
2. RAG 기능을 독립적으로 개발할 수 있다.
3. Spring Boot와 연동하기 쉽다.
4. 나중에 화면을 직접 만들 수 있다.
5. 문서 승인, 로그, 피드백 같은 운영 기능을 직접 설계할 수 있다.
이번 시리즈에서 만들 것
이번 시리즈의 1차 목표는 완전한 자동응대 시스템이 아니다.
우선은 다음 기능을 만드는 것이 목표다.
1. 문의/답변 데이터를 CSV로 준비한다.
2. Q/A 단위로 chunk를 만든다.
3. bge-m3로 임베딩한다.
4. Qdrant에 저장한다.
5. 사용자가 질문하면 관련 문서 top 5를 검색한다.
6. 검색 결과를 reranker로 재정렬한다.
7. Ollama 로컬 LLM으로 답변을 생성한다.
8. Spring Boot에서 RAG API를 호출한다.
처음에는 문서 업로드 화면이나 비개발자 관리 화면은 만들지 않는다.
먼저 확인해야 할 것은 단순하다.
질문했을 때 관련 문서가 top 3 안에 나오는가?
이것이 RAG의 가장 중요한 출발점이라고 생각한다.
다음 글에서 할 것
다음 글에서는 전체 아키텍처를 조금 더 구체적으로 설계해보려고 한다.
특히 다음 내용을 다룰 예정이다.
- Spring Boot와 FastAPI의 역할 분리
- Qdrant를 벡터 저장소로 사용하는 이유
- Ollama를 로컬 LLM 실행 도구로 사용하는 이유
- 나중에 비개발자 관리 화면을 붙이기 위한 구조
13. 블로그 작성 시 주의사항
회사 업무 데이터를 그대로 블로그에 쓰면 안 된다.
반드시 다음 내용을 익명화해야 한다.
실제 상점ID 제거
실제 TID 제거
실제 MID 제거
실제 회사명 제거
실제 장애 내용 변형
실제 고객 문의 문장 변형
예시는 다음처럼 바꾼다.
실제 데이터 ❌
A상점의 MID 123456에서 정산 오류 발생
블로그용 데이터 ✅
특정 상점의 정산 내역이 조회되지 않는 상황
코드도 마찬가지다.
운영 DB 접속 정보 ❌
실제 API URL ❌
실제 파일 경로 ❌
실제 고객 데이터 ❌
블로그에는 테스트용 가짜 데이터만 사용한다.
14. 시리즈의 핵심 메시지
이 시리즈에서 계속 가져갈 핵심 메시지는 다음과 같다.
RAG는 LLM 답변 생성이 핵심이 아니라,
좋은 근거 문서를 잘 찾는 검색 시스템이다.
그리고 이번 프로젝트에서는 이 메시지도 중요하다.
비개발자 화면은 나중에 만들 수 있다.
하지만 처음부터 문서 상태, 로그, 피드백 구조는 고려해야 한다.
15. 최종 정리
이번 시리즈는 단순한 RAG 이론 정리가 아니다.
실제로 하나의 시스템을 만들어가는 개발기다.
최종 목표는 다음과 같다.
FastAPI + Qdrant + bge-m3 + Ollama로 로컬 RAG API를 만들고,
Spring Boot에서 이 API를 호출해 한국어 문의응대 추천 시스템을 구성한다.
처음에는 작게 시작한다.
CSV 수동 색인
질문 검색 API
관련 문서 top 5 반환
검색 품질 평가
이후 점진적으로 확장한다.
reranker 추가
BM25 키워드 검색 추가
Ollama 답변 생성
Spring Boot 연동
답변 로그/피드백 저장
비개발자 관리 화면 설계