
RAG의 Embedding과 Vector Database: 문서를 '검색 가능한 형태'로 만드는 메커니즘
요약
RAG 시스템에서 문서를 검색 가능한 형태로 만드는 핵심 요소인 임베딩과 벡터 데이터베이스의 역할을 설명합니다. 텍스트를 수치화하는 임베딩 모델과 이를 메타데이터와 함께 저장하는 벡터 데이터베이스의 차이점을 다룹니다.
핵심 포인트
- 임베딩은 텍스트를 의미 기반의 수치 벡터로 변환하는 프로세스입니다.
- 벡터 데이터베이스는 벡터, 텍스트, 메타데이터를 저장하고 관리하는 저장소입니다.
- RAG는 문서와 쿼리를 모두 벡터화하여 의미적 유사성을 비교합니다.
- 임베딩을 통해 단어의 완전 일치가 아닌 의미적 연결이 가능해집니다.
RAG 시스템이 문서 청크 (chunk)를 검색할 수 있게 되려면, 우선 두 가지가 필요합니다.
첫 번째는 텍스트를 벡터 (vector)로 변환하는 방법입니다. 이것이 **embedding (임베딩)**의 역할입니다.
텍스트 chunk
↓
embedding model
...
예를 들어, 다음과 같습니다.
"New employees are eligible for ten days of paid leave."
↓
[0.12, -0.03, 0.44, ..., 0.08]
실제 벡터는 embedding model에 따라 수백 차원에서 수천 차원이 될 수 있습니다. 인간이 이 수치들을 직접 읽는 것은 아닙니다.
두 번째는 그 벡터들을 원래 텍스트에 관한 유용한 정보, 즉 metadata (메타데이터)와 함께 저장할 장소입니다. metadata에는 원본 문서, section (섹션), language (언어), version (버전), permission level (권한 수준) 등의 정보를 포함할 수 있습니다.
벡터와 metadata를 저장하는 것이 **vector database (벡터 데이터베이스)**의 역할입니다.
vector
+ metadata
+ chunk text 또는 chunk text에 대한 pointer (포인터)
...
이 두 역할은 서로 연결되어 있지만, 동일한 것은 아닙니다.
| 개념 | 역할 |
|---|---|
| Embedding | 텍스트를 벡터 표현으로 변환한다 |
| Vector database | 나중에 검색할 수 있도록 벡터, 텍스트 또는 pointer, metadata를 저장한다 |
핵심적인 질문은 다음과 같습니다.
문서 청크를 어떻게 벡터 표현으로 변환하고, 그 표현을 나중에 검색할 수 있도록 저장하는가?
다음과 같은 chunk가 있다고 가정해 봅시다.
New employees are eligible for ten days of paid leave after probation.
사용자는 다음과 같이 질문할 수도 있습니다.
How much annual leave can a new hire take?
의미는 관련이 있지만, 사용된 표현은 다릅니다.
| Chunk wording | Query wording |
|---|---|
| new employees | new hire |
| ... |
시스템이 텍스트를 단어의 완전 일치로만 취급할 경우, 유용한 연결 고리를 놓칠 가능성이 있습니다. 따라서 RAG에는 관련된 의미를 수치로서 비교하기 쉽게 만드는 표현이 필요합니다.
여기서 첫 번째 문제가 되는 것은 representation (표현)입니다.
의미를 가진 텍스트
↓
수치적으로 비교 가능한 vector
이 변환을 제공하는 것이 embedding입니다.
embedding model은 텍스트를 벡터 표현으로 변환합니다. embedding이라는 용어는 변환 프로세스와 그 결과로 얻어지는 벡터 모두를 지칭하는 데 사용되기도 합니다. 이 글에서는 역할을 명확히 하기 위해 다음과 같이 구분합니다.
embedding model = 변환기
vector = 변환기에 의해 만들어지는 수치 표현
예를 들어, 다음과 같습니다.
"New employees can take ten days of paid leave."
↓
[0.12, -0.03, 0.44, ..., 0.08]
다시 말씀드리지만, 실제 벡터는 embedding model에 따라 수백 차원에서 수천 차원이 될 수 있습니다. 인간이 이 수치들을 직접 읽는 것은 아닙니다.
RAG에서는 문서 청크와 사용자 쿼리 (query) 모두를 embedding model로 벡터화합니다. 문서 청크의 벡터는 저장됩니다. 반면, 쿼리 벡터는 저장된 문서 벡터와 비교할 수 있도록 생성됩니다.
단, embedding을 완전한 이해로 취급해서는 안 됩니다. embedding은 학습된 수치 표현입니다. 관련된 텍스트를 벡터 공간상에서 가깝게 배치하는 경우는 흔하지만, 관련이 있다는 것이 반드시 사용자의 질문에 대해 정답이라는 것을 의미하지는 않습니다.
예를 들어, 다음과 같은 경우입니다.
정규직 직원을 위한 유급 휴가 정책
계약직 직원을 위한 유급 휴가 정책
이들은 의미상으로는 유사할 수 있지만, 서로 대체하여 다룰 수는 없습니다. 사용자가 정규직 직원(full-time employees)에 대해 질문하고 있다면, 계약직 정책(contractor policy)은 잘못된 근거가 될 가능성이 있습니다.
따라서 멘탈 모델(mental model)은 다음과 같습니다.
- 임베딩 (embedding)은 의미적 유사성을 비교하는 것을 돕는다
- 임베딩 (embedding)은 사실로서의 정확성을 보장하지 않는다
흔히 하는 오해는 임베딩 모델 (embedding model)과 LLM을 동일한 것으로 취급하는 것입니다. 이들은 서로 다른 구성 요소입니다.
| 구성 요소 | 입력 | 출력 | RAG에서의 역할 |
|---|---|---|---|
| 임베딩 모델 (Embedding model) | 텍스트 (Text) | 벡터 (Vector) | 비교할 수 있도록 텍스트를 표현함 |
| LLM / 생성 모델 (generation model) | 프롬프트 (Prompt) | 텍스트 답변 (Text answer) | 최종 답변을 생성함 |
임베딩 모델 (embedding model)은 질문에 답하는 것이 아닙니다. 나중에 유용한 정보를 찾을 수 있도록 벡터 표현을 준비하는 것입니다.
이 구분이 중요한 이유는, 아무리 강력한 LLM이라 하더라도 불충분한 표현이나 저장 설계의 문제를 완전히 수정할 수 없기 때문입니다. 관련 청크 (chunk)가 검색 가능한 형태로 표현 및 저장되어 있지 않다면, 그것들은 생성 단계 (generation step)까지 도달하지 못할 가능성이 있습니다.
임베딩 모델 (embedding model)의 사용 예시:
- Hugging Face: Using Sentence Transformers:
sentence-transformers가 텍스트의 밀집 벡터 표현 (dense vector representation)을 어떻게 계산하는지 보여줍니다. - LlamaIndex: Embeddings: 인덱싱 (indexing)과 쿼리 (querying) 과정에서 RAG 프레임워크 내부의 임베딩이 어떻게 사용되는지 보여줍니다.
문서 청크 (document chunk)는 저장하기 전에 임베딩 모델 (embedding model)을 통해 벡터화됩니다. 사용자의 쿼리 (query)는 쿼리 시점 (query time)에 벡터화됩니다. 벡터 검색 (vector search)이 작동하려면 이 두 종류의 벡터가 비교 가능해야 합니다. 이것이 **호환 가능한 임베딩 공간 (compatible embedding space)**의 개념입니다.
여기서 호환성 (compatibility)이란, 문서 청크와 사용자 쿼리 모두에 동일한 임베딩 모델 (embedding model)을 사용하는 것을 의미합니다.
좋은 예:
문서 청크 (document chunk) → 임베딩 모델 A (embedding model A) → 벡터 (vector)
사용자 쿼리 (user query) → 임베딩 모델 A (embedding model A) → 벡터 (vector)
일반적인 오류:
문서 청크 (document chunk) → 임베딩 모델 A (embedding model A) → 벡터 (vector)
사용자 쿼리 (user query) → 임베딩 모델 B (embedding model B) → 벡터 (vector)
무관한 모델로부터 얻은 벡터는, 호환 가능한 벡터 (compatible vector)를 생성하도록 명시적으로 설계되지 않는 한, 일반적으로 의미 있는 방식으로 비교할 수 없습니다. 차원 수 (dimension), 학습 목표 (training objective), 벡터 공간 구조 (vector-space structure)가 다를 수 있기 때문입니다.
많은 시스템에서 모델을 변경한다는 것은 다음과 같은 작업이 필요할 수 있음을 의미합니다.
- 기존 청크 (chunk)를 재임베딩 (re-embed) 하기
- 저장된 벡터 업데이트하기
- 벡터 인덱스 (vector index) 재구축 또는 업데이트하기
- 임베딩 모델 버전 (embedding model version) 기록하기
실용적인 저장 설계 (storage design)에서는 다음과 같은 메타데이터 (metadata)를 유지해야 합니다.
embedding_model = text-embedding-model-x
embedding_version = 2026-04
vector_dimension = 1024
이를 통해 추후 유지보수 (maintenance)와 디버깅 (debugging)이 용이해집니다.
문서 청크 (chunk)와 쿼리 (query)가 동일한 임베딩 공간 (embedding space) 내의 벡터 (vector)로 표현되면, 시스템에는 이 벡터들을 비교할 규칙이 필요합니다. 그 규칙은 유사도 측정 (similarity measure) 또는 **거리 지표 (distance metric)**일 수 있습니다.
일반적인 벡터 비교 측정 방식 (vector comparison measure)에는 다음과 같은 것들이 있습니다.
| 비교 방법 | 대략적인 개념 |
|---|---|
| 코사인 유사도 (Cosine similarity) | 방향을 비교함 |
| ... |
주의: 벡터 비교 측정 방식 (vector comparison measure)이 항상 서로 대체 가능한 것은 아닙니다.
일부 임베딩 모델 (embedding model)은 특정 비교 방식을 전제로 설계되었거나 권장되기도 합니다. 또한, 일부 구성에서는 **벡터 정규화 (vector normalization)**가 필요합니다. 이는 대략적으로 말해, 비교하기 전에 벡터의 길이를 조정하는 것을 의미합니다.
벡터 검색 라이브러리 (vector search library)의 예로 FAISS: MetricType and distances가 있습니다. 이 페이지에서는 L2 거리 (L2 distance)와 내적 (inner product)을 설명하며, 내적 검색 (inner-product search) 전에 벡터를 정규화 (normalization)함으로써 코사인 유사도 (cosine similarity)를 구현할 수 있음을 보여줍니다.
청크 (chunk)가 벡터로 변환된 후에는 시스템에 이를 저장할 장소가 필요합니다. **벡터 데이터베이스 (vector database)**는 다수의 검색 가능한 레코드 (record)를 저장하고 관리합니다.
각 레코드 (record)는 통상적으로 하나의 청크 단위 (chunk-level unit)를 포함합니다.
record_001
chunk_id
vector
...
이러한 레코드 (record)가 다수 존재합니다.
vector database
record_001
record_002
...
데이터베이스 (database)가 이러한 레코드 (record)만을 가지고 있는 경우에도, 쿼리 벡터 (query vector)를 저장된 각 벡터와 하나씩 비교하면 검색은 가능합니다. 하지만 이는 속도가 느립니다.
query vector
↓
record_001의 vector와 비교
...
따라서 벡터 데이터베이스 (vector database)는 **벡터 인덱스 (vector index)**를 구축하기도 합니다. 벡터 인덱스 (vector index)란 다수의 레코드 (record)에 포함된 벡터 (vector) 군을 대상으로 만들어지는 검색 구조입니다. 그 역할은 쿼리 벡터 (query vector)를 저장된 모든 벡터와 매번 하나씩 비교하지 않고도, 가까운 벡터를 효율적으로 찾아내는 것입니다.
사용자의 쿼리
↓
query vector
...
벡터 인덱스 (vector index)의 구현 예로 FAISS: Getting started가 있습니다. 여기서는 벡터 인덱스 (vector index)를 생성하고, 벡터를 추가하며, 최근접 벡터 검색 (nearest-vector search)을 실행하는 흐름을 보여줍니다.
소규모 데이터셋 (dataset)에서는 시스템이 쿼리 벡터 (query vector)와 모든 저장된 벡터를 직접 비교하기도 합니다. 더 대규모인 데이터셋 (dataset)에서는 벡터 인덱스 (vector index)를 통해 모든 벡터를 순차적으로 조사하는 느린 처리를 피하기 쉬워집니다.
구체적인 구현 예:
- Qdrant: Points는 ID, vector, payload를 가진 레코드 (record)를 나타냅니다.
- FAISS 공식 문서 (official documentation)는 FAISS를 vector-search/index 라이브러리로 제시합니다.
- Qdrant: Payload는 메타데이터 (metadata)와 같은 필드 (field)를 payload로 나타냅니다.
임베딩 모델 (embedding model)의 선택은 지금까지 다룬 역할들, 즉 벡터 표현 (vector representation), 호환성 (compatibility), 비교 (comparison), 저장 (storage), 인덱스 (index), 메타데이터 (metadata)와 관련이 있습니다.
임베딩 모델 (embedding model)의 선택은 텍스트가 벡터로 어떻게 표현되는지에 영향을 미칩니다. 유용한 질문은 "어떤 모델이 유명한가"가 아니라, "어떤 모델이 이 시스템의 문서, 쿼리, 제약 조건에 적합한가"입니다.
문서와 쿼리가 모두 영어라면, 많은 모델이 어느 정도 잘 작동할 가능성이 있습니다. 하지만 시스템이 일본어, 중국어, 영어 또는 여러 언어가 혼재된 사용 사례를 포함하는 경우, 언어 지원 (language support)은 핵심적인 요소가 됩니다.
예시:
Japanese document:
新入社員は試用期間後に有給休暇を10日取得できます。
English query:
...
시스템이 이 두 가지를 연결해야 하는 경우, 임베딩 모델 (embedding model)에는 뛰어난 다국어 (multilingual) 또는 교차 언어 (cross-lingual) 동작 능력이 필요합니다. BGE-M3는 다국어 임베딩 모델 (multilingual embedding model)의 한 예입니다. 여기서 중요한 기준은 특정 모델을 반드시 사용해야 한다는 것이 아니라, 언어 커버리지 (language coverage)가 실제로 모델 선택 (model selection)의 요소가 된다는 점입니다.
구체적인 다국어 모델 출처:
- BGE-M3 documentation — 모델 선택 (model selection)의 기준으로 언어 커버리지 (language coverage)와 최대 입력 길이 (maximum input length)를 확인하는 데 유용합니다.
- BGE-M3 paper: M3-Embedding — 모델의 다국어 설계 (multilingual design)에 관한 기술적 출처로서 유용합니다.
임베딩 모델 (embedding model)에는 입력 길이의 상한선이 있습니다. 이는 해당 모델이 한 번에 처리할 수 있는 텍스트 양의 상한을 의미합니다.
청크 (chunk)가 너무 길면 중요한 정보가 약하게 표현되거나 잘려 나갈 수 있습니다. 청크가 너무 짧으면 충분한 문맥 (context)을 포함하지 못할 수 있습니다. 임베딩 모델은 받은 입력 (input)만을 표현할 수 있습니다.
요약하자면 다음과 같습니다.
bad chunking → weak vector representation
소스 코드 (source code), API 문서 (API documentation), 법률 계약서 (legal contracts), 의료 문서 (medical documents), 재무 보고서 (financial reports), 내부 매뉴얼 (internal manuals) 등 일부 도메인 (domain)에는 전문 용어가 포함되어 있습니다. 일반적인 임베딩 모델 (general embedding model)로도 작동하는 경우가 있지만, 도메인 특화 어휘 (domain-specific vocabulary)는 표현 문제 (representation problem)를 일으킬 수 있습니다.
예를 들어 소프트웨어 문서 (software documentation)에서는 함수 이름 (function name), 에러 코드 (error code), 클래스 이름 (class name), 설정 키 (configuration key) 등 정확한 단어가 중요할 수 있습니다. 밀집 임베딩 (dense embedding)은 텍스트를 학습된 수치 벡터 (numerical vector)로 표현합니다. 의미적 유사성을 다루는 데는 유용하지만, 정확한 어휘적 세부 사항 (exact lexical details)을 항상 충분히 유지할 수 있는 것은 아닙니다.
이것이 임베딩을 피해야 하는 이유는 아닙니다. 임베딩이 어떤 표현 문제 (representation problem)를 해결할 수 있고, 어떤 문제를 해결할 수 없는지 이해해야 하는 이유입니다.
임베딩은 두 가지 서로 다른 시점에 수행됩니다.
- **인덱싱 시점 (Indexing time)**은 사용자가 질문하기 전에 문서 청크 (document chunk)를 임베딩하여 저장할 준비를 하는 단계를 의미합니다. 문서 청크의 벡터는 벡터 데이터베이스 (vector database)에 저장됩니다.
- **쿼리 시점 (Query time)**은 사용자가 질문하는 순간을 의미합니다. 쿼리 벡터 (query vector)는 보통 저장된 문서 벡터 (document vector)와 비교할 수 있도록 쿼리 시점에 일시적으로 생성됩니다.
지식 베이스 (knowledge base)가 크거나 빈번하게 업데이트되는 경우, 인덱싱 시점 비용 (indexing-time cost)이 중요해집니다. 사용자가 기다리고 있기 때문에 쿼리 시점 지연 시간 (query-time latency) 또한 중요합니다. 따라서 임베딩 모델은 표현 품질 (representation quality), 인덱싱 비용 (indexing cost), 쿼리 시점 지연 시간 (query-time latency)에 영향을 미칩니다.
일부 임베딩 모델 (embedding model)은 쿼리 (query)와 문서 (document)에 대해 특정 접두사 (prefix)나 인코딩 방법 (encoding method)을 권장합니다. 예를 들어, 사용자 질문 (user question)에는 query:를, 문서 청크 (document chunk)에는 passage:를 붙이는 방식입니다.
이는 모델마다 다릅니다. 실무적인 규칙은 간단합니다. 모든 텍스트를 동일한 원시 형식 (raw format)으로 임베딩 (embedding)해야 한다고 가정하지 말고, 임베딩 모델의 문서 (documentation)를 따르십시오.
모델별 입력 형식 (model-specific input format)의 예:
- Sentence Transformers: Computing Embeddings는
encode(),query:및passage:와 같은 모델별 프롬프트 템플릿 (model-specific prompt template), 입력 길이 동작 (input length behavior),encode_query()및encode_document()와 같은 쿼리/문서별 인코딩 방법 (query/document-specific encoding method)을 설명합니다. - Sentence Transformers: Semantic Search는 시맨틱 검색 (semantic search)에서의 사용자 쿼리 (user query)와 코퍼스 문서 (corpus document)의 구분을 설명합니다.
벡터 검색 (vector search)과 벡터 저장소 (vector storage)에는 자주 사용되는 도구 (tool)들이 몇 가지 있습니다.
| 도구 (Tool) | 유형 (Type) | 이 계층에서의 역할 |
|---|---|---|
| FAISS | 벡터 검색 라이브러리 (Vector search library) | 로컬/커스텀 벡터 인덱싱 (local/custom vector indexing)에 유용함. 단, 그 자체로 전체 데이터베이스 (full database)는 아님 |
| ... |
RAG의 이 부분은 몇 가지 형태로 실패할 수 있습니다. 각각의 실패 (failure)는 보통 특정 표현 (representation) 또는 저장 (storage)의 문제에서 발생합니다.
| 실패 패턴 (Failure pattern) | 발생하는 현상 | 원인 |
|---|---|---|
| 모델 불일치 (Model mismatch) | 관련 텍스트가 벡터 공간 (vector space) 상에서 충분히 가깝게 위치하지 않음 | 임베딩 모델이 문서의 언어, 쿼리의 언어, 도메인 어휘 (domain vocabulary), 또는 청크 스타일 (chunk style)과 맞지 않음 |
| ... |
임베딩 (embedding)과 벡터 저장소 (vector storage)는 청크 (chunk)를 검색 가능하게 만들지만, 검색 (search), 랭킹 (ranking), 답변 생성 전략 (answer-generation strategy) 전체를 결정하는 것은 아닙니다.
- Hugging Face. Using Sentence Transformers.
- LlamaIndex. Embeddings.
- Sentence Transformers. Computing Embeddings.
- Sentence Transformers. Semantic Search.
- BAAI. BGE-M3 documentation.
- Chen et al. M3-Embedding: Multi-Linguality, Multi-Functionality, Multi-Granularity Text Embeddings through Self-Knowledge Distillation.
- FAISS. Official documentation.
- FAISS Wiki. MetricType and distances.
- Milvus. Overview.
- Qdrant. Points.
- Qdrant. Payload.
- pgvector. GitHub repository.
- Chroma. Documentation.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기