주요 도구: OpenAIEmbeddings
지원되는 모델 목록
| MODEL | PAGES PER DOLLAR | PERFORMANCE ON MTEB EVAL | MAX INPUT |
|---|---|---|---|
| text-embedding-3-small | 62,500 | 62.3% | 8191 |
| text-embedding-3-large | 9,615 | 64.6% | 8191 |
| text-embedding-ada-002 | 12,500 | 61.0% | 8191 |
| 모델명 | 특징 | 추천 상황 |
|---|---|---|
| text-embedding-3-small | 가장 경제적이며 성능도 준수함 | 가성비가 중요한 대규모 서비스 |
| text-embedding-3-large | 최고 성능, 가격은 가장 비쌈 | 정확도가 최우선인 전문 검색 서비스 |
| text-embedding-ada-002 | 과거의 표준 모델 | 굳이 새로 쓸 필요 없는 구형 모델 |
어떤 모델을 사용해서 embedding 할건지 정하고 (여기서는 text-embedding-3-small) 텍스트를 임베딩하면 벡터화(숫자)되어 리스트에 담긴 것을 확인 가능합니다.
사용자의 질문 단 하나를 벡터로 바꿀 때
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
text = "임베딩 테스트를 하기 위한 샘플 문장입니다."
query_result = embeddings.➡️embed_query(text)
[-0.00776276458054781, 0.03680367395281792, 0.019545823335647583, -0.0196656696498394, 0.017203375697135925]
많은 양의 문서를 한꺼번에 벡터로 바꿀 때
-> 항상 문자열의 리스트를 입력받고, 각 문서에 대한 임베딩 벡터를 포함하는 2차원 리스트를 반환함.
| 구분 | embed_documents | embed_query |
|---|---|---|
| 입력 형태 | 리스트 (List of Strings) | 문자열 (Single String) |
| 주요 용도 | 데이터베이스(Vector Store) 구축용 | 사용자의 질문(검색어) 처리용 |
| 특징 | 여러 문서를 한꺼번에 배치(Batch) 처리 | 단일 문장의 의도 파악에 최적화 |
임베딩 차원 지정은 검색 속도와 저장 비용을 최적화하면서도, 핵심 의미 정보를 유지하여 시스템 효율과 정확도 사이의 최적의 밸런스를 찾기 위해 필요합니다.
'dimensions=1024' 옵션을 추가하여 차원 지정가능
embeddings_1024 = OpenAIEmbeddings(model="text-embedding-3-small", ➡️dimensions=1024)
비용 및 저장소 최적화: 차원을 줄이면 벡터 DB 용량이 감소하여 인프라 유지 비용이 대폭 절감됩니다.
검색 속도(Latency) 향상: 저차원 벡터는 유사도 계산 연산량이 적어 대규모 데이터셋에서 훨씬 빠른 응답 속도를 보장합니다.
정확도 밸런스: '매트료슈카 임베딩' 기술 덕분에 차원을 줄여도 핵심 의미 정보는 대부분 유지되므로, 성능 손실을 최소화하며 효율을 극대화할 수 있습니다.
환경 적응성: 메모리가 제한된 모바일이나 엣지 디바이스 환경에 맞춰 모델 부하를 조절할 수 있습니다.
주요 도구: CacheBackedEmbeddings
이유: 임베딩은 비용(돈/시간)이 듭니다. 똑같은 문장을 매번 새로 계산하는 건 비효율적이죠.
embeddings를 키-값 저장소에 캐싱하는 embedder 주변에 래퍼입니다.
캐시 임베더를 설정할 때는 from_bytes_store 메서드를 통해 다음 세 가지 핵심 부품을 연결합니다.
# 캐시를 지원하는 임베딩 생성
embedding = OpenAIEmbeddings()
cached_embedder = CacheBackedEmbeddings.from_bytes_store(
underlying_embeddings=embedding,
document_embedding_cache=➡️LocalFileStore("./cache/"), # 로컬 파일 저장소 설정
namespace=embedding.model # 기본 임베딩과 저장소를 사용하여 캐시 지원 임베딩을 생성
)
from langchain.embeddings import CacheBackedEmbeddings
from langchain.storage import InMemoryByteStore
store = ➡️InMemoryByteStore() # 메모리 내 바이트 저장소 생성
# 캐시 지원 임베딩 생성
cached_embedder = CacheBackedEmbeddings.from_bytes_store(
embedding, store, namespace=embedding.model
)
비용 절감과 데이터 보존이 중요한 실무 환경에는 LocalFile을, 속도가 중요하고 일회성인 작업에는 InMemory를 선택
주요 도구: HuggingFaceEmbeddings
특징: OpenAI API(유료) 없이 내 로컬(코랩) 환경에서 무료 오픈소스 모델로 갈아타는 방법.
intfloat/multilingual-e5-large (3~4위):
현재 오픈소스 모델 중 최상위권 성능입니다.
instruct 버전은 질문과 답변의 맥락을 더 잘 구분하도록 튜닝되어 있습니다.
BAAI/bge-m3 (6위):
한국어 임베딩의 교과서 같은 모델입니다.
성능이 안정적이고, 다국어 지원이 강력해서 실무에서 가장 많이 쓰입니다.
e5-base / e5-small (7~8위):
성능은 상위권 모델보다 조금 낮지만, 가볍고 속도가 매우 빠릅니다.
컴퓨터 자원이 부족하거나 빠른 응답이 필요할 때 선택합니다.
모델을 내 컴퓨터가 아닌 별도의 전용 서버(Endpoint)에 올려놓고 API 형태로 호출하는 방식
from langchain_huggingface.embeddings import HuggingFaceEndpointEmbeddings
model_name = "intfloat/multilingual-e5-large-instruct"
hf_embeddings = ➡️HuggingFaceEndpointEmbeddings(
model=model_name,
task="feature-extraction",
huggingfacehub_api_token=os.environ["HF_TOKEN"],
)
embedded_documents = hf_embeddings.embed_documents(texts)
embedded_query = hf_embeddings.embed_query("LangChain 에 대해서 알려주세요.")
내 컴퓨터(Local)의 GPU를 사용하여 임베딩을 생성합니다. 비용이 0원이며 보안이 중요한 프로젝트에 필수적
from langchain_huggingface.embeddings import HuggingFaceEmbeddings
model_name = "intfloat/multilingual-e5-large-instruct"
hf_embeddings = HuggingFaceEmbeddings(
model_name=model_name,
model_kwargs={"device": "cuda"}, # cuda, cpu-> 내 컴퓨터 가동
encode_kwargs={"normalize_embeddings": True},
# 추출된 벡터들의 길이를 1로 맞추는 정규화 작업 -> 유사도를 구할 때 복잡한 계산 없이 단순한 '내적'만으로도 정확한 비교가 가능
)
| 구분 | Dense (밀집) | b. Sparse (희소) | Multi-Vector (다중) |
|---|---|---|---|
| 대표 모델 | OpenAI | c. ColBERT | |
| 비유 | 문장의 전체적인 분위기 | 문장 속 핵심 단어 | 문장 속 모든 단어의 관계 |
| 수학적 특징 | 고정된 차원에 정보 압축 | 단어 사전 기반 점수 부여 | 문장을 여러 벡터로 분할 저장 |
| 장점 | 문맥 및 유사어 파악 능력이 좋음 | 고유명사를 정확하게 검색함 | 검색 정밀도가 가장 높음 |
| 단점 | 특정 단어 포함 여부 확인이 어려움 | 문맥(의미) 파악이 불가능함 | 저장 용량이 크고 속도가 느림 |
a. BGE-M3는 세 가지 방식을 모델 하나로 모두 구현하고 있음❕❕❕
현재 한국어를 포함한 다국어 검색에서 가장 가성비 좋고 강력한 오픈소스 모델이기 때문에 실무 표준으로 소개됨
from langchain_huggingface import HuggingFaceEmbeddings
model_name = ➡️"BAAI/bge-m3"
model_kwargs = {"device": "cuda"}
encode_kwargs = {"normalize_embeddings": True}
hf_embeddings = HuggingFaceEmbeddings(
model_name=model_name, model_kwargs=model_kwargs, encode_kwargs=encode_kwargs
)
랭체인의 HuggingFaceEmbeddings는 범용적이지만, BGE-M3 전용 기능(Sparse, Multi-vector 추출 등)을 세밀하게 제어하기에는 한계가 있습니다.
제조사가 제공하는 라이브러리를 쓰면 use_fp16(반정밀도 연산) 같은 속도 최적화 옵션을 더 직접적으로 사용할 수 있습니다.
# FlagEmbedding 설치
!pip install -qU FlagEmbedding
from FlagEmbedding import BGEM3FlagModel
bge_embeddings = BGEM3FlagModel(
"BAAI/bge-m3", use_fp16=True
) # use_fp16을 True로 설정하면 약간의 성능 저하와 함께 숫자를 표현하는 비트 수를 줄여 계산량을 줄어 빨라짐.
bge_embedded = bge_embeddings.encode(
texts,
batch_size=12,
max_length=8192, # 한번에 읽는 토큰수:작은 값을 설정하여 프로세스의 속도를 높일 수 있음.
)➡️["dense_vecs"]
["dense_vecs"]
->BGE-M3는 Dense, Sparse, ColBERT 결과를 동시에 생성하는 멀티태스킹 모델이므로, encode() 결과 중 필요한 데이터 형태(dense_vecs)만 명시적으로 추출하여 사용하려고 넣은 코드.
from FlagEmbedding import BGEM3FlagModel
bge_flagmodel = BGEM3FlagModel(
"BAAI/bge-m3", use_fp16=True
)
bge_encoded = bge_flagmodel.encode(texts, ➡️return_dense=True)
기존 밀집(Dense) 임베딩은 문맥은 잘 잡지만 "고유 명사(예: 제품명, 이름)" 검색에 약합니다. 이를 보완하기 위해 키워드 일치 방식(Lexical)의 가중치를 더해 검색 정확도를 높임
bge_flagmodel = BGEM3FlagModel(
"BAAI/bge-m3", use_fp16=True
) # use_fp16을 True로 설정하면 약간의 성능 저하와 함께 계산 속도가 빨라집니다.
bge_encoded = bge_flagmodel.encode(texts, ➡️return_sparse=True)
여기서는 BGE-M3 모델 사용함
lexical_scores1 = bge_flagmodel.compute_lexical_matching_score(
bge_encoded["lexical_weights"][0], bge_encoded["lexical_weights"][0]
)
# 0 <-> 0 자기 자신과의 비교
print(lexical_scores1)
0.30167388916015625
= 0번 문서와 0번 문서가 얼마나 '같은 단어'를 공유하는지 계산한 값입니다. 당연히 똑같은 단어들로 구성되어 있으니 모델이 판단한 최대 일치 점수가 나옵니다.
lexical_scores2 = bge_flagmodel.compute_lexical_matching_score(
bge_encoded["lexical_weights"][0], bge_encoded["lexical_weights"][1]
)
# 0 <-> 1 다른 문서와의 비교
print(lexical_scores2)
0 =두 문서 사이에 겹치는 단어가 하나도 없다. Dense 방식은 단어가 달라도 '분위기'가 비슷하면 0.8 같은 점수를 주지만, Sparse 방식은 글자 자체가 일치하지 않으면 가차 없이 0점.
문장 전체를 하나의 점(Vector)으로 찍는 대신, 단어 하나하나의 벡터를 모두 비교합니다. 계산량은 훨씬 많지만, 문맥적 유사도를 찾는 정밀도가 압도적으로 높아 고성능 검색 엔진 구현 시 사용
bge_flagmodel = BGEM3FlagModel(
"BAAI/bge-m3", use_fp16=True
) # use_fp16을 True로 설정하면 약간의 성능 저하와 함께 계산 속도가 빨라집니다.
bge_encoded = bge_flagmodel.encode(texts, ➡️return_colbert_vecs=True)
colbert_scores1 = bge_flagmodel.colbert_score(
bge_encoded["colbert_vecs"][0], bge_encoded["colbert_vecs"][0]
)
colbert_scores2 = bge_flagmodel.colbert_score(
bge_encoded["colbert_vecs"][0], bge_encoded["colbert_vecs"][1]
)
# 0 <-> 0
print(colbert_scores1)
# 0 <-> 1
print(colbert_scores2)
앞서 본 Sparse 방식이 "0점"을 줬던 문장들에 대해, ColBERT는 어떻게 반응하는지 비교하면 , ColBERT는 글자는 다르지만, 단어들의 세부적인 맥락을 보니 의미적 연관성이 있다고 판단해 tensor(0.3748)라고 점수를 부여해줌.
"ColBERT가 좋은 이유" Sparse 방식은 '아이폰'과 '스마트폰'을 완전히 다른 것으로 보지만, ColBERT는 두 단어를 구성하는 토큰(Token) 벡터들이 서로 유사한 영역에 있음을 감지한다.
국내 AI 기업인 Upstage(업스테이지)의 Solar 모델 실습
업스테이지는 검색의 정확도를 높이기 위해 비대칭 임베딩(Asymmetric Embedding) 전략을 사용하는데
질문과 답변은 문장 구조가 다르기 때문에 각각의 특성에 맞춰 학습시켜, 질문용 모델과 답변용 모델이 분리 되어 있다!
from langchain_upstage import UpstageEmbeddings
# 쿼리 전용 임베딩 모델
query_embeddings = UpstageEmbeddings(model="solar-embedding-1-large-query")
# 문장 전용 임베딩 모델
passage_embeddings = UpstageEmbeddings(model="solar-embedding-1-large-passage")
# 쿼리 임베딩
embedded_query = query_embeddings.embed_query("LangChain 에 대해서 상세히 알려주세요.")
# 임베딩 차원 출력-> 4096
len(embedded_query)
# 문서 임베딩
embedded_documents = passage_embeddings.embed_documents(texts)
앞서 배운 BGE-M3나 E5 모델은 1024차원이었지만 업스테이지 모델은 4096차원으로 정보를 4배나 더 세밀하게 쪼개서 저장합니다. 그만큼 문장의 미묘한 뉘앙스를 잡아내는 능력이 탁월하지만, 저장 공간(Vector DB)을 더 많이 차지한다는 트레이드오프가 있습니다.
유사도 결과에서도 한국어와 영어의 교차 검색에서 언어가 달라도 의미가 통하면 높은 점수를 주는 등 더 정교한 의미 검색이 가능함!
Ollama는 로컬 환경에서 대규모 언어 모델(LLM)을 쉽게 실행할 수 있게 해주는 오픈소스 프로젝트로 개발자들이 AI 모델을 자신의 컴퓨터에서 직접 실험하고 사용할 수 있도록 지원합니다.
from langchain_community.embeddings import OllamaEmbeddings
ollama_embeddings = ➡️OllamaEmbeddings(
model="nomic-embed-text", #768차원짜리 가벼운 모델. 로컬에서 돌려야해서 가장 대중적으로 쓰임.
)
쿼리와 문서를 인베딩하는 방식은 위 다른 실습과 동일하고 특이한 점은 유사도에서 점수가 높게 나왔는데 그 이유는 다른 모델과는 달리 정규화를 거치지 않은 순수 벡터 값을 그대로 내적했기 때문에, 벡터의 크기만큼 점수가 뻥튀기된 것입니다. 점수의 절댓값은 의미가 없고 상대적인 순위만 확인하면 됩니다.
[Query] LangChain 에 대해서 알려주세요.
====================================
[0] 유사도: 399.644 | LangChain은 초거대 언어모델로 애플리케이션을 구축하는 과정을 단순화합니다.
[1] 유사도: 356.518 | 랭체인 한국어 튜토리얼은 LangChain의 공식 문서, cookbook 및 다양한 실용 예제를 바탕으로 하여 사용자가 LangChain을 더 쉽고 효과적으로 활용할 수 있도록 구성되어 있습니다.
[2] 유사도: 322.359 | LangChain simplifies the process of building applications with large language models
[3] 유사도: 321.078 | 안녕, 만나서 반가워.
[4] 유사도: 224.858 | Retrieval-Augmented Generation (RAG) is an effective technique for improving AI responses.
GPT4All은 무료로 사용할 수 있는 로컬 실행 기반의 개인정보 보호를 고려한 챗봇으로
GPU 없이 CPU만으로도 돌아가는 저사양 환경을 위한 가성비 모델입니다.
업스테이지(4096), BGE-M3(1024)에 비해 훨씬 작은 384차원을 사용합니다. (실습에서 확인가능)
| 모델명 | 제공사 | 차원 | 주요 특징 | 추천 용도 |
|---|---|---|---|---|
| OpenAI | OpenAI | 1536 | 유료, 가장 표준적인 성능 | 범용 RAG 서비스 구축 |
| BGE-M3 | BAAI | 1024 | 오픈소스, 한국어 성능 최강 | 국내 검색 서비스, 하이브리드 검색 |
| Solar | Upstage | 4096 | 유료, 초고해상도, 비대칭 임베딩 | 정밀도가 중요한 전문 문서 검색 |
| GPT4All | Nomic | 384 | 무료, CPU 최적화(저사양 최적) | 개인 프로젝트 및 로컬 환경 |