지금까지의 시맨틱 검색은 문서·프롬프트에 각각 벡터 하나를 부여해 비교하는 단순한 구조였다. 결과는 훌륭하지만, 더 정교한 구조로 더 높은 검색 품질이 가능하다. 이번 편은 그 두 구조 — 크로스 인코더(cross-encoder)와 ColBERT — 를 장단점과 함께 본다.
1. Bi-Encoder — 지금까지의 구조
지금까지 쓴 구조는 bi-encoder다. 문서는 각각 임베딩 모델로 벡터를 부여받고, 프롬프트도 벡터로 임베딩된 뒤, 벡터 DB의 ANN 알고리즘이 프롬프트 벡터에 가까운 문서를 빠르게 찾는다. "bi(둘)"는 문서와 프롬프트를 따로(separately) 임베딩한다는 뜻이다. 이게 중요한 이유는, 모든 문서를 미리 임베딩해 두고 프롬프트만 받은 뒤 임베딩하면 되어 검색이 매우 빠르다는 점이다.

2. Cross-Encoder — 품질의 최고 기준
속도를 조금 포기하면 더 높은 품질을 얻을 수 있다. 크로스 인코더는 문서 점수를 매길 때, 문서와 프롬프트를 이어 붙여(concatenate) 하나의 텍스트로 만든 뒤 특수한 임베딩 모델에 통과시킨다. 프롬프트와 문서가 함께 입력되므로, bi-encoder가 놓칠 수 있는 둘 사이의 깊은 맥락적 상호작용을 이해한다. 그리고 관련성 점수(보통 0~1)를 직접 출력한다 — 프롬프트-문서가 일치할 확률로 볼 수 있다.

예를 들어 "great places to eat in New York"이라는 프롬프트가 오면, 각 문서 앞에 프롬프트를 붙여 크로스 인코더에 통과시키고 점수를 얻는다. 관련성 높은 문서는 0.7처럼 높은 점수를, 낮은 문서는 낮은 점수를 받는다.

크로스 인코더는 검색 관련성 지표에서 거의 항상 bi-encoder보다 좋은 결과를 준다. 문제는 확장성이 끔찍하다는 것이다. knowledge base가 수백만~수십억 문서라면, 프롬프트마다 그 모든 "문서+프롬프트 쌍"을 크로스 인코더에 통과시켜야 한다. 게다가 크로스 인코더는 프롬프트가 있어야 돌아가므로 미리 전처리할 수도 없다. 그래서 기본 검색기로 쓰기엔 너무 비효율적이지만, 품질이 좋아 다른 검색의 결과를 개선하는 도구(리랭킹)로 훌륭하다.

3. ColBERT — 속도와 품질의 절충
bi-encoder의 속도와 cross-encoder의 품질 사이를 노린 구조가 ColBERT(Contextualized Late Interaction over BERT)다. 문서 벡터를 미리 생성하되(bi-encoder처럼), 프롬프트-문서의 깊은 상호작용도 어느 정도 포착한다(cross-encoder처럼).

핵심은, 문서 전체에 벡터 하나가 아니라 토큰마다 벡터 하나를 만든다는 것이다. 1,000 토큰 문서는 1,000개의 dense 벡터가 된다. 프롬프트도 같은 식으로 토큰마다 벡터를 만든다. 점수는 각 프롬프트 토큰이 문서에서 가장 비슷한 토큰을 찾아 그 최고 유사도를 얻고, 그 최고값들을 모두 더해 문서 전체 점수를 만든다 — 이를 MaxSim 점수라 한다. 예를 들어 프롬프트의 "New", "York"은 문서의 "New York", "City"와, "Eat"은 "Cuisine"과 잘 매칭된다.


ColBERT는 bi-encoder의 확장성과 cross-encoder의 풍부한 상호작용을 상당 부분 함께 얻는다. 점수 계산이 bi-encoder보다는 무겁지만 여전히 실시간에 가까운 검색이 가능하다. 가장 큰 단점은 저장할 벡터 수가 토큰 수에 비례한다는 것 — 2,000 토큰 문서면 2,000개 벡터를 저장해야 한다(bi-encoder는 문서당 벡터 1개).

4. 세 구조 비교


바로 그 아이디어 — 비싼 크로스 인코더를 1차 검색 결과에만 적용해 순위를 다시 매기는 — 가 다음 편의 리랭킹(reranking)이다.
'AI > RAG' 카테고리의 다른 글
| Transformer Architecture (0) | 2026.07.03 |
|---|---|
| Reranking (0) | 2026.07.03 |
| Query Parsing (0) | 2026.07.02 |
| 고급 청킹 기법 (0) | 2026.07.02 |
| Chunking (0) | 2026.07.02 |