안녕하세요! 테디노트님의 RAG 비법노트 36일차 학습 기록입니다.
입사 후에는 공부 시간을 내기가 정말 쉽지 않지만, 틈틈이 배워가며 기록을 남기려 합니다 😊
오늘은 이전 시간(35일차) 에 배운 “임베딩 개념”을 바탕으로,
실제로 OpenAI Embeddings API를 활용해 텍스트를 벡터로 변환하는 과정을 실습했습니다.
1. 임베딩이란?
간단히 복습하자면, 임베딩(Embeding)은 문서나 문장을 숫자 벡터(고정 차원)로 변환하는 과정입니다.
이 벡터는 의미적으로 유사한 문장끼리 벡터 공간에서 가까운 위치에 놓이도록 설계되어 있습니다.
즉,
“비슷한 의미를 가진 문장은 가까이, 다른 의미는 멀리” 라는 원리에 따라 텍스트를 수학적으로 표현하는 것이죠.
2. OpenAI Embeddings 모델 개요
OpenAI는 현재 text-embedding-3 시리즈를 주요 임베딩 모델로 제공합니다.
이 모델들은 이전 text-embedding-ada-002 대비 성능과 효율이 크게 개선되었습니다.
| 모델 | 차원(Dim) | 성능 (MTEB) | 1달러당 처리량 | 특징 |
| text-embedding-3-small | 1,536 | 62.3% | 62,500 페이지 | 빠르고 저렴 |
| text-embedding-3-large | 3,072 | 64.6% | 9,615 페이지 | 최고 성능 |
| text-embedding-ada-002 | 1,536 | 61.0% | 12,500 페이지 | 이전 세대 모델 |
🔍 참고: OpenAI Embeddings 공식 문서
3. OpenAIEmbeddings로 텍스트 임베딩 생성
LangChain에서는 OpenAIEmbeddings 클래스를 사용해 간단히 벡터를 생성할 수 있습니다.
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(model='text-embedding-3-small')
print(embeddings.model)
text = '임베딩 테스트를 하기 위한 샘플 문장입니다.'
query_result = embeddings.embed_query(text)
print(query_result[:5])
print(len(query_result))
출력 결과:
text-embedding-3-small
[-0.00776276458054781, 0.03680367395281792, 0.019545823335647583, -0.0196656696498394, 0.017203375697135925]
1536
이렇게 하면 text 문장이 1536차원 벡터로 변환됩니다.
이 벡터는 리스트 형태이며, 각 숫자는 의미적 좌표를 나타냅니다.
4. Document 임베딩
문장 하나가 아닌 여러 문서를 한 번에 임베딩할 수도 있습니다.
doc_result = embeddings.embed_documents(
[text, text, text, text]
)
print(len(doc_result)) # 문서 개수
print(len(doc_result[0])) # 각 벡터의 차원 수
여기서 doc_result는 4개의 문서 각각에 대한 임베딩 벡터를 포함하며, 각 벡터는 1536차원의 float 리스트로 구성됩니다.
5. 차원(Dimensions) 조정
text-embedding-3 시리즈에서는 dimensions파라미터를 통해 임베딩 벡터의 크기를 줄일 수 있습니다.
embeddings_1024 = OpenAIEmbeddings(
model="text-embedding-3-small",
dimensions=1024
)
len(embeddings_1024.embed_documents([text])[0])
→ 출력 결과는 1024차원 벡터,
즉, 계산 속도와 저장 공간을 절약할 수 있는 옵션입니다.
이는 대규모 문서 임베딩(RAG 파이프라인 구축 시)에 매우 유용합니다.
6. 문장 유사도 계산
이제 여러 문장을 임베딩한 뒤, cosine_similarity를 이용해 유사도를 계산해봅니다.
from sklearn.metrics.pairwise import cosine_similarity
sentences = [
"안녕하세요? 반갑습니다.",
"안녕하세요? 반갑습니다!",
"안녕하세요? 만나서 반가워요.",
"Hi, nice to meet you.",
"I like to eat apples."
]
embedded_sentences = embeddings_1024.embed_documents(sentences)
def similarity(a, b):
return cosine_similarity([a], [b])[0][0]
for i, s1 in enumerate(embedded_sentences):
for j, s2 in enumerate(embedded_sentences):
if i < j:
print(f"[유사도 {similarity(s1, s2):.4f}] {sentences[i]} <-> {sentences[j]}")
출력 결과:
[유사도 0.9644] 안녕하세요? 반갑습니다. <-> 안녕하세요? 반갑습니다!
[유사도 0.8376] 안녕하세요? 반갑습니다. <-> 안녕하세요? 만나서 반가워요.
[유사도 0.5042] 안녕하세요? 반갑습니다. <-> Hi, nice to meet you.
[유사도 0.1362] 안녕하세요? 반갑습니다. <-> I like to eat apples.
[유사도 0.8142] 안녕하세요? 반갑습니다! <-> 안녕하세요? 만나서 반가워요.
[유사도 0.4790] 안녕하세요? 반갑습니다! <-> Hi, nice to meet you.
[유사도 0.1318] 안녕하세요? 반갑습니다! <-> I like to eat apples.
[유사도 0.5128] 안녕하세요? 만나서 반가워요. <-> Hi, nice to meet you.
[유사도 0.1409] 안녕하세요? 만나서 반가워요. <-> I like to eat apples.
[유사도 0.2249] Hi, nice to meet you. <-> I like to eat apples.
한국어 문장 간에는 높은 유사도가,
영어 문장과의 유사도는 낮게 계산되는 걸 확인할 수 있습니다.
즉, OpenAI의 다국어 임베딩은 언어 혼용 상황에서도 의미 기반 비교가 가능합니다.
마무리
오늘은 OpenAIEmbeddings 클래스를 활용해
텍스트 임베딩을 생성하고, 차원 축소 및 문장 유사도 계산까지 실습해보았습니다.
💬 한 줄 요약
OpenAI의 text-embedding-3 시리즈는 빠르고 강력하며, RAG 시스템의 기반이 되는 핵심 모듈이다.
읽어주셔서 감사합니다.