0. 왜 임베딩이 중요한가?
- 검색(Search): “강원도 캠핑장 추천”을 검색할 때, 의미가 비슷한 문서를 빠르게 찾는다.
- 추천(Recommender): “이 노래 좋아하면 이런 곡도 좋아할 것”이라는 거리 근접성을 계산한다.
- RAG(Retrieval-Augmented Generation): LLM이 답변하기 전에 관련 청크를 찾아 프롬프트에 주입한다.
본질적으로 임베딩은 “의미가 비슷하면 벡터(숫자)가 가까워지도록” 학습된 함수이다.
1. 용어 먼저 정리하기
| 기호 | 의미 | 쉬운 비유 |
|---|---|---|
| V (Vocabulary size) | 모델이 직접 구분할 수 있는 서브워드 조각 개수. 일반적으로 30k ~ 50k. | 영어 알파벳 26자 + 자주 쓰는 ‘글자 조각’ 목록 |
| D (Embedding dimension) | 하나의 토큰을 표현할 숫자 좌표 수. BERT 계열은 768, 1024 등. | 단어를 설명할 “색, 크기, 맛 …” 속성 768가지 |
| n | 입력 문장이 토큰화돼 나온 토큰 길이. 입·출력마다 달라진다. | “안녕하세요” → n=2, “반갑습니다” → n=3 |
| 청크(Chunk) | 문서 일부(약 200-400토큰)를 의미 보존·LLM 프롬프트에 넣기 적당한 단위. | 한 장짜리 챕터 요약본 |
2. 임베딩의 역사 – “통계 → 문맥 → 다국어”
| 세대 | 대표 기법 | 핵심 아이디어 |
|---|---|---|
| ① 통계 시대 | 원-핫, TF-IDF | 빈도로만 표현, 문맥 無 → 희소·고차원 |
| ② 예측 시대 | Word2Vec (2013) | 주변 단어 예측(CBOW/Skip-gram)으로 의미 좌표 획득 |
| ③ 확장 | FastText | 서브워드 포함 → OOV(Out-Of-Vocab) 완화 |
| ④ 문서 단위 | Doc2Vec, Siamese | 문장·문단 직접 벡터 학습 |
| ⑤ 컨텍스트 시대 | ELMo (2018) | 양방향 LSTM, 다의어 구분 |
| ⑥ Transformer | BERT (2018~) | Self-Attention, Masked LM → 문맥 의존 임베딩 |
| ⑦ 응용 | Sentence-BERT, LaBSE | ‘문장 쌍 유사도’ 태스크 재학습 → RAG 최적 |
3. 내부 동작
토큰화(Tokenize) → ID 시퀀스 → 임베딩 행렬 조회(E) → (n × D) 행렬 → 풀링 → D차원 벡터
3-1. 토큰화
- 문자열을 서브워드로 쪼갠다.
- 각 서브워드는 V 크기 어휘집에서 고정 ID를 갖는다.
[1542, 2350], n=2.
3-2. 임베딩 행렬 조회
- 학습 완료된 E ∈ ℝV×D 가 GPU 메모리에 상주한다.
- ID = 1542 라면
E[1542]행을 그대로 복사한다. - n개 토큰이면 (n × D) 행렬이 쌓인다.
3-3. 시퀀스 압축(Pooling)
| 방법 | 직관 | 파이썬 한 줄 |
|---|---|---|
| 평균(Mean) | “모든 토큰 벡터 평균이 문장 의미” | vec = emb.mean(0) |
| 최대(Max) | “각 차원 중 가장 강한 특징” | vec = emb.max(0) |
| [CLS] | Transformer가 문장 대표로 내놓는 첫 토큰 | vec = emb[0] |
풀링이 n을 지워버리므로 최종 결과는 항상 D차원이다.
4. 예제로 따라가기
가정 : V=50k, D=768, 문장 길이 n=4.
“AI 임베딩 재미있다”
└▶ [1010, 4123, 9981, 7777] (n=4)
↓
E[1010]…E[7777] → (4 × 768) 행렬
↓ 평균
하나의 768차원 벡터 완성
→ 이제 이 벡터 한 줄이 “AI 임베딩 재미있다”의 의미 좌표다.
5. 청크가 벡터 하나가 되는 이유
| 구분 | 과정 | 결과 크기 |
|---|---|---|
| 문장 (n≈20) | 토큰화 → 조회 → 풀링 | 1 × 768 |
| 청크 (n≈300) | 동일 과정 | 1 × 768 |
| 문서(수천) | 너무 길어 여러 청크로 나눔 | 청크 개수 × 768 |
- 즉 길이가 다를 뿐 토큰-ID-조회-풀링 공식은 불변이다.
- RAG는 이렇게 만든 “청크 벡터”끼리 코사인 유사도를 계산해 “관련 청크 k개”를 뽑는다.
6. RAG 파이프라인 속 임베딩
flowchart LR
A[문서 PDF] -->|청크 분할| B[청크 리스트]
B --> C[SBERT 임베딩] --> D[(FAISS 인덱스)]
U[사용자 질문] --> Cq[질문 임베딩] --> D
D -->|Top-k ID| E{청크 원문}
E -->|컨텍스트| L[LLM 생성] --> O[답변]
- 오프라인: 문서 → 청크 → 벡터
.npy+id_map저장 후 인덱싱. - 온라인: 질문 벡터 ↔ 인덱스 → 관련 청크 → LLM 프롬프트 주입.
7. 메타데이터 주입과 하이브리드 검색
| 기법 | 한 줄 요약 | 장점 |
|---|---|---|
| 벡터+메타 Concatenate | [텍스트 벡터 ‖ 날짜 벡터] |
시간·카테고리 필터링까지 한 방에 |
| Sparse+Dense Hybrid | BM25 1차 후보 → 임베딩 재랭크 | 키워드·의미 둘 다 잡는다 |
| 재랭킹 가중치 | 최종 점수 = cosSim × (1+신뢰도) | 구조화 점수(저자, 권위 등) 반영 |
8. 실전 엔지니어링 팁
| 체크포인트 | 이유·팁 |
|---|---|
| 청크 크기 | 200~400 토큰. 너무 작으면 맥락 손실, 너무 크면 LLM 입력 초과. |
.npy |
np.save()로 (N,768) 한 번 저장 → 모델 재실행 無. |
id_map |
np.save("id_map.npy", np.array(pks)) → 검색 결과 해석용. |
| 인덱스 선택 | IndexFlatIP: 소규모 디버그 / HNSW, IVF: 대용량 운영 |
| 8-bit 양자화 | 메모리 4×↓, 속도 ↑. 검색 정확도 1~2% 감소 수준. |
| GPU-FAISS | 수억 벡터도 ms 단위 검색. Docker로 쉽게 배포 가능. |
9. 최신 트렌드
- 경량화 모델: DistilBERT, TinyBERT, MiniLM → 모바일 온-디바이스 임베딩.
- LoRA·QLoRA 파인튜닝: 수 MB 추가 파라미터만으로 도메인 적응.
- 멀티모달 벡터: CLIP, Gemini Vision으로 텍스트+이미지 검색.
- pgvector v4: Postgres에서도 Dense+Sparse 동시 질의.
- RAFT + GPU-FAISS: 대용량 인덱스 장애 복구·마이그레이션 자동화.
10. 한계와 주의점
| 영역 | 제약·위험 |
|---|---|
| 다의어 완전 해결 X | BERT도 극단적 문맥은 오해할 수 있다. |
| OOV 특수문자 | OCR 오류·이모지 등은 서브워드 분해로 의미 희석. |
| 데이터 편향 | 훈련 코퍼스 쏠림 → 벡터 편향 → 추천·검색 편향. |
| 운영 비용 | 대형 Transformer 100 ms↑ → Distillation·캐싱 필수. |
11. 치트시트 (요약표)
| 질문 | 3초 답 |
|---|---|
| 임베딩이란? | 텍스트 ➜ 고정 차원 벡터 변환 함수 |
| V, D? | V = 어휘집 크기, D = 벡터 차원 |
| 문장·청크 차이? | 길이만 다름. 과정은 동일 → 둘 다 벡터 하나 |
| RAG 흐름? | 질문 벡터 ↔ 인덱스 ↔ 관련 청크 ↔ LLM |
| 필수 파일? | .npy 벡터, id_map 매핑 |
| 좋은 청크 크기? | 200 ~ 400 토큰 |
12. 마무리
임베딩은 “텍스트를 숫자로 번역” 하는 인공지능의 관문이다.
Word2Vec에서 BERT·SBERT까지 진화하며 검색, 추천, RAG의 필수 모듈이 되었고,
메타데이터 주입·하이브리드 검색·경량화로 서비스 품질과 운영 효율을 동시에 잡는다.
참고 자료
- Mikolov et al., Efficient Estimation of Word Representations in Vector Space (2013)
- Reimers & Gurevych, Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks (2019)
- Facebook Research, FAISS: https://github.com/facebookresearch/faiss
- Sentence-Transformers: https://sbert.net
- OpenAI text-embedding-ada-002 API: https://platform.openai.com/docs/api-reference/embeddings