RAG(Retrieval-Augmented Generation) 시스템에서 벡터 검색은 검색 품질과 응답 속도를 좌우하는 핵심 기술입니다. 저는 3년간 다양한 규모(스타트업부터 대규모 프로덕션까지)의 RAG 시스템을 구축하며 세 가지 주요 벡터 인덱스 알고리즘을 실전에서 검증했습니다. 이 튜토리얼에서는 HolySheep AI를 활용한 비용 최적화와 함께 각 알고리즘의 장단점을 실무 관점에서 비교分析합니다.

벡터 인덱스 기본 개념과 성능 지표

벡터 인덱스는 고차원 임베딩 공간에서 효율적으로 유사도를 검색하기 위한 자료구조입니다. Recall(정확도), QPS(초당 쿼리 처리량), 메모리 사용량, 빌드 시간이 핵심 평가 지표입니다. 수백만 개의 벡터를 다루는 프로덕션 환경에서는 이 지표들의 균형이 시스템成败을 결정합니다.

HNSW vs IVF vs DiskANN 핵심 비교표

비교 항목 HNSW IVF (IVF-PQ) DiskANN
알고리즘 유형 그래프 기반 (階層적 Navigable Small World) 클러스터링 기반 (Inverted File) 디스크 최적화 (Vamana 그래프)
빌드 시간 중간 (수십 분~수 시간) 빠름 (수 분~수십 분) 빠름 (수 분~수십 분)
메모리 사용량 높음 (원본 벡터 저장) 중간 (PQ 압축) 낮음 (디스크 활용)
QPS (대용량) 매우 높음 (인메모리) 높음 (인메모리) 중간~높음 (디스크 I/O)
Recall @10 95~99% (높은 ef 설정 시) 85~95% (nprobe 튜닝) 90~97% (beam width 튜닝)
대용량 확장성 제한적 (메모리 의존) 제한적 (메모리 의존) 우수 (수억 개 벡터 가능)
적합한 규모 ~1,000만 벡터 ~5,000만 벡터 수억 벡터 이상
인덱스 크기 원본 대비 1.2~1.5배 원본 대비 0.1~0.3배 (PQ) 원본 대비 0.3~0.5배

각 알고리즘 심층 분석

HNSW (Hierarchical Navigable Small World)

HNSW은 계층적 그래프 구조를 사용하여 근접 이웃 검색을 빠르게 수행합니다. 저는 초기 RAG 프로젝트에서 HNSW을 주로 사용했으며, 100만 벡터 이하에서는 탁월한 성능을 보여줍니다. ef_construction과 ef_search 파라미터 조절로 정확도와 속도 간 균형을 맞출 수 있습니다.

# Python으로 Faiss-HNSW 인덱스 생성 및 검색
import numpy as np
import faiss

128차원 임베딩 100만 개 생성 (예시)

dimension = 128 num_vectors = 1_000_000 vectors = np.random.random((num_vectors, dimension)).astype('float32')

HNSW 인덱스 생성

M: 각 노드의 연결 수 (높을수록 정확도↑, 메모리↑)

efConstruction: 빌드 시 탐색 범위

efSearch: 검색 시 탐색 범위

M = 32 efConstruction = 200 efSearch = 100 index = faiss.IndexHNSWFlat(dimension, M) index.hnsw.efConstruction = efConstruction index.hnsw.efSearch = efSearch

벡터 추가

index.add(vectors)

검색 수행

query_vector = np.random.random((1, dimension)).astype('float32') k = 10 # 상위 10개 결과 distances, indices = index.search(query_vector, k) print(f"검색 결과 indices: {indices[0]}") print(f"유사도 거리: {distances[0]}") print(f"인덱스 크기: {index.ntotal} 벡터")

IVF-PQ (Inverted File with Product Quantization)

IVF-PQ는 벡터를 클러스터로 나누고, Product Quantization으로 벡터를 압축하여 메모리 사용량을 크게 줄입니다. 저는 비용 최적화가 중요한 프로젝트에서 IVF-PQ를 선택했습니다. nprobe 파라미터로 검색 정확도와 속도를 조절할 수 있습니다.

# Python으로 Faiss-IVF-PQ 인덱스 생성 및 검색
import numpy as np
import faiss

768차원 임베딩 500만 개 생성 (예시)

dimension = 768 num_vectors = 5_000_000 vectors = np.random.random((num_vectors, dimension)).astype('float32')

IVF-PQ 인덱스 생성

nlist: 클러스터 수 (벡터 수의 제곱근 근처가 일반적)

m: PQ 서브벡터 수 (dimension을 나누는 수)

nbits: 각 서브벡터 양자화 비트 수

nlist = 4096 # 클러스터 수 m = 64 # PQ 서브벡터 수 nbits = 8 # 양자화 비트 수

IVF-PQ 인덱스 생성

quantizer = faiss.IndexFlatIP(dimension) # Inner Product (코사인 유사도近似) index = faiss.IndexIVFPQ(quantizer, dimension, nlist, m, nbits)

훈련 데이터로 quantizer 훈련 (전체 데이터의 일부 사용 가능)

print("훈련 시작...") train_vectors =