logo
aillmembedding

임베딩(Embedding) 완전 이해 - 의미를 숫자로 바꾸기

컴퓨터는 "사과"와 "바나나"가 비슷하고 "사과"와 "자동차"가 다르다는 걸 어떻게 알까요? 글자만 비교하면 "사과"와 "사고"가 더 비슷해 보일 텐데 말이죠. 이 문제를 푸는 열쇠가 임베딩(Embedding) 입니다. 텍스트의 의미를 숫자 벡터로 바꿔, 의미가 비슷하면 숫자도 가깝게 만드는 기술입니다.

이 글에서는 임베딩이 무엇이고, 왜 유사도가 계산되며, 실무에서 어떻게 활용하고 무엇을 조심해야 하는지 정리합니다.


1. 임베딩은 한 문장으로

"의미가 비슷한 것끼리 가까이 모이도록, 텍스트를 좌표(벡터)로 바꾸는 것."

임베딩 모델에 문장을 넣으면 고정 길이의 숫자 배열이 나옵니다.

const v = await embed("결제를 취소하고 싶어요"); // => [0.021, -0.135, 0.008, 0.240, ... ] (예: 1536개의 숫자)

이 숫자 하나하나에 사람이 이해할 이름표가 붙어 있진 않습니다. 대신 전체 벡터가 하나의 "의미 좌표" 를 이룹니다. 핵심 성질은 이것입니다.

  • "결제 취소하는 법"과 "환불 요청 방법"은 → 벡터가 가깝다
  • "결제 취소하는 법"과 "오늘 점심 메뉴"는 → 벡터가 멀다

단어가 달라도 의미가 통하면 가까이 놓인다는 게 핵심입니다. 이래서 키워드 검색으로는 못 잡는 "뜻이 같은 다른 표현"을 잡아낼 수 있습니다.


2. 벡터 공간이라는 지도

임베딩을 이해하는 가장 좋은 비유는 지도 입니다. 세상의 모든 개념을 아주 고차원(수백~수천 차원) 공간의 점으로 찍은 지도라고 상상해보세요.

  • 가까운 점 = 의미가 비슷한 것
  • 먼 점 = 의미가 다른 것

유명한 예로, 잘 학습된 벡터 공간에서는 이런 "방향"도 의미를 가집니다.

왕(king) - 남자(man) + 여자(woman) ≈ 여왕(queen)

"성별을 바꾸는 방향"이라는 게 벡터의 뺄셈·덧셈으로 표현된다는 뜻입니다. 물론 실제 문장 임베딩이 이렇게 딱 떨어지진 않지만, 의미가 기하학적 위치·방향으로 표현된다는 직관을 주기엔 충분합니다.

우리 눈은 3차원까지밖에 못 보지만, 임베딩은 보통 수백~수천 차원을 씁니다. 차원이 많을수록 더 미묘한 의미 차이를 담을 수 있습니다.


3. 유사도는 어떻게 재는가 - 코사인 유사도

두 벡터가 얼마나 비슷한지 재는 대표 방법이 코사인 유사도(Cosine Similarity) 입니다. 두 벡터가 이루는 각도를 봅니다.

  • 같은 방향(각도 0°) → 유사도 1 (매우 비슷)
  • 직각(90°) → 유사도 0 (무관)
  • 반대 방향(180°) → 유사도 -1 (반대)
import numpy as np def cosine(a, b): return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)) cosine(embed("환불 방법"), embed("결제 취소")) # 예: 0.87 (가까움) cosine(embed("환불 방법"), embed("점심 메뉴")) # 예: 0.12 (멂)

왜 거리가 아니라 각도일까요? 코사인은 벡터의 크기(길이)를 무시하고 방향만 봅니다. 문서가 길든 짧든, "무엇에 관한 내용인가(방향)"만 비교하고 싶기 때문입니다.

참고: 벡터를 미리 정규화(길이를 1로) 해두면, 코사인 유사도와 내적(dot product)이 같아집니다. 그래서 많은 벡터 DB가 정규화된 벡터에 내적을 써서 빠르게 검색합니다.


4. 임베딩 모델

임베딩을 만드는 것은 임베딩 전용 모델 입니다. 텍스트를 생성하는 LLM과는 목적이 다릅니다. 생성 모델은 "다음 단어"를, 임베딩 모델은 "의미 요약 벡터"를 내놓습니다.

고를 때 보는 지표들:

  • 차원 수: 384, 768, 1536, 3072 등. 높을수록 표현력은 좋지만 저장·연산 비용이 큽니다.
  • 다국어 지원: 한국어 성능이 중요하면 다국어/한국어 특화 모델을 확인하세요.
  • 최대 입력 길이: 한 번에 임베딩할 수 있는 토큰 한도.
  • 비대칭 여부: 검색용 모델 중엔 "질문(query)"과 "문서(passage)"를 다르게 인코딩하도록 설계된 것도 있습니다. 이 경우 넣을 때 프리픽스를 맞춰줘야 성능이 나옵니다.

가장 중요한 실무 규칙: 넣을 때(색인)와 찾을 때(질의)는 반드시 같은 모델을 써야 합니다. 서로 다른 모델의 벡터는 좌표계가 달라 비교 자체가 무의미합니다.


5. 임베딩으로 무엇을 하나

임베딩은 "의미의 좌표"이므로 활용처가 아주 넓습니다.

질문을 벡터로 바꾸고, 문서 벡터들 중 가까운 것을 찾습니다. 키워드가 겹치지 않아도 뜻이 통하면 찾아냅니다. RAG의 검색 단계가 바로 이것입니다.

5-2. 추천

"이 상품과 비슷한 상품", "이 글과 비슷한 글"을 벡터 거리로 찾습니다. 사용자가 좋아한 아이템들의 벡터 평균 근처를 추천하는 식으로도 씁니다.

5-3. 분류 · 클러스터링

  • 분류: 각 카테고리 예시들의 임베딩을 기준점으로 두고, 새 입력이 어느 쪽에 가까운지로 분류합니다.
  • 클러스터링: 라벨 없이도 비슷한 것끼리 그룹으로 묶습니다(문의 유형 자동 분류 등).

5-4. 중복 · 유사도 탐지

거의 같은 문서, 표절, 중복 문의를 유사도 임계값으로 걸러냅니다.

-- pgvector: 특정 글과 유사한 글 5개 추천 SELECT id, title, 1 - (embedding <=> :target_embedding) AS score FROM articles ORDER BY embedding <=> :target_embedding LIMIT 5;

6. 실무 포인트 - 차원, 정규화, 그리고 함정

  • 정규화를 습관화하라. 벡터를 L2 정규화해 두면 유사도 계산이 일관되고, 대부분의 벡터 DB 인덱스가 이를 전제로 최적화돼 있습니다.
  • 차원은 무조건 클수록 좋은 게 아니다. 차원이 커지면 저장 용량과 검색 비용이 올라갑니다. 최근 모델들은 일부 차원만 잘라 써도 성능이 유지되는(Matryoshka) 방식을 지원하기도 합니다. 정확도와 비용의 균형점을 찾으세요.
  • 모델을 바꾸면 전부 다시 임베딩. 임베딩 모델을 교체하면 좌표계가 바뀌므로, 저장된 모든 벡터를 재생성(재색인) 해야 합니다. 운영 중에는 큰 작업이니 미리 계획하세요.
  • 정규화·전처리를 색인과 질의에서 동일하게. 소문자화, 공백 처리, 프리픽스 규칙 등을 양쪽에서 똑같이 맞춰야 합니다.
  • 유사도 점수는 절대값보다 상대값. "0.8이면 무조건 관련 있다"가 아니라, 모델·도메인마다 분포가 다릅니다. 실제 데이터로 임계값을 튜닝하세요.
  • 긴 문서는 잘라서. 임베딩 모델의 입력 한도를 넘으면 뒤가 잘립니다. 문서를 의미 단위로 나눠 각각 임베딩하는 게 정석입니다.

마무리

임베딩은 "의미를 숫자 좌표로 바꿔, 가까우면 비슷하다고 판단하는" 단순하지만 강력한 도구입니다.

세 가지만 기억하세요.

  1. 임베딩은 텍스트의 의미 좌표다. 의미가 비슷하면 벡터가 가깝다.
  2. 유사도는 보통 코사인(각도) 으로 재고, 정규화해 두면 계산이 깔끔하다.
  3. 색인과 질의는 같은 모델·같은 전처리로. 모델을 바꾸면 전부 재색인이다.

임베딩을 이해하면 검색·추천·분류·RAG가 모두 "벡터 공간에서 가까운 점 찾기"라는 하나의 원리로 보이기 시작합니다.

me

강경원

Backend Developer

성능과 안정성으로 신뢰받는 백엔드 개발자 · 요즘은 AI/LLM을 서비스에 접목합니다

이력서 보기