임베딩과 벡터 검색: 의미로 찾는 검색의 동작 원리
이 블로그의 RAG 심화 시리즈에서 벡터 검색은 계속 등장했지만, 임베딩과 벡터 검색 자체를 기초부터 정리한 글이 없었습니다. 이번에 정리합니다. 결론을 먼저 적으면, 임베딩은 텍스트를 의미가 보존되는 숫자 벡터로 바꾸는 기술이고, 벡터 검색은 그 벡터 공간에서 거리가 가까운 것을 찾는 기술입니다. 키워드가 겹치지 않아도 “환불 규정"으로 “결제 취소 정책” 문서를 찾을 수 있는 이유가 여기에 있습니다.
임베딩: 텍스트를 좌표로 바꾸기 #
임베딩 모델은 텍스트를 받아 고정 길이의 실수 배열, 즉 벡터를 출력합니다. 차원 수는 모델에 따라 수백에서 수천 사이입니다. 핵심 성질은 하나입니다. 의미가 비슷한 텍스트는 벡터 공간에서 가까운 위치에 놓입니다. “노트북 배터리가 빨리 닳아요"와 “랩톱 전원이 오래 못 가요"는 겹치는 단어가 거의 없지만, 임베딩 벡터는 가깝게 나옵니다.
몇 가지 실무적 사실을 함께 알아두면 좋습니다.
- 임베딩 모델은 생성형 LLM과 별개의 모델입니다. 호출 단가도 생성 모델보다 훨씬 저렴해서, 대량 문서를 임베딩하는 비용은 보통 전체 비용에서 큰 비중이 아닙니다.
- 텍스트만이 아니라 이미지, 코드도 임베딩할 수 있고, 텍스트와 이미지를 같은 공간에 놓는 멀티모달 임베딩도 있습니다.
- 임베딩 모델도 입력 토큰 한도가 있습니다. 문서를 통째로 넣는 것이 아니라 적절한 크기로 잘라서 임베딩하며, 이 자르기(청킹)가 검색 품질을 크게 좌우합니다. 청킹 전략은 RAG 심화 #2에서 다뤘습니다.
유사도: 가까움을 재는 방법 #
두 벡터가 얼마나 가까운지는 보통 셋 중 하나로 잽니다.
| 방식 | 무엇을 재나 | 비고 |
|---|---|---|
| 코사인 유사도 | 두 벡터 사이의 각도 | 가장 널리 쓰임. 길이 무시 |
| 내적(dot product) | 각도 + 벡터 크기 | 정규화된 벡터에서는 코사인과 동일 |
| 유클리드 거리 | 좌표상 직선 거리 | 값이 작을수록 유사 |
대부분의 임베딩 모델은 벡터를 정규화해 내놓거나 코사인 유사도를 권장하므로, 특별한 이유가 없으면 모델 제공자가 권장하는 방식을 그대로 쓰면 됩니다. 주의할 점은 유사도 점수의 절대값이 모델마다 스케일이 달라서, “0.8 이상이면 관련 있음” 같은 임계값은 모델을 바꾸면 다시 잡아야 한다는 것입니다.
벡터 검색: 전수 조사에서 근사 검색으로 #
검색은 결국 “질의 벡터와 가장 가까운 벡터 k개 찾기(kNN)“입니다. 가장 단순한 구현은 저장된 모든 벡터와 거리를 계산하는 전수 조사이고, 수만 건 규모까지는 이걸로 충분합니다. NumPy 행렬 연산 한 줄이면 되고 정확도도 100%입니다.
문제는 규모입니다. 수백만〜수억 건이 되면 전수 조사는 느려지므로, ANN(Approximate Nearest Neighbor, 근사 최근접 이웃) 인덱스를 씁니다. 대표 알고리즘이 HNSW로, 벡터들을 다층 그래프로 연결해 두고 그래프를 따라 내려가며 후보를 좁힙니다. 전부 비교하지 않는 대신 정확한 최근접을 놓칠 가능성이 생기며, 이 정확도를 재현율(recall)이라고 부릅니다. ANN 인덱스는 공통적으로 속도, 재현율, 메모리 사이의 트레이드오프를 파라미터로 조절합니다.
저장소 선택: 전용 DB가 항상 정답은 아닙니다 #
벡터를 어디에 저장하고 검색할지는 크게 세 갈래입니다.
- 기존 DB의 벡터 확장: PostgreSQL의 pgvector가 대표입니다. 이미 PostgreSQL을 운영 중이라면 별도 인프라 없이 벡터 컬럼을 추가하고, 메타데이터 필터링과 조인을 SQL로 함께 처리할 수 있습니다. 수백만 건 규모까지는 충분히 실용적입니다. Elasticsearch, OpenSearch, Redis도 벡터 검색을 지원합니다.
- 전용 벡터 DB: Pinecone, Qdrant, Weaviate, Milvus 등입니다. 대규모 벡터에 최적화된 인덱싱, 샤딩, 필터링을 제공합니다. 수천만 건 이상이거나 벡터 검색이 서비스의 핵심 경로일 때 검토합니다.
- 라이브러리 내장: FAISS 같은 라이브러리를 애플리케이션에 내장하는 방식입니다. 서버 없이 배치 작업이나 소규모 검색에 적합하지만, 영속화와 동시성은 직접 챙겨야 합니다.
판단 기준은 단순합니다. 이미 운영 중인 DB로 시작하고, 규모나 지연 시간이 문제가 될 때 전용 DB로 옮깁니다. 처음부터 전용 벡터 DB를 도입하면 인프라 하나가 늘어나는 운영 비용이 먼저 옵니다.
임베딩의 약점: 정확 매칭과 하이브리드 검색 #
벡터 검색은 의미의 가까움에는 강하지만, 문자열의 정확한 일치에는 약합니다. 에러 코드 E4032, 모델명 RTX 5090, 사내 프로젝트 코드네임처럼 의미보다 표기 자체가 중요한 질의에서는 키워드 검색(BM25)이 벡터 검색을 이깁니다. 그래서 실무 검색 시스템은 벡터 검색과 키워드 검색을 함께 돌려 결과를 합치는 하이브리드 구성이 표준에 가깝습니다. 구체적인 결합 방법은 RAG 심화 #3 하이브리드 검색에서 다뤘습니다.
운영에서 마주치는 것들 #
- 모델 교체 = 전체 재색인: 임베딩 벡터는 만든 모델에 종속됩니다. 다른 모델의 벡터와는 비교할 수 없으므로, 임베딩 모델을 바꾸면 저장된 문서 전체를 다시 임베딩해야 합니다. 문서가 많다면 재색인 파이프라인을 처음부터 설계에 넣어야 합니다.
- 차원과 메모리: 1536차원 float32 벡터 하나는 약 6KB입니다. 1000만 건이면 벡터만 60GB이고, ANN 인덱스는 보통 이걸 메모리에 올립니다. 차원 축소나 양자화로 줄일 수 있지만 재현율과 트레이드오프입니다.
- 신선도: 문서가 수정되면 해당 청크를 다시 임베딩해서 갱신해야 합니다. 원본과 인덱스의 동기화 지연은 검색 결과에 그대로 나타납니다.
정리 #
- 임베딩은 텍스트를 의미가 보존되는 벡터로 바꾸고, 벡터 검색은 그 공간에서 가까운 것을 찾습니다. 키워드가 달라도 의미로 찾을 수 있는 이유입니다.
- 소규모는 전수 조사로 충분하고, 대규모는 HNSW 같은 ANN 인덱스로 속도와 재현율을 교환합니다.
- 저장소는 기존 DB의 벡터 확장(pgvector 등)으로 시작하고, 규모가 커지면 전용 벡터 DB를 검토하는 순서가 안전합니다.
- 정확 매칭에는 약하므로 키워드 검색과 결합한 하이브리드가 실무 표준입니다.
- 임베딩 모델을 바꾸면 전체 재색인이 필요합니다. 운영 설계에 미리 반영해야 합니다.