🤖 AI/ML

Embedding Model

텍스트를 벡터로 변환하는 모델

📖 상세 설명

Embedding Model은 텍스트, 이미지, 오디오 등 비정형 데이터를 고정 길이의 수치 벡터(임베딩)로 변환하는 AI 모델입니다. 이 벡터는 원본 데이터의 의미적 특성을 수학적으로 인코딩하여, 컴퓨터가 유사도 계산, 검색, 분류 등을 수행할 수 있게 합니다.

초기에는 Word2Vec, GloVe 같은 정적 임베딩이 주류였지만, 2018년 BERT 등장 이후 Transformer 기반 모델이 대세가 되었습니다. 현재는 OpenAI text-embedding-3, Cohere Embed v3, Google Gecko 등 상용 API와 BGE, E5, GTE 같은 오픈소스 모델이 경쟁하고 있습니다.

임베딩 모델은 텍스트를 입력받아 보통 256~3072차원의 실수 벡터를 출력합니다. 의미가 비슷한 텍스트는 벡터 공간에서 가깝게, 다른 텍스트는 멀리 위치합니다. 이 특성 덕분에 코사인 유사도나 유클리드 거리로 의미적 유사성을 수치화할 수 있습니다.

실무에서 Embedding Model은 RAG(검색 증강 생성), 시맨틱 검색, 추천 시스템, 중복 탐지, 클러스터링의 핵심 컴포넌트입니다. Vector Database(Pinecone, Weaviate, Milvus)와 결합하여 수억 건의 문서에서 밀리초 내에 관련 정보를 찾아냅니다.

💻 코드 예제

# Embedding Model 활용 예제
from openai import OpenAI
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

client = OpenAI()

# 1. OpenAI text-embedding-3-small 사용 ($0.02/1M tokens)
def get_embedding(text: str, model="text-embedding-3-small"):
    response = client.embeddings.create(input=text, model=model)
    return response.data[0].embedding

# 임베딩 생성
texts = [
    "Python은 데이터 분석에 많이 사용됩니다",
    "파이썬은 머신러닝 분야에서 인기가 높습니다",
    "자바스크립트는 웹 개발에 필수입니다",
    "오늘 날씨가 좋네요"
]
embeddings = [get_embedding(t) for t in texts]

# 2. 유사도 계산
similarity_matrix = cosine_similarity(embeddings)
print("텍스트 유사도 행렬:")
print(np.round(similarity_matrix, 2))
# Python-파이썬: 0.92 (높음), Python-날씨: 0.31 (낮음)

# 3. 시맨틱 검색 구현
query = "데이터 사이언스 프로그래밍 언어"
query_emb = get_embedding(query)

scores = cosine_similarity([query_emb], embeddings)[0]
ranked_results = sorted(zip(texts, scores), key=lambda x: x[1], reverse=True)

print("\n검색 결과:")
for text, score in ranked_results:
    print(f"  {score:.3f}: {text}")

# 4. 오픈소스 모델 (sentence-transformers)
from sentence_transformers import SentenceTransformer

# BGE 모델 - 한국어 지원, 무료
model = SentenceTransformer('BAAI/bge-m3')  # 다국어 지원

embeddings = model.encode(texts)
print(f"\n임베딩 차원: {embeddings.shape}")  # (4, 1024)

# 5. 배치 처리 + Vector DB 저장 (Chroma 예시)
import chromadb
from chromadb.utils import embedding_functions

chroma_client = chromadb.Client()
openai_ef = embedding_functions.OpenAIEmbeddingFunction(
    model_name="text-embedding-3-small"
)

collection = chroma_client.create_collection(
    name="documents",
    embedding_function=openai_ef
)

# 문서 추가 (임베딩 자동 생성)
collection.add(
    documents=texts,
    ids=[f"doc_{i}" for i in range(len(texts))]
)

# 유사 문서 검색
results = collection.query(
    query_texts=["AI 프로그래밍"],
    n_results=2
)
print(f"\n검색된 문서: {results['documents']}")

🗣️ 실무에서 이렇게 말하세요

💬 회의에서
"RAG 파이프라인의 검색 품질이 낮은 건 임베딩 모델 문제일 수 있어요. text-embedding-ada에서 text-embedding-3-large로 바꾸면 MTEB 벤치마크 기준 15% 정도 성능이 올라갑니다."
💬 면접에서
"임베딩 모델 선택 시 고려하는 건 세 가지입니다. 첫째 차원 수(검색 속도 vs 정확도 트레이드오프), 둘째 max token 길이(긴 문서 처리 가능 여부), 셋째 다국어 지원(한국어 성능) 입니다."
💬 기술 토론에서
"도메인 특화 검색이라면 Fine-tuning을 고려해보세요. 법률 문서에 일반 임베딩 모델 쓰면 전문 용어를 못 잡는데, 법률 코퍼스로 contrastive learning 하면 recall이 30% 이상 오릅니다."

⚠️ 흔한 실수 & 주의사항

임베딩 모델 변경 시 기존 벡터 재사용

모델마다 벡터 공간이 완전히 다릅니다. 모델을 바꾸면 기존에 저장된 모든 임베딩을 다시 생성해야 합니다. 그렇지 않으면 검색 결과가 엉망이 됩니다.

긴 문서를 그대로 임베딩

대부분의 임베딩 모델은 512~8192 토큰 제한이 있습니다. 긴 문서는 청크로 분할하고, 각 청크를 별도 임베딩한 뒤 검색 시 조합해야 합니다.

올바른 방법: 쿼리와 문서 임베딩 구분

일부 모델(E5, BGE)은 쿼리 앞에 "query: ", 문서 앞에 "passage: " 프리픽스를 붙여야 최적 성능이 나옵니다. 모델 문서를 반드시 확인하세요.

🔗 관련 용어

📚 더 배우기