
1. 임베딩이란 ?
임베딩(Embedding)이란 텍스트, 이미지, 오디오 등의 데이터를 숫자 배열(벡터)로 변환하는 것이다.
"사과" → [0.12, -0.34, 0.91, 0.07, -0.55, ...] (1536개 숫자)
"과일" → [0.11, -0.31, 0.88, 0.09, -0.51, ...]
"자동차" → [0.55, 0.72, 0.03, 0.44, 0.21, ...]

핵심 원리는 단순하다. 의미가 비슷한 텍스트는 벡터 공간에서 가까운 위치에 놓인다.
2. 왜 임베딩을 쓰는가 — 키워드 검색의 한계
전통적인 키워드 검색은 단어가 정확히 일치해야 결과가 나온다.
키워드 검색
- 사용자: "강아지 훈련"
- 결과: "강아지 훈련" 포함 문서만 반환
→ "반려견 교육", "펫 트레이닝" 같은 연관 결과 누락
임베딩 검색
- 사용자: "강아지 훈련"
- 결과: 의미적으로 가까운 문서 순으로 반환
→ "반려견 교육", "펫 트레이닝" 모두 검색 가능
단어가 달라도 의미가 비슷하면 찾아준다는 것이 가장 큰 장점이다.
최근 많이 사용하는 RAG 아키텍처에서 LLM에게 관련 문서를 제공할 때도 임베딩 검색이 핵심 역할을 한다.
3. 임베딩 모델 종류
| 모델 | 제공사 | 차원 수 | 특징 |
|---|---|---|---|
amazon.titan-embed-text-v1 |
AWS Bedrock | 1536 | AWS 인프라와 통합 용이 |
amazon.titan-embed-text-v2:0 |
AWS Bedrock | 1024 / 512 / 256 | 차원 선택 가능 |
text-embedding-3-small |
OpenAI | 1536 | 가볍고 빠름 |
text-embedding-3-large |
OpenAI | 3072 | 고정밀 |
모델 선택 시 고려할 것:
- 언어 지원: 한국어 텍스트는 다국어 지원 모델이 유리
- 차원 수: 크면 정확하지만 저장/연산 비용 증가
- 인프라: AWS를 쓴다면 Bedrock Titan이 레이턴시/비용 유리
4. embed_query vs embed_documents
model.embed_query("검색어") # 검색 쿼리 1개
model.embed_documents(["문서1", "문서2", ...]) # 저장할 문서 여러 개
| 메서드 | 용도 | 특징 |
| embed_query() | 검색어 임베딩 단건 | retrieval 최적화 |
| embed_documents() | 저장 문서 임베딩 배치 처리 | content 최적화 |
일부 모델(Titan v1 등)은 두 메서드가 내부적으로 동일하게 동작하지만,
최신 모델은 실제로 다른 표현을 사용하므로 저장 시엔 embed_documents, 검색 시엔 embed_query를 쓰는 게 원칙이다.
5. 벡터 저장소 종류
| 저장소 | 방식 | 특징 |
| FAISS | 파일 기반 인메모리 | 빠른 검색, 파일(S3)에 저장 |
| pgvector | PostgreSQL 확장 | 기존 RDB와 통합, SQL JOIN 가능 |
| Pinecone | 완전 관리형 Saas | 설치 불필요, 대용량에 강함, 유료 |
| Chroma | 경량 로컬 벡터 DB | 개발/프로토타이핑에 적합 |
| Qdrant | 오픈소스 벡터 DB | 필터링 성능 강점 |
- 이미 PostgreSQL을 쓰고 있다면 → pgvector
- 파일/문서 단위 지식베이스라면 → FAISS + S3
- 수억 건 이상 대용량이라면 → Pinecone, Qdrant 등 전용 서비스
6. 실전 코드 — LangChain + Bedrock Titan
설치
pip install langchain-aws
임베딩 생성
from langchain_aws import BedrockEmbeddings
model = BedrockEmbeddings(
model_id="amazon.titan-embed-text-v1",
region_name="ap-northeast-2"
)
# 단건 임베딩
vector = model.embed_query("검색어를 입력하세요")
print(len(vector)) # 1536
# 배치 임베딩
texts = ["문서 A 내용", "문서 B 내용", "문서 C 내용"]
vectors = model.embed_documents(texts)
print(len(vectors)) # 3
print(len(vectors[0])) # 1536
유사도 직접 계산 (저장소 없이)
import numpy as np
def cosine_similarity(a: list, b: list) -> float:
a, b = np.array(a), np.array(b)
return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))
vec1 = model.embed_query("강아지")
vec2 = model.embed_query("반려견")
vec3 = model.embed_query("자동차")
print(cosine_similarity(vec1, vec2)) # 높음 (유사)
print(cosine_similarity(vec1, vec3)) # 낮음 (비유사)
7. 임베딩 품질을 높이는 전처리 팁
1. 제목을 prefix로 붙이기
text = f"[title: {title}] {description}"
2. 불필요한 문자 제거
import re
text = re.sub(r'[^\w\s가-힣]', ' ', text)
text = ' '.join(text.split())
3. 긴 텍스트는 청킹
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_text(long_text)
vectors = model.embed_documents(chunks)
4. 메타데이터를 텍스트에 포함
text = f"[카테고리: {category}] [태그: {tags}] {title} {description}"
728x90
'Python' 카테고리의 다른 글
| PostgreSQL과 PgVector에 관하여 (0) | 2026.04.10 |
|---|---|
| Video Generation Pipeline 구조 분리 기록 (0) | 2026.03.22 |
| LongCat Avatar: num_segments 자동 계산 로직 추가 (0) | 2026.03.19 |
| pthread_setaffinity_np failed for thread ... Invalid argument. Specify the number of threads explicitly so the affinity is not set. (0) | 2026.03.18 |
| Fish-speech tts 테스트 및 문제 해결(3) (0) | 2026.03.16 |