검색

Embedding

텍스트를 의미가 담긴 숫자 벡터로 바꿔 유사도를 계산할 수 있게 하는 기법

입문

한 줄 정의

임베딩은 텍스트를 의미가 담긴 고정 길이의 숫자 벡터로 바꾸는 것이다.

왜 필요한가

컴퓨터는 문자열을 직접 비교할 수밖에 없다. 그래서 다음을 구분하지 못한다.

  • “자동차 가격” 과 “차량 시세” — 글자는 다르지만 의미는 가깝다
  • “사과를 먹었다” 와 “사과를 했다” — 글자는 비슷하지만 의미는 멀다

임베딩은 의미를 좌표로 바꾼다. 의미가 가까운 문장은 벡터 공간에서도 가깝게 놓인다. 그래서 의미 기반 검색이 가능해진다.

핵심 개념

용어설명
차원(dimension)벡터의 길이. text-embedding-3-small은 1536
코사인 유사도두 벡터가 이루는 각도로 유사도를 재는 방법
정규화벡터 길이를 1로 맞춰 비교를 단순화하는 것

동작 구조

flowchart LR
    T["중고차 매입 절차"] --> M[임베딩 모델]
    M --> V["[0.021, -0.113, ...]"]
    V --> S[(벡터 저장소)]
    Q[질문] --> M2[임베딩 모델]
    M2 --> C[유사도 계산]
    S --> C
    C --> R[가까운 문서]

같은 모델로 문서와 질문을 모두 벡터로 바꾼 뒤, 거리를 재서 가까운 것을 찾는다.

예제

세 문장을 임베딩했다고 하자.

문장질문과의 유사도
중고차 매입 시 감가 기준0.89
차량 시세 조회 방법0.72
오늘 점심 메뉴 추천0.11

질문이 “중고차 살 때 가격이 얼마나 깎이나?”였다면 첫 번째가 선택된다. 단어가 하나도 겹치지 않아도 의미로 찾아낸다.

코드

from openai import OpenAI

client = OpenAI()

response = client.embeddings.create(
    model="text-embedding-3-small",
    input="중고차 매입 절차",
)

vector = response.data[0].embedding
print(len(vector))  # 1536

코사인 유사도는 다음과 같이 정의된다.

sim(a,b)=abab\text{sim}(\mathbf{a}, \mathbf{b}) = \frac{\mathbf{a} \cdot \mathbf{b}}{\|\mathbf{a}\|\|\mathbf{b}\|}

장점

  • 단어가 겹치지 않아도 의미로 검색된다
  • 언어가 달라도 의미가 가까우면 찾아진다(다국어 모델)
  • 한 번 계산해두면 재사용할 수 있다

단점

  • 문서와 질문에 같은 모델을 써야 한다. 섞으면 결과가 무의미하다
  • 모델을 바꾸면 전체를 다시 임베딩해야 한다
  • 고유명사나 숫자처럼 정확히 일치해야 하는 검색에는 약하다
  • 차원이 크면 저장 비용이 늘어난다

자주 발생하는 문제

증상원인해결
검색 결과가 엉망문서와 질문의 임베딩 모델이 다름같은 모델로 통일
특정 제품명을 못 찾음의미 검색의 한계키워드 검색과 함께 쓰는 하이브리드 검색
비용이 많이 나옴매번 재계산결과를 저장해두고 재사용

실제 프로젝트 적용

아직 없음.

관련 문서

참고 자료