임베딩이란?
임베딩(Embedding)은 텍스트, 이미지 등 비정형 데이터를 고정 차원의 실수 벡터(float 배열)로 변환하는 기술입니다. 의미적으로 유사한 데이터는 벡터 공간에서 가까이 위치하며, 이를 통해 유사도 검색, 분류, 클러스터링 등이 가능해집니다.
OpenAI Embedding API 사용하기
from openai import OpenAI
import numpy as np
client = OpenAI()
def get_embedding(text, model="text-embedding-3-small"):
response = client.embeddings.create(input=text, model=model)
return response.data[0].embedding
vec1 = get_embedding("맛있는 한국 음식 추천해주세요")
vec2 = get_embedding("한식 맛집을 알려주세요")
vec3 = get_embedding("파이썬 프로그래밍 기초를 배우고 싶습니다")
def cosine_similarity(a, b):
a, b = np.array(a), np.array(b)
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
print(f"음식-맛집: {cosine_similarity(vec1, vec2):.4f}") # ~0.92
print(f"음식-프로그래밍: {cosine_similarity(vec1, vec3):.4f}") # ~0.45
임베딩 모델 비교
| 모델 | 차원 | 가격 (1M tokens) | 특징 |
|---|---|---|---|
| text-embedding-3-small | 1536 | $0.02 | 비용 효율적 |
| text-embedding-3-large | 3072 | $0.13 | 높은 정확도 |
| text-embedding-ada-002 | 1536 | $0.10 | 이전 세대 |
| Cohere embed-v3 | 1024 | - | 다국어 강점 |
| BGE-M3 (오픈소스) | 1024 | 무료 | 로컬 실행 가능 |
PostgreSQL + pgvector
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
content TEXT NOT NULL,
embedding vector(1536),
metadata JSONB
);
CREATE INDEX ON documents
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);
SELECT id, content,
1 - (embedding <=> $1::vector) AS similarity
FROM documents
ORDER BY embedding <=> $1::vector
LIMIT 10;
Python에서 pgvector 사용
import psycopg2
from pgvector.psycopg2 import register_vector
conn = psycopg2.connect("dbname=mydb")
register_vector(conn)
cur = conn.cursor()
embedding = get_embedding("PostgreSQL 성능 튜닝 가이드")
cur.execute(
"INSERT INTO documents (content, embedding, metadata) VALUES (%s, %s, %s)",
("PostgreSQL 성능 튜닝 가이드", embedding, '{"category": "database"}')
)
query_vec = get_embedding("DB 최적화 방법")
cur.execute("""
SELECT content, 1 - (embedding <=> %s::vector) AS similarity
FROM documents ORDER BY embedding <=> %s::vector LIMIT 5
""", (query_vec, query_vec))
for row in cur.fetchall():
print(f"{row[1]:.4f} - {row[0]}")
RAG 파이프라인
def rag_answer(question):
q_vec = get_embedding(question)
cur.execute("""
SELECT content FROM documents
ORDER BY embedding <=> %s::vector LIMIT 3
""", (q_vec,))
context = "\n".join([row[0] for row in cur.fetchall()])
response = client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": f"다음 문서를 참고하여 답변하세요:\n{context}"},
{"role": "user", "content": question}
]
)
return response.choices[0].message.content
실전 팁
- 긴 문서는 500-1000 토큰 단위로 청킹(chunking)하여 임베딩하세요.
- text-embedding-3 모델은 dimensions 파라미터로 차원을 줄일 수 있습니다.
- 한국어 텍스트는 영어보다 토큰 수가 많으므로, 청크 크기를 글자 수 기준으로 조정하세요.
- pgvector의 HNSW 인덱스는 IVFFlat보다 검색 정확도가 높습니다.
댓글 0