기본 콘텐츠로 건너뛰기

벡터 검색 제대로 알기: 임베딩·청킹·FAISS를 회사 PC에서 직접 돌려 봤다 [RAG 검색 이해하기 3편]

2편에서 키워드 검색은 사전을 키우는 만큼 똑똑해진다고 정리했다. 하지만 사전에 없는 말은 여전히 못 찾는다. 이번 편은 뜻으로 찾는 벡터 검색이다. (1편: 개념 정리 · 2편: 키워드 검색)

이번에는 회사 PC에서 직접 돌렸다. 그런데 첫 줄부터 막혔다. 모델을 내려받는 단계에서 SSL 인증서 오류가 났다. ㅡ,.ㅡ; 그 이야기부터 시작한다.

회사 PC에서 돌리려다 SSL 인증서에서 막혔다

벡터 검색에는 임베딩 모델이 필요하다. 보통 Hugging Face라는 사이트에서 내려받는다. 라이브러리 설치(pip)는 잘 됐는데, 모델을 받는 순간 이런 오류가 났다.

[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate in certificate chain

사이트가 막힌 게 아니었다. 회사망의 보안 장비가 HTTPS 통신을 중간에서 검사하면서 회사 자체 인증서로 바꿔 끼우는데, 브라우저와 Windows는 이 인증서를 믿지만 파이썬은 자기 인증서 목록만 써서 연결을 끊은 거다. 최신 pip는 Windows 인증서 저장소를 쓰기 때문에 pip만 통과했던 것이고.

해결은 파이썬도 Windows 인증서 저장소를 쓰게 하는 것이다. truststore라는 작은 라이브러리로 된다.

python -m pip install truststore

# 코드 맨 위에 두 줄
import truststore
truststore.inject_into_ssl()   # 파이썬이 Windows 인증서 저장소(회사 인증서 포함)를 쓰게 함

인터넷에 흔히 보이는 "인증서 검증 끄기(verify=False)"는 보안상 쓰면 안 된다. 회사에서 따라 해 볼 사람은 여기서 거의 다 한 번씩 막힐 거다.

임베딩: 문장을 384개의 숫자로 바꾼다

벡터 검색의 핵심은 임베딩이다. 문장을 넣으면 숫자 목록(벡터)이 나온다. 이번에 쓴 multilingual-e5-small 모델은 문장 하나를 숫자 384개로 바꾼다. 뜻이 비슷한 문장끼리 비슷한 숫자가 나오도록 학습된 모델이라, 숫자끼리 비교하면 뜻이 얼마나 가까운지 알 수 있다.

임베딩 개념도: 문장을 숫자로 바꾸면 뜻의 거리를 잴 수 있다

가까움은 보통 코사인 유사도로 잰다. 두 벡터가 같은 방향을 가리킬수록 1에 가깝다. 코드는 생각보다 짧다.

import truststore; truststore.inject_into_ssl()   # 회사망이면 꼭 (아래 설명)
from sentence_transformers import SentenceTransformer, util

model = SentenceTransformer("intfloat/multilingual-e5-small")  # 처음에 약 470MB 내려받음

docs = [
    "머신러닝 모델 학습용 GPU서버 사용 신청 절차",
    "기계학습 기초 교육 과정 안내",
    "인공지능 기반 문서 분류 시스템 운영 매뉴얼",
    "출장비 정산 규정 및 영수증 제출 방법",
    "딥러닝 프레임워크 설치 가이드",
]
# 1) 문서를 미리 벡터로 바꿔 둔다 (e5 모델은 문서 앞에 'passage: ')
doc_vecs = model.encode(["passage: " + d for d in docs], normalize_embeddings=True)

# 2) 질문도 벡터로 바꾼다 (질문 앞에는 'query: ')
q_vec = model.encode("query: 회사 돈으로 쓴 택시비 돌려받는 법", normalize_embeddings=True)

# 3) 코사인 유사도로 가까운 순서대로 줄 세운다
scores = util.cos_sim(q_vec, doc_vecs)[0].tolist()
for s, d in sorted(zip(scores, docs), reverse=True):
    print(f"{s:.3f}  {d}")

모델마다 지켜야 할 규칙이 있다. e5 모델은 질문 앞에 query: , 문서 앞에 passage: 를 붙여야 한다. 모델 설명서에 이렇게 학습했으니 안 붙이면 성능이 떨어진다고 적혀 있다.

실험 1: 겹치는 단어가 하나도 없는데 찾았다

1편·2편과 같은 가짜 문서 5개로 돌렸다. 각 질문의 1위만 뽑으면 이렇다.

질문벡터 검색 1위점수키워드 검색이었다면
회사 돈으로 쓴 택시비 돌려받는 법출장비 정산 규정 및 영수증 제출 방법0.832겹치는 단어가 없어 0건
AI로 문서를 자동으로 나눠 주는 시스템 있어?인공지능 기반 문서 분류 시스템 운영 매뉴얼0.876동의어 사전이 있어야 찾음
기계학습기계학습 기초 교육 과정 안내0.884찾음
머신러닝머신러닝 모델 학습용 GPU서버 사용 신청 절차0.869찾음 (기계학습 문서는 0점)

'택시비'와 '출장비', '돌려받는'과 '정산'은 글자가 하나도 안 겹친다. 그런데 찾았다. 2편에서 동의어 사전으로 겨우 풀었던 '머신러닝 = 기계학습'도 사전 없이 된다. '머신러닝'으로 찾으면 기계학습 교육 문서가 2위(0.838)로 바로 따라온다. 키워드 검색에서는 0점이던 문서다.

그런데 관계없는 문서도 0.78이다

결과를 처음부터 끝까지 보면 이상한 게 보인다. '머신러닝'을 물었는데 출장비 정산 규정이 0.793이다. 1위(0.869)와 차이가 0.08밖에 안 난다.

벡터 검색 점수 분포: 관계없는 문서도 0.8 근처, R1과 R2는 동점

모델 설명서를 찾아보니 이 모델은 원래 점수가 0.7~1.0 사이에 몰린다고 한다. 학습 방식 때문에 생기는 정상적인 특성이고, 점수 자체가 아니라 순서만 의미가 있다고 적혀 있다.

이게 실무에서는 꽤 중요하다. 키워드 검색은 관계없는 문서에 0점을 준다. 벡터 검색은 관계없는 문서에도 그럴듯한 점수를 준다. 그래서 "0.8 넘으면 관련 문서"처럼 점수로 자르기가 어렵고, 결국 상위 몇 개(top-k)를 가져오게 된다. 질문에 맞는 문서가 없을 때도 뭔가는 가져온다는 뜻이다. RAG에서 이게 생성형 AI에게 그대로 넘어가면, 관계없는 문서를 근거로 답을 만들 수 있다.

실험 2: 문서번호와 R1·R2는 구분하지 못한다

실제로 우리 문서들은 R1, R2 식으로 버전이 올라가면서 같은 내용이 중복으로 검색되는 문제가 있었다. 벡터 검색은 이걸 어떻게 볼까?

질문1위2위3위
TD-2024-0137TD-2024-0137 장애 대응 절차 (0.885)TD-2024-0131 운영 매뉴얼 R2 (0.867)TD-2024-0131 운영 매뉴얼 R1 (0.866)
GPU 서버 운영 매뉴얼 R2…매뉴얼 R2 (0.916)…매뉴얼 R1 (0.905)장애 대응 절차 (0.860)
GPU 서버 운영 매뉴얼 최신 버전…매뉴얼 R1 (0.899)…매뉴얼 R2 (0.899)장애 대응 절차 (0.870)

1위는 맞혔지만 차이가 아주 작다. 문서번호 0137을 물었는데 0131 문서가 0.018 차이로 따라온다. R2를 물으면 R1이 0.011 차이다. '최신 버전'으로 물으면 R1과 R2가 똑같이 0.899다. 벡터 검색은 R2가 R1보다 새것이라는 걸 모른다. 숫자 하나 다른 두 문서는 뜻이 거의 같기 때문이다.

이런 건 벡터 검색에 맡길 일이 아니다. 문서번호는 2편의 keyword 필드처럼 정확히 맞추고, '최신 버전'은 문서에 버전·날짜 정보를 따로 달아서 걸러야 한다(메타데이터 필터). 이건 4편에서 하이브리드로 묶을 때 다룬다.

실험 3: 긴 문서는 잘라서 넣는다 (청킹)

사내 문서는 몇 쪽, 몇십 쪽씩 된다. 통째로 벡터 하나로 만들면 두 가지 문제가 생긴다. 하나는 이 모델이 앞부분 512토큰까지만 읽고 나머지는 버린다는 것. 다른 하나는 벡터 하나에 여러 내용이 섞여 흐려진다는 것이다. 그래서 문서를 조각(청크)으로 잘라서 넣는다. 이걸 청킹이라고 한다.

GPU 서버 사용 규정을 5개 장으로 된 가짜 문서로 만들고, 장 단위로 잘랐다.

import re
# '제N장' 앞에서 자른다: 규정·매뉴얼은 장·조 단위가 곧 뜻의 단위다
chunks = [c.strip() for c in re.split(r"(?=제\d장)", long_doc) if c.strip()]
질문통째로 넣은 문서조각 1위결과
개인정보가 있는 데이터를 올려도 돼?0.841제4장 데이터 (0.869)정답 조각이 1위
GPU 서버는 최대 며칠까지 쓸 수 있어?0.875제2장 신청 (0.861)정답(제3장, "최대 2주")이 2위 안에 없음

첫 질문은 청킹이 제 역할을 했다. 개인정보 이야기가 든 제4장만 정확히 집어 왔다. 생성형 AI에게 문서 전체 대신 이 조각 하나만 넘기면 된다.

두 번째는 실패했다. '며칠까지'와 '최대 2주'를 이어 주지 못하고, '기간'이라는 말이 든 제2장을 1위로 올렸다. 작은 모델의 한계일 수도 있고, 조각이 너무 짧아서일 수도 있다. 같은 조각 5개에 2편의 키워드 검색(BM25)을 돌려 보니 반대로 제3장이 1위(2.52)였다. '최대'라는 단어가 그대로 겹치기 때문이다. 벡터 검색만 믿으면 안 되는 이유가 또 하나 생겼다.

청킹을 할 때 흔히 쓰는 요령은 이렇다.

  • 뜻의 단위로 자른다: 글자 수로 뚝뚝 자르지 말고 장·조·소제목 단위로.
  • 조금씩 겹치게 자른다: 경계에 걸린 문장이 잘리지 않게 앞뒤를 조금 겹친다.
  • 조각마다 문서 제목을 붙인다: "GPU 서버 사용 규정 > 제3장 사용 시간"처럼 붙이면 조각만 봐도 무슨 문서인지 안다.

3만 건이면 얼마나 걸릴까: FAISS와 벡터 DB

마지막으로 속도다. 벡터 3만 개를 만들어 놓고 질문 하나와 전부 비교했다.

방법1회 검색 시간
numpy로 3만 개 전부 비교1.43 ms
FAISS (IndexFlatIP)2.82 ms

FAISS가 더 느리게 나왔다. 이번에 쓴 IndexFlatIP는 FAISS에서도 '전부 다 비교하는' 가장 단순한 방식이라 numpy와 하는 일이 같고, 질문 하나씩 돌리면 오히려 준비 시간이 더 든다. FAISS가 빛을 보는 건 수백만 건 이상에서 HNSW나 IVF 같은 근사 검색(전부 비교하지 않고 가까운 후보만 보는 방식)을 쓸 때다. 3만 건이면 그냥 다 비교해도 1~3ms다.

FAISS는 코드 안에서 쓰는 라이브러리다. 서비스에서는 보통 벡터 DB를 쓴다. 저장·수정·삭제, 그리고 "R2만", "2025년 이후 문서만" 같은 필터를 같이 해 주기 때문이다.

종류예이럴 때
라이브러리FAISS공부, 실험, 작은 규모
전용 벡터 DBQdrant, Milvus벡터 검색이 중심인 서비스
RDB 확장pgvector (PostgreSQL)RDB에 있는 정보와 같이 쓰고 싶을 때
검색엔진 내장Elasticsearch / OpenSearch 벡터 필드이미 키워드 검색을 쓰고 있을 때 (하이브리드가 쉬움)

자바로 치면 FAISS는 메모리에 올린 HashMap이고, 벡터 DB는 DB 서버다.

직접 돌려 보니 벡터 검색은 "뜻"에 강하고 "글자"에 약했다. 택시비로 출장비 규정을 찾는 건 키워드 검색이 절대 못 하는 일이다. 반대로 문서번호, R1·R2, '최대 2주' 같은 정확한 값은 키워드 검색이 더 잘한다. 둘을 합치는 게 다음 편, 하이브리드 검색이다.

이상 벡터 검색 제대로 알기 끝!

댓글

이 블로그의 인기 게시물

싱가포르 여행 필수 준비물: G타입 변환 어댑터 (돼지코 전기 플러그)

조만간 우리 아이들이 싱가포르로 여행을 간다. 핸드폰 충전은 물론이고 다른 전기 제품 사용 때문에 어댑터가 꼭 필요하다. 해외여행 갈 때 어댑터 하나 잘못 챙겨가면 충전도 못 하고 전기 사용도 못 해서 낭패 보는 경우가 많다. 10년 전에 내가 싱가포르에 출장 갈 일이 있었는데 그때는 멀티 어댑터를 누군가에게 빌려갔었다. 이번 기회에 아이들 여행 준비물 중에 하나인 변환 플러그 검색하면서 알게 된 싱가포르 사용하는 전압과 플러그 타입, 어떤 어댑터를 챙겨야 하는지를 공유하려 한다. 싱가포르 여행을 계획하는 사람들을게 도움이 되겠지?  내 자식들 챙겨주는 마음으로 꼼꼼하게 설명해 줄 테니, 싱가포르 여행 준비물 리스트에 어댑터 관련 정보가 필요한 사람들은 꼭 참고했으면 한다. 1. 싱가포르 전기 환경 (전압과 플러그 타입) 해외여행 시 현지 전기 환경을 파악하는 것은 필수적인 여행 준비물 점검 사항이다. 싱가포르는 한국과 다른 전압 및 플러그 타입을 사용한다. 1.1 싱가포르 전압 (Voltage) 싱가포르는 230V(볼트) 전압을 사용한다. 한국은 220V를 사용하므로 전압 자체는 큰 차이가 없다. 대부분의 최신 전자기기(휴대폰 충전기, 노트북 충전기 등)는 100~240V의 프리볼트(Free Voltage)를 지원하므로, 전압 변환기(변압기)는 별도로 필요하지 않다. 1.2 싱가포르 플러그 타입 (Plug Type) 및 사용 국가 싱가포르는 Type G 플러그를 사용한다. 이는 영국식 3핀(세 발) 플러그 형태로, 한국(Type C, F)과는 모양이 완전히 다르다. 따라서 한국에서 사용하는 전자기기를 싱가포르에서 사용하려면 반드시 Type G 형태의 어댑터가 필요하다. Type G 플러그를 사용하는 주요 국가   아시아: 싱가포르, 홍콩, 말레이시아, 아랍에미리트(UAE) 등 유럽: 영국, 아일랜드, 몰타, 키프로스 등 기타: 사우디아라비아, 카리브해 일부 국가 등 이러한 국가들을 여행할 때도 Type G 어댑터 하나만 있으면 전기 ...

제주도 탐나는전 결제 사용 후기 (실물카드 미소지로 사용 실패)

제주도 여행을 앞두고 지역화폐인 '탐나는전'을 신청했다. 평소 성남사랑상품권을 잘 쓰고 있어서 제주도에서도 비슷하게 편리하게 쓸 수 있을 거라 생각했거든. 그런데... 결론부터 말하면 한 번도 써보지 못하고 환불하게 됐다. 탐나는전 신청과 설정 제주 출발 전에 미리 탐나는전을 신청했어. 신청 후 1주일 이내에 집에 도착.. 안내 브로셔를 보니 꽤 체계적으로 되어있더라고. 캐시백 혜택부터 시작해서 카드 등록, 사용법까지 자세히 나와있었어. 특히 소득공제 혜택도 있고, 한도상향 완료라는 문구도 보이니 더욱 기대가 됐어. 성남사랑상품권처럼 잘 활용할 수 있을 거라 생각했거든. 카드 등록 카드 등록을 진행했어. 인터페이스도 깔끔하고 사용하기 편해 보였어. "탐나는전 사용 가능한 카드를 신청 또는 등록해주세요!"라는 안내 문구를 보며 설레었지. 카드 정보를 직접 입력하거나 바코드로 인식할 수 있게 되어있어서 편리했어. 성남사랑상품권 앱과 비슷한 느낌이었거든. 난 바코드로 한큐에 등록.. 출발 전날인 6월 24일에 10만원을 충전했어. 탐나는전 선불카드로 등록도 완료하고, 제주도에서 맛있는 것도 사고 기념품도 살 생각에 들떠있었지. 그런데... 현실은? 제주도에 도착해서 탐나는전을 써보려고 했는데, 큰 문제가 있었어. 성남사랑상품권처럼 QR코드나 바코드로 간편하게 결제할 수 있을 거라 생각하고 실물카드를 안 가져갔거든. 그런데 제주도 매장들은 대부분 실물카드만 받더라고! QR코드나 바코드 결제를 지원하는 곳이 거의 없어서 당황했어. 성남에서는 거의 모든 곳에서 앱으로 간편결제가 되니까 당연히 제주도에서도 될 거라 생각했는데... 완전 오산이었어 😢 결국 환불... 여행 내내 한 번도 써보지 못하고, 마지막 날인 6월 29일에 결국 10만원 전액 환불했어. 충전 수수료나 환불 수수료 같은 건 없어서 다행이었지만, 뭔가 허무한 기분이었어. 후기와 조언 탐나는전 자체는 나쁘지 않은 시스템인 것 같아. 소득공제 혜택도 있고, 앱도 사용하기 편해...

미국 주식 투자 환전 수수료 비교 (증권사 환율우대 100% 찾는 법)

나는 달러 환테크와 미국 주식 투자를 병행하고 있다. 단순히 달러를 사고파는 것을 넘어, 환전한 달러로 바로 미국 주식을 매매할 수 있어야 하므로 증권사 환전 서비스를 이용하는 것은 필수다. 혹시 미국 주식을 아직도 한번도 매매 못한 사람을 위해 일반적인 프로세스는 아래와 같다. 이때 가장 중요한 것이 바로 '환전수수료' , 즉 환율우대 혜택이다. 1%, 0.1%의 수수료 차이가 투자 수익률에 큰 영향을 미치기 때문이다. 오늘은 미국 주식 투자를 위한 증권사별 환전 서비스를  비교하고, 환율우대 혜택을 가장 많이 받을 수 있는 곳이 어디인지 직접 정리해 본다.  1. 들어가기 전: 환전수수료와 환율우대란? 우리가 달러를 살 때, 기준이 되는 '매매기준율'에 증권사가 수수료를 붙여서 판매한다. 이 수수료를 '환전 스프레드' 라고 하며, 보통 1달러당 5원~10원 정도다. '환율우대' 란 이 환전 스프레드를 깎아주는 것을 의미한다. 예를 들어, 환율우대 95% 는 내가 내야 할 환전수수료의 95%를 할인해준다는 뜻이다. 당연히 우대율이 높을수록 우리에게 유리하며, 환율우대 100%는 환전수수료가 0원 이라는 의미다. 2. 증권사별 환전 우대율 및 이용 시간 비교 (우대율 높은 순) ※ 중요: 아래 정보는 신규 또는 휴면 고객 대상 이벤트 기준으로, 2025년 8월 말 현재 시점으로 재확인한 내용이다. 이벤트 기간이나 조건은 언제든 변경될 수 있으니, 거래 전 반드시 해당 증권사에 직접 확인해야 한다. 참고로 난 한투로 미국 주식을 하고 있는데 90% 우대를 받고 있다. 아직은 작은 금액이라 무시하고 있지만 억단위로 넘어가면 위 증권사 계좌로 넘어갈 계획이다. 3. 서비스별 심층 분석 및 투자 전략 3.1 조건부 최강자: NH투자증권 (나무증권)  NH투자증권은 '원화주문' 이라는 독특한 서비스를 통해 차별점을 가진다. 핵심 장점: 24시간 100% 자동 환율우대: 미국 주식 시장이 열리...