본문 바로가기
AI2024년 6월 25일6분 읽기

벡터 임베딩 이해하기 — 텍스트를 숫자로 바꾸는 원리

YS
김영삼
조회 138

임베딩이란?

임베딩(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-small1536$0.02비용 효율적
text-embedding-3-large3072$0.13높은 정확도
text-embedding-ada-0021536$0.10이전 세대
Cohere embed-v31024-다국어 강점
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

아직 댓글이 없습니다.
Ctrl+Enter로 등록