키워드 검색에서 시맨틱 검색, 하이브리드 검색으로 이어지는 검색 기술의 진화 과정과 AI 검색 시스템의 핵심 구성요소를 살펴봅니다.
검색 기술은 크게 세 가지 패러다임을 거쳐 발전해 왔습니다. 각 단계는 이전 방식의 한계를 극복하면서 등장했으며, 현대 검색 시스템은 이 세 가지를 모두 활용하는 방향으로 진화하고 있습니다.
가장 오래되고 널리 사용된 방식은 **키워드 검색(Keyword Search)**입니다. 사용자가 입력한 검색어와 문서에 포함된 단어를 직접 대조하여 결과를 반환합니다. 대표적인 알고리즘은 BM25로, TF-IDF를 개선하여 단어 빈도와 문서 길이를 함께 고려합니다.
import math
def bm25_score(term_freq, doc_length, avg_doc_length, doc_freq, total_docs, k1=1.2, b=0.75):
"""BM25 스코어링 함수"""
idf = math.log((total_docs - doc_freq + 0.5) / (doc_freq + 0.5) + 1)
tf_norm = (term_freq * (k1 + 1)) / (term_freq + k1 * (1 - b + b * (doc_length / avg_doc_length)))
return idf * tf_normBM25는 빠르고 예측 가능하다는 장점이 있지만, 근본적인 한계를 가지고 있습니다. "자동차 수리"를 검색했을 때 "차량 정비"라는 표현이 포함된 문서를 찾지 못합니다. 동의어, 유의어, 맥락적 의미를 전혀 이해하지 못하기 때문입니다.
**시맨틱 검색(Semantic Search)**은 텍스트의 의미를 벡터 공간에 매핑하여 검색하는 방식입니다. **임베딩 모델(Embedding Model)**이 텍스트를 고차원 벡터로 변환하고, 벡터 간의 거리(유사도)를 기반으로 관련 문서를 찾습니다.
from sentence_transformers import SentenceTransformer
import numpy as np
model = SentenceTransformer("all-MiniLM-L6-v2")
query = "자동차 수리 방법"
documents = [
"차량 정비 가이드: 엔진 오일 교환 절차",
"오늘의 날씨 예보",
"자동차 고장 진단과 수리 매뉴얼",
]
query_embedding = model.encode(query)
doc_embeddings = model.encode(documents)
# 코사인 유사도 계산
similarities = np.dot(doc_embeddings, query_embedding) / (
np.linalg.norm(doc_embeddings, axis=1) * np.linalg.norm(query_embedding)
)
for doc, score in sorted(zip(documents, similarities), key=lambda x: x[1], reverse=True):
print(f"{score:.4f} | {doc}")이 방식에서는 "자동차 수리"와 "차량 정비"가 의미적으로 가까운 벡터로 표현되므로, 정확한 단어가 일치하지 않아도 관련 문서를 찾을 수 있습니다.
**하이브리드 검색(Hybrid Search)**은 키워드 검색과 시맨틱 검색을 결합합니다. 각 방식의 강점을 취하고 약점을 보완하는 전략입니다. 예를 들어 제품 코드나 고유명사처럼 정확한 매칭이 필요한 경우에는 BM25가, 의미적 유사성이 중요한 경우에는 시맨틱 검색이 더 효과적입니다.
키워드 기반 검색은 수십 년간 정보 검색의 표준이었지만, 다음과 같은 근본적 한계를 갖고 있습니다.
어휘 불일치 문제(Vocabulary Mismatch Problem): 같은 개념을 다른 단어로 표현하면 검색에 실패합니다. "머신러닝"과 "기계학습", "딥러닝"과 "심층학습"처럼 한국어 환경에서는 영어 용어와 한국어 번역어가 혼용되므로 이 문제가 더 심각합니다.
의도 파악 불가: "사과"를 검색했을 때 과일인지, 사과(謝過)인지 구분하지 못합니다. 검색어 자체만으로는 사용자의 의도를 파악할 수 없습니다.
문맥 무시: 문서 전체의 맥락이 아닌 개별 단어의 출현 여부만 판단합니다. 긴 문서에서 특정 단어가 한 번 등장한 것과 핵심 주제로 반복 등장한 것을 동일하게 취급할 수 있습니다.
랭킹의 한계: BM25 점수는 통계적 단어 빈도에 기반하므로, 사용자가 실제로 원하는 "관련성"과 괴리가 있을 수 있습니다.
이러한 한계는 단순히 알고리즘을 개선한다고 해결되지 않습니다. 텍스트의 "의미"를 이해하는 근본적으로 다른 접근이 필요했고, 그것이 바로 임베딩 기반 시맨틱 검색입니다.
현대 AI 검색 시스템은 네 가지 핵심 구성요소로 이루어져 있습니다.
**임베딩(Embedding)**은 텍스트를 고정 길이의 숫자 벡터로 변환하는 과정입니다. BERT, Sentence-BERT, E5, BGE 등의 사전 훈련된 모델이 이 역할을 수행합니다. 좋은 임베딩 모델은 의미적으로 유사한 텍스트를 벡터 공간에서 가까운 위치에 배치합니다.
| 모델 | 차원 | 특징 |
|---|---|---|
| all-MiniLM-L6-v2 | 384 | 가볍고 빠름, 범용 |
| multilingual-e5-large | 1024 | 다국어 지원, 한국어 성능 우수 |
| bge-m3 | 1024 | 다국어, 밀집+희소 벡터 동시 생성 |
| ELSER v2 | 희소 | Elasticsearch 전용, 희소 벡터 |
생성된 벡터를 효율적으로 검색할 수 있도록 인덱스 구조에 저장합니다. 수백만 개의 벡터에서 유사한 것을 찾으려면 전수 비교(brute-force)가 아닌 ANN(Approximate Nearest Neighbor) 알고리즘이 필요합니다. 대표적인 알고리즘으로 HNSW, IVF, Product Quantization 등이 있습니다.
사용자의 쿼리를 동일한 임베딩 모델로 벡터화한 뒤, 인덱스에서 가장 유사한 벡터를 가진 문서를 추출합니다. 이 단계에서는 속도가 중요하므로 Bi-encoder 방식을 사용합니다. 쿼리와 문서를 독립적으로 인코딩하기 때문에, 문서 벡터는 미리 계산해 둘 수 있습니다.
검색 단계에서 추출한 후보 문서들의 최종 순위를 결정합니다. Cross-encoder 기반의 리랭킹 모델이 쿼리와 각 문서를 함께 처리하여 더 정밀한 관련성 점수를 산출합니다. Bi-encoder보다 느리지만 정확도가 훨씬 높습니다.
검색 시스템에서 Bi-encoder는 "빠르지만 덜 정확한" 1차 필터, Cross-encoder는 "느리지만 더 정확한" 2차 정밀 평가 역할을 합니다. 이 2단계 구조가 현대 검색 시스템의 표준 패턴입니다.
AI 기반 검색 시스템의 전체 흐름을 아키텍처 다이어그램으로 표현하면 다음과 같습니다.
이 아키텍처에서 핵심 흐름은 다음과 같습니다.
이 시리즈는 총 11장으로 구성되어 있으며, AI 검색 시스템의 이론과 실전을 모두 다룹니다.
이번 장에서는 검색 기술이 키워드 매칭에서 시맨틱 이해, 그리고 하이브리드 방식으로 진화해 온 과정을 살펴보았습니다. 전통적 검색의 어휘 불일치 문제와 의도 파악 한계를 확인했고, AI 검색 시스템의 네 가지 핵심 구성요소인 임베딩, 인덱싱, 검색, 랭킹의 역할을 이해했습니다.
다음 장에서는 시맨틱 검색 아키텍처를 본격적으로 파고들어, Bi-encoder 기반 검색의 작동 원리와 임베딩 모델 선택, 문서 청킹 전략, 벡터 데이터베이스 연동까지 Python 구현과 함께 다루겠습니다.
이 글이 도움이 되셨나요?
Bi-encoder 기반 시맨틱 검색의 작동 원리, 임베딩 모델 선택, 문서 청킹 전략, ANN 검색, 벡터 데이터베이스 연동을 Python 구현과 함께 다룹니다.
Precision, Recall, NDCG, MRR, MAP 등 검색 품질 메트릭의 원리와 계산법, 오프라인/온라인 평가 방법론, A/B 테스트와 평가 데이터셋 구축을 다룹니다.
쿼리 분류, 의도 인식, 엔티티 인식부터 LLM 기반 쿼리 확장, HyDE(가상 문서 생성), 다국어 처리까지 쿼리 이해 파이프라인을 다룹니다.