RAG를 공부하다 보면 Vector DB와 Retriever라는 용어가 자주 등장합니다.
둘 다 검색과 관련된 개념이라 처음에는 비슷하게 느껴질 수 있습니다. 하지만 실제 역할은 다릅니다.
Vector DB는 검색 가능한 데이터를 저장하고 찾는 저장소이고, Retriever는 사용자 질문에 맞는 문서를 가져오는 검색 인터페이스입니다.
쉽게 말하면 Vector DB는 문서 조각이 저장된 장소에 가깝고, Retriever는 그 안에서 질문과 관련된 문서를 찾아오는 역할에 가깝습니다.
이번 글에서는 Vector DB와 Retriever의 차이, Top-k, Metadata filtering, Similarity Search, MMR 같은 RAG 검색 관련 개념을 쉽게 정리해보겠습니다.
RAG 흐름에서 Vector DB와 Retriever의 위치
먼저 RAG 전체 흐름에서 Vector DB와 Retriever가 어디에 있는지 보겠습니다.
문서 Chunk
→ Embedding
→ Vector
→ Vector DB 저장
사용자 질문
→ Embedding
→ 질문 Vector
→ Retriever
→ Vector DB 검색
→ 관련 Chunk 반환
→ Context 구성
→ LLM 답변
여기서 Vector DB는 문서 Chunk의 Vector, 원문 content, metadata를 저장하고 검색할 수 있게 해주는 역할을 합니다.
Retriever는 사용자의 질문을 받아 관련 문서를 찾아오는 역할을 합니다.

Vector DB란?
Vector DB는 임베딩을 통해 만들어진 Vector를 저장하고, 질문 Vector와 비슷한 문서 Vector를 찾아주는 저장소입니다.
일반적인 데이터 저장 예시는 다음과 같습니다.
id: 1
title: 연차 신청 방법
content: 연차 신청은 HR 시스템에서 진행한다.
Vector DB는 여기에 임베딩 결과인 Vector와 metadata를 함께 저장합니다.
id: attendance_001
content:
연차 신청은 HR 시스템 > 근태관리 > 휴가신청 메뉴에서 진행한다.
vector:
[0.15, -0.21, 0.03, 0.88, ...]
metadata:
source: 회사_근태_매뉴얼.pdf
page: 12
category: 근태
즉, Vector DB는 단순히 텍스트만 저장하는 것이 아니라, 텍스트의 의미를 표현한 Vector를 함께 저장합니다.
Vector DB가 문장을 Vector로 바꾸는 것은 아닙니다. 문장을 Vector로 바꾸는 작업은 Embedding 모델이 담당하고, Vector DB는 그 결과를 저장하고 검색합니다.
Vector DB에는 무엇이 저장될까?
Vector DB에는 보통 다음 정보들이 저장됩니다.
| 저장 항목 | 설명 |
|---|---|
| id | 각 문서 Chunk를 구분하는 값 |
| content | 원래 문서 Chunk 내용 |
| vector | Embedding 결과로 만들어진 숫자 배열 |
| metadata | 출처, 페이지, 카테고리, 날짜 같은 부가 정보 |
여기서 중요한 점은 Vector만 저장해서는 RAG 답변을 만들기 어렵다는 것입니다.
LLM이 최종 답변을 만들려면 실제 문서 내용인 content가 필요합니다. 또한 답변의 출처를 표시하거나 검색 범위를 제한하려면 metadata가 필요합니다.
그래서 Vector DB는 보통 Vector, 원문 content, metadata를 함께 관리합니다.
Vector DB는 어떤 검색을 할까?
Vector DB는 일반적인 문자열 검색이 아니라, 보통 유사도 검색을 수행합니다.
예를 들어 Vector DB에 다음과 같은 문서 Chunk가 저장되어 있다고 가정해보겠습니다.
Chunk A:
연차 신청은 HR 시스템 > 근태관리 > 휴가신청 메뉴에서 진행한다.
Chunk B:
서버 장애 발생 시 로그를 먼저 확인한다.
Chunk C:
급여는 매월 25일에 지급된다.
사용자가 다음과 같이 질문합니다.
휴가는 어디서 등록해?
이 질문은 Embedding 모델을 통해 질문 Vector로 변환됩니다.
질문 Vector:
[0.14, -0.19, 0.05, 0.82, ...]
Vector DB는 이 질문 Vector와 가장 가까운 문서 Vector를 찾습니다.
1위: Chunk A - 연차 신청은 HR 시스템 > 근태관리 > 휴가신청 메뉴에서 진행한다.
2위: Chunk C - 급여는 매월 25일에 지급된다.
3위: Chunk B - 서버 장애 발생 시 로그를 먼저 확인한다.
사용자의 질문이 휴가나 연차 신청과 관련 있으므로, Chunk A가 가장 관련성이 높은 결과로 나올 수 있습니다.
Top-k란?
Vector DB나 Retriever를 설정할 때 자주 나오는 개념이 Top-k입니다.
Top-k는 검색 결과를 상위 몇 개 가져올지 정하는 설정입니다.
예를 들어 다음과 같이 설정했다고 해보겠습니다.
k = 3
그러면 질문과 관련성이 높은 문서 Chunk 3개를 가져옵니다.
1위 Chunk
2위 Chunk
3위 Chunk
k가 너무 작으면?
예를 들어 k를 1로 설정하면 가장 관련성이 높은 Chunk 하나만 가져옵니다.
k = 1
이 경우 불필요한 정보는 적지만, 필요한 정보가 하나의 Chunk에 모두 들어 있지 않으면 답변이 부족해질 수 있습니다.
k가 너무 크면?
반대로 k를 10으로 설정하면 검색 결과를 많이 가져옵니다.
k = 10
이 경우 관련 정보를 더 많이 포함할 수 있지만, 관련 없는 정보까지 섞일 가능성도 커집니다.
Context가 길어지면서 비용이 늘어나고, LLM이 불필요한 정보 때문에 핵심을 놓칠 수도 있습니다.
Top-k는 무조건 클수록 좋은 값이 아니라, 필요한 정보와 불필요한 정보 사이의 균형을 잡는 설정입니다.
Metadata filtering이란?
Metadata filtering은 문서의 부가 정보를 기준으로 검색 범위를 제한하는 방식입니다.
Vector DB에는 content와 vector뿐만 아니라 metadata도 함께 저장된다고 했습니다.
예를 들어 다음과 같은 문서들이 있다고 해보겠습니다.
Chunk 1:
content: 연차 신청은 HR 시스템에서 진행한다.
metadata: {category: "근태", year: 2026}
Chunk 2:
content: 급여는 매월 25일에 지급된다.
metadata: {category: "급여", year: 2026}
Chunk 3:
content: 2024년 연차 신청 방식은 그룹웨어를 사용한다.
metadata: {category: "근태", year: 2024}
사용자가 이렇게 질문합니다.
2026년 연차 신청은 어디서 해?
이때 단순 유사도 검색만 하면 2024년 문서도 함께 검색될 수 있습니다.
그래서 metadata 조건을 걸 수 있습니다.
category = "근태"
year = 2026
그러면 검색 범위가 줄어듭니다.
2026년 근태 문서 안에서만 유사도 검색
이렇게 metadata filtering을 사용하면 source, category, year, page 같은 정보를 기준으로 검색 범위를 제한할 수 있습니다.
결과적으로 질문과 맞지 않는 문서를 줄이고, 더 정확한 검색 결과를 얻는 데 도움이 됩니다.
Retriever란?
Retriever는 사용자 질문을 받아 관련 문서를 반환하는 검색 인터페이스입니다.
쉽게 말하면, 사용자의 질문에 맞는 문서를 찾아오는 역할입니다.
사용자 질문
→ Retriever
→ 관련 Document 목록 반환
예를 들어 사용자가 이렇게 묻는다고 해보겠습니다.
연차 신청은 어디서 해?
Retriever는 관련 문서를 찾아 반환합니다.
[
Document(
page_content="연차 신청은 HR 시스템 > 근태관리 > 휴가신청 메뉴에서 진행한다.",
metadata={page: 12}
),
Document(
page_content="휴가 신청은 팀장 승인 후 완료된다.",
metadata={page: 13}
)
]
Retriever는 LLM처럼 직접 답변을 생성하지 않습니다.
Retriever의 역할은 LLM이 답변을 만들 수 있도록 답변 재료가 되는 문서를 찾아오는 것입니다.
Retriever는 꼭 Vector DB만 사용할까?
아닙니다. Retriever는 Vector DB보다 더 넓은 개념입니다.
Retriever는 사용자 질문에 맞는 정보를 가져오는 인터페이스이기 때문에, 내부 구현은 다양할 수 있습니다.
- Vector DB 검색
- 키워드 검색
- SQL 조회
- Elasticsearch 검색
- API 호출
- 웹 검색
- 하이브리드 검색
예를 들어 질문에 따라 적합한 검색 방식이 달라질 수 있습니다.
| 질문 | 적합한 검색 방식 |
|---|---|
| 연차 신청 방법 알려줘 | Vector DB 기반 Retriever |
| 내 남은 연차 며칠이야? | SQL 기반 Retriever |
| 오늘 환율 알려줘 | API 기반 Retriever |
| 청년미래적금 문서 찾아줘 | 키워드 검색 기반 Retriever |
따라서 Retriever를 단순히 Vector DB와 같은 의미로 보면 안 됩니다.
Retriever는 Vector DB를 사용할 수 있지만, Vector DB 그 자체는 아닙니다.
Vector DB와 Retriever의 차이
Vector DB와 Retriever를 비교하면 다음과 같습니다.
| 구분 | Vector DB | Retriever |
|---|---|---|
| 역할 | Vector 저장 및 유사도 검색 | 질문에 맞는 문서 반환 |
| 범위 | 저장소와 검색 엔진에 가까움 | 검색 인터페이스에 가까움 |
| 입력 | Vector 또는 검색 Query | 사용자 Query |
| 출력 | 유사한 문서 Chunk 또는 검색 결과 | Document 목록 |
| 내부 구현 | Chroma, FAISS, Pinecone, Qdrant 등 | Vector DB, SQL, API, 키워드 검색 등 |
| RAG에서 역할 | 검색 가능한 지식 저장소 | LLM에게 줄 Context 후보를 가져옴 |
쉽게 비유하면 다음과 같습니다.
Vector DB = 도서관 서고
Retriever = 필요한 책을 찾아오는 사서
LLM = 사서가 찾아준 책을 읽고 답변하는 사람
LangChain에서는 Vector Store를 Retriever로 사용할 수 있다
LangChain에서는 Vector Store를 Retriever 형태로 감싸서 사용할 수 있습니다.
개념적으로는 다음과 같은 코드 형태입니다.
retriever = vector_store.as_retriever(search_kwargs={"k": 3})
이렇게 하면 Vector Store를 직접 다루기보다 Retriever 인터페이스를 통해 검색할 수 있습니다.
docs = retriever.invoke("연차 신청은 어디서 해?")
흐름은 다음과 같습니다.
사용자 질문
→ retriever.invoke()
→ 내부적으로 Vector Store 검색
→ 관련 Document 반환
즉, Retriever는 LLM Chain이나 Agent가 사용하기 좋은 형태의 검색 인터페이스가 됩니다.
Retriever가 반환한 결과는 어디로 갈까?
Retriever가 반환한 Document는 보통 Context로 묶여 Prompt에 들어갑니다.
예를 들어 Retriever가 다음 문서를 반환했다고 해보겠습니다.
Document 1:
연차 신청은 HR 시스템 > 근태관리 > 휴가신청 메뉴에서 진행한다.
Document 2:
휴가 신청은 팀장 승인 후 완료된다.
이 결과는 Prompt에 다음과 같이 들어갈 수 있습니다.
아래 Context를 참고해서 질문에 답변하세요.
Context:
연차 신청은 HR 시스템 > 근태관리 > 휴가신청 메뉴에서 진행한다.
휴가 신청은 팀장 승인 후 완료된다.
Question:
연차 신청은 어디서 해?
그다음 LLM은 Context를 참고해 답변을 생성합니다.
연차 신청은 HR 시스템의 근태관리 > 휴가신청 메뉴에서 진행할 수 있습니다.
정리하면 다음과 같습니다.
Retriever = Context 후보를 가져옴
Prompt = Context와 질문을 묶음
LLM = 최종 답변 생성
Similarity Search와 Retriever는 같은 말일까?
Similarity Search와 Retriever도 비슷해 보일 수 있지만 정확히는 다릅니다.
Similarity Search는 Vector DB에서 질문 Vector와 가까운 문서 Vector를 찾는 검색 방식입니다.
질문 Vector와 가까운 문서 Vector 검색
반면 Retriever는 사용자 질문을 받아 관련 Document 목록을 반환하는 인터페이스입니다.
질문을 받아 관련 Document 목록 반환
Retriever 내부에서 Similarity Search를 사용할 수 있습니다.
Retriever
→ Similarity Search 실행
→ 관련 Document 반환
하지만 Retriever가 항상 Similarity Search만 사용하는 것은 아닙니다. SQL, 키워드 검색, API 호출 같은 다른 방식도 사용할 수 있습니다.
MMR이란?
Retriever 설정을 보다 보면 MMR이라는 개념도 나옵니다.
MMR은 Maximal Marginal Relevance의 줄임말입니다.
쉽게 말하면, 관련성은 유지하면서 너무 비슷한 결과만 반복해서 가져오지 않도록 하는 방식입니다.
예를 들어 사용자가 이렇게 질문했다고 해보겠습니다.
연차 신청 방법 알려줘
단순 유사도 검색 결과가 다음과 같을 수 있습니다.
1. 연차 신청은 HR 시스템에서 진행한다.
2. 연차 신청은 HR 시스템에서 가능하다.
3. 연차 신청 메뉴는 HR 시스템에 있다.
세 결과가 거의 같은 내용입니다.
MMR은 관련성을 유지하면서 조금 더 다양한 결과를 가져오도록 도와줍니다.
1. 연차 신청은 HR 시스템에서 진행한다.
2. 휴가 신청은 팀장 승인 후 완료된다.
3. 반차 신청도 동일 메뉴에서 가능하다.
즉, MMR은 관련 있는 결과를 가져오되, 중복된 내용만 반복해서 가져오지 않도록 하는 검색 방식입니다.
Vector DB 종류
RAG에서 사용할 수 있는 Vector DB 또는 Vector Store는 여러 종류가 있습니다.
- Chroma
- FAISS
- Pinecone
- Qdrant
- Weaviate
- Milvus
- PGVector
- Elasticsearch Vector Search
- InMemoryVectorStore
처음 공부할 때는 로컬에서 가볍게 사용할 수 있는 Chroma, FAISS, InMemoryVectorStore 같은 도구로 시작해도 충분합니다.
실무 서비스에서는 데이터 규모, 검색 성능, 메타데이터 필터링, 운영 편의성, 비용 등을 기준으로 Vector DB를 선택해야 합니다.
| 종류 | 특징 |
|---|---|
| InMemoryVectorStore | 메모리에 저장하는 방식으로 간단한 실습에 적합 |
| FAISS | 로컬 실습에 많이 사용되는 Vector Search 라이브러리 |
| Chroma | 개발 및 로컬 실습에서 자주 사용되는 Vector Store |
| Qdrant | 서버형 또는 서비스형으로 사용할 수 있는 Vector Search 엔진 |
| Pinecone | 관리형 Vector DB 서비스 |
| PGVector | PostgreSQL에서 Vector 검색을 사용할 수 있게 해주는 확장 |
개발자 관점에서 보는 저장과 검색 흐름
개발자 관점에서는 Vector DB와 Retriever를 저장 단계와 질문 단계로 나누어 보면 이해하기 쉽습니다.
저장 단계
1. 문서 원본을 읽는다.
2. Document로 변환한다.
3. Chunk로 나눈다.
4. 각 Chunk를 Embedding한다.
5. Vector, content, metadata를 Vector DB에 저장한다.
예를 들면 다음과 같습니다.
Chunk:
연차 신청은 HR 시스템 > 근태관리 > 휴가신청 메뉴에서 진행한다.
Vector:
[0.15, -0.21, 0.03, 0.88, ...]
Metadata:
source: 회사_근태_매뉴얼.pdf
page: 12
질문 단계
1. 사용자 질문을 받는다.
2. 질문을 Embedding한다.
3. Retriever가 질문에 맞는 Document를 검색한다.
4. 내부적으로 Vector DB에서 유사도 검색을 수행할 수 있다.
5. 관련 Document를 반환한다.
6. Document 내용을 Context로 만든다.
7. Context와 질문을 Prompt에 넣는다.
8. LLM이 답변한다.
예시: 블로그 작성 가이드 RAG
블로그 작성 가이드를 RAG에 넣는다고 가정해보겠습니다.
Vector DB에 다음과 같은 Chunk가 저장되어 있습니다.
content:
청년정책 글은 신청 대상, 신청 기간, 지원 내용, 신청 방법, 유의사항 순서로 작성한다.
metadata:
category: "청년정책"
source: "blog_guideline.md"
사용자가 질문합니다.
청년미래적금 글은 어떤 순서로 쓰면 돼?
Retriever는 내부적으로 Vector DB를 검색합니다.
질문 Vector와 가까운 Chunk 검색
→ 청년정책 글 작성 순서 Chunk 반환
Prompt에는 다음과 같이 들어갑니다.
Context:
청년정책 글은 신청 대상, 신청 기간, 지원 내용, 신청 방법, 유의사항 순서로 작성한다.
Question:
청년미래적금 글은 어떤 순서로 쓰면 돼?
LLM은 Context를 참고해 답변합니다.
청년미래적금 글은 신청 대상, 신청 기간, 지원 내용, 신청 방법, 유의사항 순서로 구성하면 좋습니다.
이 예시에서 역할을 나누면 다음과 같습니다.
Vector DB = 청년정책 작성 가이드 Chunk 저장
Retriever = 질문에 맞는 Chunk 검색
LLM = 검색된 가이드를 바탕으로 답변 작성
정리
이번 글에서는 Vector DB와 Retriever의 역할을 정리했습니다.
- Vector DB는 임베딩된 문서 Chunk의 Vector, 원문 content, metadata를 저장하는 저장소입니다.
- Vector DB는 질문 Vector와 가까운 문서 Vector를 찾아 유사도 검색을 수행합니다.
- Retriever는 사용자 질문을 받아 관련 Document를 반환하는 검색 인터페이스입니다.
- Retriever는 Vector DB보다 더 넓은 개념입니다.
- Retriever는 Vector DB뿐 아니라 SQL, 키워드 검색, API, 웹 검색 등도 사용할 수 있습니다.
- Top-k는 검색 결과를 몇 개 가져올지 정하는 설정입니다.
- Metadata filtering은 source, category, year 같은 조건으로 검색 범위를 제한하는 방식입니다.
- MMR은 관련성을 유지하면서 중복을 줄이고 다양한 결과를 가져오는 검색 방식입니다.
한 문장으로 정리하면 다음과 같습니다.
Vector DB는 의미 기반 검색을 위해 Vector를 저장하는 저장소이고, Retriever는 사용자 질문에 맞는 문서를 찾아 LLM에게 전달할 Context 후보를 가져오는 검색 인터페이스입니다.
다음 글에서는 RAG 구현을 쉽게 도와주는 프레임워크인 LangChain을 살펴보겠습니다.