임베딩 임베딩
텍스트나 이미지의 “의미”를 숫자 벡터로 바꿔놓는 작업임.
"고양이가 낮잠을 잔다"
│
│ 임베딩 모델 (BERT, GPT, Word2Vec, ResNet 등)
▼
[0.12, -0.34, 0.88, ..., 0.05] ← 768 혹은 1536차원 벡터
컴퓨터는 글자 그 자체로는 “비슷한 의미”를 판단하지 못함. 그래서 의미를 좌표로 옮겨놓고, 좌표 사이의 거리로 유사도를 계산하는 방식임. “고양이”와 “강아지”는 벡터 공간에서 가깝고, “고양이”와 “세탁기”는 멀리 떨어져 있는 식.
주의할 포인트 두 가지
- 문서와 질문은 같은 임베딩 모델로 변환해야 함. 한쪽은
text-embedding-3-small로 만들고 다른 쪽은BGE-M3로 만들면 좌표계 자체가 달라서 유사도 계산이 의미가 없어짐. - FAISS는 임베딩을 “만들지” 않음. 이미 만들어진 벡터를 받아 저장/검색만 함. 임베딩 생성은 BERT, OpenAI API 같은 모델이 담당하고, FAISS는 결과물을 꽂아넣는 창고 역할.
한마디로: 임베딩은 “의미를 좌표로 바꾸는 번역 작업”이고, FAISS는 그 좌표들을 관리하는 창고임.
FAISS
FAISS는 데이터베이스가 아니라, 벡터 전용 “고속 검색 엔진 라이브러리”임.
Facebook AI Research가 만든 라이브러리이며, 이름부터 Facebook AI Similarity Search. 이름 그대로 “유사도 검색”에 특화됨.
[일반 DB] [FAISS]
디스크 기반 메모리(RAM) 기반
SQL 쿼리 벡터 유사도 계산
"이름이 홍길동인 사람" "이 벡터와 제일 비슷한 벡터 10개"
행/열 구조 고차원 벡터 배열 + 인덱스
실체는 Index 객체
FAISS에서 “저장”이라는 건 벡터들을 그냥 배열로 쌓아놓는 게 아님. 검색 속도를 위해 인덱스(Index) 라는 구조로 재편성해서 보관함. faiss.write_index(index, "my.index")로 디스크에 떨어지는 그 파일이 바로 FAISS 저장소의 실체.
벡터를 빠르게 찾기 위한 3가지 전략
- 클러스터링(Clustering): 비슷한 벡터끼리 미리 묶어두고, 검색 시 해당 그룹 안에서만 상세 검색
- 양자화(Quantization): 벡터를 압축해서 메모리 사용량을 줄이고 연산 속도를 끌어올림
- 파티셔닝(Partitioning): 공간을 구역으로 나눠서, 쿼리 벡터가 속한 구역 근처만 훑음
세 가지 모두 “전체를 다 뒤지지 말고, 일단 후보를 좁히자”는 공통 아이디어임. 택배 물류센터에서 전국 소포를 다 뒤지지 않고, 지역 허브부터 좁혀가는 것과 같은 원리.
거리 계산 방식
FAISS는 두 가지 거리에 특화됨:
- 유클리드 거리(L2 거리): 지도 위 두 점 사이 직선거리. 벡터의 크기와 방향을 모두 고려.
- 내적(Inner Product): 두 벡터가 얼마나 같은 방향을 보고 있는지.
|A| × |B| × cos(θ).
정규화된(크기가 1인) 벡터에서 내적 = 코사인 유사도. 그래서 보통 벡터를 미리 정규화하고 내적을 쓰는 방식이 자주 쓰임.
LangChain에서 “Vector Store”라고 부르는 이유
LangChain 같은 프레임워크는 FAISS를 Vector Store(벡터 저장소)라고 감싸서 제공함. “저장소”라는 표현이 붙는 건, 진짜 범용 DB라서가 아니라 “검색을 위한 벡터 인덱스를 저장한다”는 특화된 역할을 가리키는 것.
리트리버와 FAISS 동작 방식
리트리버(Retriever)는 “질문에 맞는 문서를 찾아오는 담당자”임. FAISS는 그 담당자가 쓰는 도구 중 하나.
1단계: 저장 (Indexing)
문서들 ──[임베딩 모델]──▶ 벡터들 ──[FAISS 인덱스로 재편성]──▶ 저장
2단계: 검색 (Search)
사용자 질문 ──[같은 임베딩 모델]──▶ 질문 벡터
3단계: 유사도 비교
질문 벡터 ◀──▶ 저장된 벡터들 (FAISS가 고속 계산)
→ 가장 가까운 top-k개 반환
핵심은 “저장할 때 쓴 임베딩 모델 == 검색할 때 쓰는 임베딩 모델”이라는 규칙. 여기 어긋나면 좌표계가 달라서 결과가 망가짐.
코사인유사도
벡터의 “크기”는 무시하고, “방향”만 비교하는 유사도 점수임.
벡터 A: ──────▶ (길이 5)
벡터 B: ─▶ (길이 1)
두 화살표가 같은 방향을 보고 있으면 → 코사인 유사도 = 1
직각으로 만나면 → 코사인 유사도 = 0
정반대 방향이면 → 코사인 유사도 = -1
수식으로 보면
cos(θ) = (A · B) / (|A| × |B|)
= 정규화된 A와 정규화된 B의 내적
두 벡터를 각각 길이 1로 맞춘 뒤 내적을 구하면 그게 바로 코사인 유사도. 그래서 벡터를 미리 정규화해두면 내적만 계산해도 되므로 속도가 빨라짐.
왜 크기는 무시하는지
문서 길이가 길어지면 임베딩 벡터의 “크기”도 커지는 경향이 있음. 하지만 궁금한 건 “의미가 같은 방향인가?”이지, “문장이 긴가?”가 아님. 그래서 크기를 떼어내고 방향만 보는 것.
한마디로: 코사인 유사도 = “방향만 보는 유사도 점수”.
VectorDB
벡터들을 대량으로 저장하고, 유사한 벡터를 빠르게 찾아오는 데 특화된 DB임.
FAISS가 “메모리 기반 검색 엔진 라이브러리”라면, VectorDB는 “디스크 저장 + 메타데이터 + 스케일링까지 포함한 완전한 DB”. 포함 관계로 보면:
VectorDB ⊃ 벡터 인덱스(FAISS 같은 구조) + 메타데이터 테이블 + 영속화 + 네트워크 인터페이스
대표적인 VectorDB: Pinecone, Weaviate, Milvus, Qdrant, ChromaDB, PostgreSQL의 pgvector 확장.
VectorDB가 필요한 이유
RAG에서 VectorDB는 LLM의 외부 기억 장치 역할을 함. LLM 자체는 학습 시점 이후의 정보를 모르고, 사내 문서나 개인 노트 같은 비공개 데이터도 모름. 그걸 보완하려고 외부에 지식을 쌓아두는 것임.
- 최신 정보 반영: LLM 학습 컷오프 이후에 생긴 정보도 VectorDB에 넣어두면 검색해서 가져옴
- 환각(Hallucination) 감소: 근거가 되는 실제 문서를 같이 물려주니까 LLM이 지어내는 빈도가 줄어듦
- 비용 및 효율성: LLM을 다시 파인튜닝하는 것보다 VectorDB에 문서만 추가하는 게 훨씬 싸고 빠름
- 전문분야 적용: 의료, 법률, 사내 정책처럼 비공개/특수 지식을 담아둘 수 있음
VectorDB와 일반 DB의 차이점
일반 DB는 “정확히 일치하는 것”을, VectorDB는 “의미적으로 비슷한 것”을 찾음.
| 구분 | Vector DB (벡터 데이터베이스) | 일반 DB (관계형 데이터베이스) |
|---|---|---|
| 데이터 형태 | 비정형 데이터(텍스트, 이미지 등)를 의미적으로 변환한 고차원 벡터(Vector) | 정형 데이터를 **테이블(Table)**의 행(Row)과 열(Column) 구조로 저장 |
| 검색 방식 | 유사도 검색(Similarity Search): “의미적으로 얼마나 가까운가?” 기준 (예: ‘고양이’ 이미지와 비슷한 이미지) | 정확한 일치 검색(Exact Match): “특정 조건에 맞는가?” 기준 (예: 이름이 ‘홍길동’인 사용자) |
| 핵심 기술 | 근사 최근접 이웃(ANN, Approximate Nearest Neighbor) 알고리즘. 수억 건 중에서도 유사한 걸 빠르게 찾아냄 | SQL(Structured Query Language). 정해진 규칙에 따라 조회/추가/수정/삭제 |
| 사용 사례 | AI 챗봇, RAG 시스템, 이미지/음성 검색, 추천 시스템, 이상 탐지 | 고객 정보 관리, 재고 관리, 금융 거래 기록, 회원 시스템 |
| 예시 쿼리 | “‘AI 기술의 미래’라는 문장과 가장 비슷한 의미를 가진 다른 문서를 찾아줘" | "2024년에 작성된 ‘AI’ 카테고리의 모든 게시글을 찾아줘” |
ANN이 핵심이라는 점
벡터 검색에서 가장 정확한 방식은 모든 벡터와 거리를 다 계산하는 brute-force지만, 수백만~수억 건이면 불가능함. 그래서 “정확도는 살짝 포기하고 속도를 취한” 근사 알고리즘(HNSW, IVF, PQ 등)을 씀. 이것이 ANN이고, FAISS/Pinecone/Weaviate 같은 엔진들의 공통 심장부임.
한마디로: VectorDB는 “의미로 찾는 DB + ANN으로 빠르게”.