# 6.1 Embedding의 개념과 Cosine Similarity

OpenAI Embedding API를 효과적으로 사용하려면, Embedding의 근본적인 개념과 그 활용 방식, 그리고 Embedding 간의 유사도를 비교하는 데 가장 널리 쓰이는 Cosine Similarity에 대한 이해가 중요합니다. 이 절에서는 Embedding이란 무엇인지부터 시작하여 Cosine Similarity의 수학적 정의, 구현과 활용에 이르기까지 순차적으로 자세히 설명하겠습니다.

## 6.1.1 Embedding이란 무엇인가

"Embedding"은 자연어 처리(NLP) 분야에서 텍스트 데이터를 의미 있는 벡터로 변환하는 기술입니다. 말 그대로 "임베딩(넣어넣기)"은 고차원 의미를 저차원 수치공간으로 매핑하는 과정을 뜻합니다. 즉, 사람이 이해하는 "의미"를 기계가 계산할 수 있는 수치로 변환하는 것을 말합니다.

### Embedding의 요소

* 일반적으로 단어나 문장을 Embedding하면, 해당 텍스트는 n차원의 실수 벡터 (예: \[0.13, -0.87, 1.02, ...]) 로 변환됩니다.
* 이 벡터는 텍스트의 의미적 특성을 내포하고 있어, 비슷한 의미의 텍스트는 벡터 공간 상에서도 서로 가깝게 위치합니다.

#### Embedding의 예시

| 텍스트   | 벡터 (단순화된 형태)         |
| ----- | -------------------- |
| "고양이" | \[0.21, -0.03, 0.77] |
| "개"   | \[0.19, -0.01, 0.75] |
| "자동차" | \[-0.58, 0.45, 0.12] |

위 예시에서 ‘고양이’와 ‘개’는 유사한 의미(반려동물)이므로 비슷한 방향의 벡터를 가집니다. 반면 ‘자동차’는 별개의 개념이기 때문에 벡터 공간상에서 방향이 다릅니다.

## 6.1.2 OpenAI Embedding 모델

OpenAI는 Embedding 생성을 위한 전용 모델을 제공합니다. 대표적인 모델은 다음과 같습니다:

* text-embedding-ada-002 (가장 최신, 성능 대비 비용 효율 우수)
* text-embedding-3-small / text-embedding-3-large (2024년 기준 최신)

이 모델들은 단어 단위가 아닌 문장, 단락, 문서 수준의 의미 구조를 파악하여 고차원 벡터(예: 1536차원)로 변환해줍니다.

### 간단한 코딩 예 (Python + openai 패키지):

```python
import openai

openai.api_key = "your-api-key"

response = openai.embeddings.create(
    model="text-embedding-ada-002",
    input="올해 가장 인기 있는 여행 도시는 어디인가?"
)

embedding_vector = response.data[0].embedding
print(f"임베딩 벡터 차원: {len(embedding_vector)}")  # 일반적으로 1536 차원
```

## 6.1.3 임베딩 벡터 비교: Cosine Similarity

벡터로 변환하는 목적은 “비슷한 의미의 텍스트인지”를 비교하기 위함입니다. 이를 위해 벡터 간의 유사도를 측정하는 지표가 필요하며, 대부분의 경우 Cosine Similarity(코사인 유사도)를 사용합니다.

### Cosine Similarity 정의

코사인 유사도는 두 벡터 사이의 "각도"를 측정해 이들이 얼마나 유사한 방향을 갖는지를 나타냅니다. 수식은 다음과 같습니다:

\[\
\text{cosine\_similarity}(A, B) = \frac{A \cdot B}{|A| \cdot |B|}\
]

여기서,

* ( A \cdot B ): 두 벡터의 내적(dot product)
* ( |A| ): 벡터 A의 크기 (Euclidean norm)
* 결과값은 -1 \~ 1 사이의 실수
  * 1: 완전히 같은 방향 (즉, 매우 유사한 의미)
  * 0: 직각 (비슷하지 않음)
  * -1: 반대 방향 (의미가 서로 상반됨)

### 예시

```python
from numpy import dot
from numpy.linalg import norm
import numpy as np

def cosine_similarity(v1, v2):
    return dot(v1, v2) / (norm(v1) * norm(v2))

vec1 = np.array([0.21, -0.03, 0.77])
vec2 = np.array([0.19, -0.01, 0.75])
vec3 = np.array([-0.58, 0.45, 0.12])

print(cosine_similarity(vec1, vec2))  # 매우 유사 → 0.99 등
print(cosine_similarity(vec1, vec3))  # 유사하지 않음 → 0.1 ~ 0.3
```

## 6.1.4 Embedding + Cosine Similarity의 실제 활용

실제 개발 환경에서는 다양한 형태로 이 기술 조합이 활용됩니다:

### 문서 검색 시스템 (RAG)

* 유저의 질의(Query)를 Embedding한 후,
* 방대한 문서 벡터들과 Cosine Similarity를 구해 가장 유사한 문서 추출
* 이를 LLM에게 제공해 답변을 생성

### 챗봇의 문맥 회수 (Context Retrieval)

* 이전 발화 내용 중 중요 요소를 벡터로 저장
* 현재 대화와의 유사도 비교 후 관련 맥락 자동 추출

### 데이터 클러스터링

* 임베딩 벡터들을 차원 축소(PCA, t-SNE) 후 시각화하거나
* K-means, DBSCAN 등의 클러스터링에 활용해 의미 기반 자동 분류

## 6.1.5 Cosine Similarity 외 다른 유사도 지표

Cosine Similarity는 문장 길이 차이의 영향을 덜 받기 때문에 많이 쓰이지만, 경우에 따라 다음과 같은 거리 함수들도 사용됩니다:

* Euclidean Distance (유클리드 거리): 절대 거리 중심
* Manhattan Distance: 좌표 상 축 중심 거리 측정
* Dot Product 자체: 빠르지만 정규화 부족

그러나 대부분 Embedding 기반 검색에서는 cosine similarity가 가장 안정적이고 의미 보존력이 뛰어납니다.

## 6.1.6 실전 Tip: 벡터 정규화는 필수

Embedding 벡터 비교 전에는 정규화를 수행하거나, 벡터를 사전에 L2 노멀라이즈(L2 normalize)된 상태로 저장하고 비교하는 것이 효율적입니다.

```python
def normalize(vec):
    return vec / norm(vec)
```

이는 검색 엔진 구현 시 효율적인 인덱싱과 빠른 검색을 가능케 합니다 (FAISS나 Pinecone 등에서도 내부적으로 정규화 적용).

## 6.1.7 요약

| 항목        | 설명                                               |
| --------- | ------------------------------------------------ |
| Embedding | 텍스트를 의미 기반의 벡터로 변환                               |
| 목표        | 의미적으로 유사한 텍스트를 수치적으로 가까운 벡터로 표현                  |
| 비교 방식     | Cosine Similarity(벡터 간 각도 유사도)                   |
| 활용 분야     | 검색엔진, 챗봇 프롬프트 회수, 분류기, 유사 문서 검출 등                |
| 라이브러리 예   | numpy, scikit-learn, FAISS, Pinecone, Weaviate 등 |

다음 절에서는 Embedding을 실제로 어떤 방식으로 생성하고 활용하는지, 문서 단위의 벡터화와 OpenAI API를 사용하는 실습 단계를 안내합니다. 이제 개념을 이해했으니, 본격적인 구현으로 넘어가보겠습니다.
