FastEmbed: Qdrant의 효율적 임베딩 생성 파이썬 라이브러리

FastEmbed: Qdrant의 효율적 임베딩 생성 파이썬 라이브러리 (FastEmbed: Qdrant's Efficient Python Library for Embedding Generation)

데이터 사이언스나 머신러닝을 다루다 보면 어느 순간 모델, 라이브러리, 프레임워크의 미로 속에 서 있는 자신을 발견하게 돼요. 어떤 모델을 고를까, 임베딩 크기는 어떻게 할까, 토크나이징은 어떻게 접근할까 — 작업을 시작할 때 맞닥뜨리는 건 이런 질문들뿐이죠. 임베딩 작업을 좀 더 쉽고 직관적으로 만들고 싶어 하는 데이터 사이언티스트들이 많다는 걸 우리도 잘 알고 있었어요. 그래서 만들었습니다. 속도와 효율, 사용성에 초점을 맞춘 파이썬 라이브러리, FastEmbed를요. NLP 임베딩 사용 사례의 80%는 커버하는, 바로 쓸 수 있는 기본 워크플로우도 함께 만들어 두었어요.

출처: 공식문서

지금 임베딩을 만드는 상황

보통 임베딩은 내부적으로 PyTorch나 TensorFlow 모델을 활용해서 만들죠. 그런데 이런 라이브러리들은 사용 난이도와 연산 속도 측면에서 비용이 들어요. 모델 추론과 파인튜닝 같은 개선 작업 두 가지를 모두 겨냥해서 만들어진 프레임워크라서 어쩌면 당연한 일이겠죠.

그래서 우리는 텍스트 임베딩을 빠르고 효율적으로 만드는 작업 하나에 집중하는 작은 라이브러리를 만들었어요. 처음에는 최고 수준의 트랜스포머 모델 몇 개만 골라서 시작하기로 했죠. 작고 특정 사용 사례에 집중하다 보니 불필요한 의존성 없이 가볍게 유지할 수 있었어요. 지원하는 모델은 제한하고, 모델 가중치는 양자화하고, ONNX Runtime과 매끄럽게 통합했어요. FastEmbed는 추론 시간, 리소스 사용량, 성능(리콜/정확도) 사이에서 균형을 잡아 줍니다.

텍스트 문서 임베딩 예제 빠르게 보기

텍스트 문서를 임베딩하는 게 얼마나 단순해졌는지 예제로 바로 보여드릴게요. 먼저 FastEmbed를 설치합니다.

pip install fastembed

그다음 문서 목록에 대한 임베딩을 생성합니다.

from typing import List
from fastembed import TextEmbedding

documents: List[str] = [
    "Hello, World!",
    "fastembed is supported by and maintained by Qdrant."
]
embedding_model = TextEmbedding()
embeddings: List[np.ndarray] = list(embedding_model.embed(documents))

마지막 세 줄이 꽤 많은 일을 대신 해 줘요. 양자화된 모델을 내려받고, ONNXRuntime으로 로드하고, 문서에 대한 배치 임베딩 생성을 실행하는 것까지 전부 여기서 처리됩니다.

코드 자세히 살펴보기

조금 더 고급 예제 코드를 한 줄씩 뜯어볼게요.

from fastembed import TextEmbedding

여기서 FastEmbed의 TextEmbedding 클래스를 가져오고 있어요. 고른 텍스트 모델을 기반으로 임베딩을 생성하는 핵심 클래스죠. 기본값으로 BAAI/bge-small-en-v1.5를 로드합니다.

documents: List[str] = [
    "passage: Hello, World!",
    "query: How is the World?",
    "passage: This is an example passage.",
    "fastembed is supported by and maintained by Qdrant."
]

documents라는 이 목록에 임베딩으로 바꿀 네 개의 텍스트 문자열을 정의했어요.

여기서 passagequery라는 접두사를 써서 생성할 임베딩의 종류를 구분한 점에 주목하세요. 이건 BAAI/bge 모델 계열의 cross-encoder 구현에서 물려받은 방식이에요. 검색(retrieval)에서 특히 유용하니 강력히 권장합니다.

이런 query, passage 접두사는 단순한 문법적 장식이 아니에요. 임베딩 생성 시 텍스트를 어떻게 다뤄야 하는지 알고리즘에 알려 주는 역할을 해요. query 접두사는 보통 유사도 비교에 최적화된 임베딩을 만들도록 모델을 유도하고, passage 임베딩은 맥락 이해를 위해 파인튜닝된 표현을 만들어요. 접두사를 생략하면 기본 동작이 적용되지만, 좀 더 세밀한 결과를 원한다면 명시해 주는 걸 권합니다.

다음으로 기본 모델을 사용해 Embedding 모델을 초기화합니다: BAAI/bge-small-en-v1.5.

embedding_model = TextEmbedding()

기본 모델을 포함한 몇몇 모델의 컨텍스트 윈도우는 최대 512 토큰이에요. 이 제한은 임베딩 모델의 훈련과 설계 자체에서 비롯됩니다. 그보다 긴 시퀀스를 임베딩하고 싶다면 시퀀스에서 단일 벡터를 얻기 위한 풀링 전략을 쓰는 걸 권해요. 예를 들어 문서의 여러 청크에 대한 임베딩의 평균을 사용하면 돼요. SBERT 논문이 추천하는 방식이기도 하죠.

이 모델은 속도와 정확도의 균형을 잘 잡아서, 실제 애플리케이션에 안성맞춤이에요.

embeddings: List[np.ndarray] = list(embedding_model.embed(documents))

마지막으로 embedding_model 객체의 embed() 메서드를 documents 목록과 함께 호출해요. 이 메서드는 파이썬 제네레이터를 반환하므로, 모든 임베딩을 얻으려면 리스트로 변환해 줍니다. 이 임베딩들은 빠른 수학 연산에 최적화된 NumPy 배열이에요.

embed() 메서드는 원래 documents 목록의 각 문서에 대응하는 NumPy 배열의 리스트를 반환해요. 배열의 차원은 고른 모델에 따라 달라지는데, 예를 들어 “BAAI/bge-small-en-v1.5”는 384차원 벡터를 만들어 냅니다.

이 NumPy 배열들은 클러스터링, 유사도 비교, 혹은 머신러닝 모델에 넣어 추가 분석하는 등 어떤 다운스트림 애플리케이션에든 쉽게 파싱해서 쓸 수 있어요.

FastEmbed가 유용한 이유

FastEmbed는 (너무 많은) 성능을 희생하지 않으면서 추론 속도를 목표로 만들어졌어요.

  • 가벼움(Light): PyTorch 같은 다른 추론 프레임워크와 달리 FastEmbed는 외부 의존성이 아주 적어요. ONNX Runtime을 쓰기 때문에 AWS Lambda 같은 서버리스 환경에 딱 맞죠.
  • 빠름(Fast): ONNX를 사용함으로써 FastEmbed는 다양한 하드웨어 플랫폼에서 고성능 추론을 보장해요.
  • 정확함(Accurate): FastEmbed는 OpenAI의 Ada-002 같은 모델보다 더 나은 정확도와 리콜을 목표로 해요. 항상 MTEB 리더보드에서 좋은 결과를 보여 준 모델만 사용하죠.
  • 지원(Support): FastEmbed는 밀집(dense), 희소(sparse), 멀티벡터 모델을 포함해 다국어 모델까지 폭넓게 지원해서 다양한 사용 사례를 충족시켜요.

기본 TextEmbedding 모델로 BAAI/bge-small-en-v1.5를 사용합니다.

FastEmbed 내부 들여다보기

양자화된 모델(Quantized Models): CPU(그리고 Mac Metal)용으로 모델을 양자화해서, 더 적은 연산 리소스로 최고의 성능을 얻을 수 있게 해요. 기본 모델은 정말 작아서 원한다면 AWS Lambda에서도 돌릴 수 있어요!

모델 양자화를 쉽게 만들어 준 Huggingface의 Optimum에게 감사의 인사를 전합니다.

가벼운 의존성(Light on Dependencies):

FastEmbed는 최소한의 RAM/디스크 사용량을 유지해 차별화되어 있어요. PyTorch 같은 다른 추론 프레임워크와 달리 외부 의존성이 거의 필요 없고, CPU에서 돌릴 때 CUDA 드라이버도 요구하지 않습니다.

이건 의도된 설계예요. FastEmbed는 CPU 위에서 바로 최적의 성능을 제공하도록 만들어졌고, 특수 하드웨어나 복잡한 설정 없이도 프로덕션에서 쓸 만큼 민첩하고 빠르게 유지되죠.

ONNXRuntime과 GPU 지원: ONNXRuntime 덕분에 여러 프로바이더를 지원할 수 있어요. FastEmbed의 기본 양자화는 CPU를 대상으로 하지만 GPU 가속도 가능합니다. fastembed-gpu를 설치하고 cuda=True로 설정하면(여러 GPU에 작업을 분산하려면 device_ids도 함께) CPU 대신 GPU에서 추론을 돌릴 수 있어요. FastEmbed는 parallel 파라미터로 여러 CPU 워커에 추론을 병렬화하고, lazy_load로 모델을 지연 로드하는 것도 지원해서 대규모 인덱싱 파이프라인의 처리량을 최적화해 줍니다.

현재 지원 모델

FastEmbed는 이제 밀집 텍스트 임베딩을 훌씬 넘어섰어요. 오늘날 지원하는 것들은:

  • 밀집 임베딩(Dense embeddings) – 이 글 전체에서 사용한 기본 TextEmbedding 모델 (예: BAAI/bge-small-en-v1.5, multilingual-e5, nomic-embed-text-v2-moe)
  • 희소 임베딩(Sparse embeddings) – 정확한 키워드식 검색을 위한 BM25, SPLADE, miniCOIL을 포함한 SparseTextEmbedding 모델
  • 멀티벡터 임베딩(Multi-vector embeddings) – 재스코어링과 소규모 검색에 이상적인 ColBERT를 포함한 LateInteractionTextEmbedding 모델
  • 이미지 임베딩(Image embeddings) – 시각·멀티모달 검색을 위한 CLIP 변형을 포함한 ImageEmbedding 모델
  • 리랭커(Rerankers) – top-K 결과를 재정렬하는 cross-encoder인 TextCrossEncoder (예: ms-marco-MiniLM)
  • 후처리(Postprocessing) – 빠른 1단계 검색을 위해 멀티벡터 임베딩을 하나의 고정 크기 벡터로 압축하는 MUVERA

우리가 지원하는 대부분의 모델은 더 빠른 연산을 위해 양자화되어 있어요!

FastEmbed를 쓰면서 아이디어가 있거나 필요한 기능이 있다면 언제든 알려 주세요. GitHub 페이지에 이슈를 등록해 주시면 됩니다. 우리가 다음에 뭘 만들지 결정할 때 가장 먼저 보는 곳이거든요: FastEmbed GitHub Issues.

FastEmbed의 기본 TextEmbedding 모델에 관해서는 최고의 오픈소스 모델을 지원하는 데 힘쓰고 있어요. 뭔가 바뀌면 새 버전 번호가 올라가니까, 뜻밖의 변화를 피하려면 쓰고 있는 FastEmbed 버전을 고정해 두는 게 좋아요.

FastEmbed를 Qdrant와 함께 쓰기

Qdrant는 벡터 스토어로, 현대 머신러닝과 AI 애플리케이션을 위한 포괄적이고 효율적이며 확장 가능한 엔터프라이즈 솔루션을 제공해요. 수십억 개의 데이터 포인트를 다루든, 저지연 고성능 벡터 데이터베이스 솔루션이 필요하든, 특수한 양자화 기법을 원하든 – Qdrant는 이 모든 요구를 정면으로 해결하도록 설계되었어요.

FastEmbed와 Qdrant의 벡터 스토어 기능을 결합하면 임베딩 생성, 저장, 검색이 매끄럽게 이어지는 투명한 워크플로우가 만들어져요. API 설계가 단순해지면서도, 기본 TextEmbedding 모델 대신 FastEmbed로 직접 만든 임베딩을 Qdrant에 사용하는 것 같은 큰 변경까지도 유연하게 할 수 있죠.

아래는 FastEmbed를 Qdrant와 함께 시작하는 자세한 가이드입니다.

1단계: 설치

코드를 시작하기 전에 먼저 Qdrant 클라이언트와 FastEmbed 라이브러리를 설치해야 해요. pip를 사용하면 됩니다. zsh 같은 셸이 대괄호를 확장하지 않도록 패키지 이름을 따옴표로 감싸 주세요.

pip install "qdrant-client[fastembed]>=1.14.2"

2단계: Qdrant 클라이언트 초기화

설치가 끝나면 Qdrant 클라이언트를 초기화합니다. 인메모리로 하거나 데이터베이스 경로를 지정해서 할 수 있어요.

from qdrant_client import QdrantClient, models
# Initialize the client
client = QdrantClient(":memory:")  # or QdrantClient(path="path/to/db")

3단계: 문서, 메타데이터, ID 준비

클라이언트가 초기화되면 임베딩할 텍스트 문서와 관련 메타데이터, 고유 ID를 준비합니다.

docs = [
    "Qdrant has Langchain integrations",
    "Qdrant also has Llama Index integrations"
]
metadata = [
    {"source": "Langchain-docs"},
    {"source": "LlamaIndex-docs"},
]
ids = [42, 2]

4단계: 컬렉션 생성

Qdrant는 무엇이든 추가하기 전에 저장할 벡터의 크기와 거리 메트릭을 알아야 해요. FastEmbed가 특정 모델의 벡터 크기를 알아내 주므로, 하드코딩하는 대신 클라이언트에 직접 물어볼 수 있습니다.

model_name = "BAAI/bge-small-en-v1.5"

client.create_collection(
    collection_name="demo_collection",
    vectors_config=models.VectorParams(
        size=client.get_embedding_size(model_name),
        distance=models.Distance.COSINE,
    ),
)

5단계: 컬렉션에 문서 추가

컬렉션이 생겼으니, 각 문서를 models.Document로 감싸 어떤 모델로 임베딩할지 클라이언트에 알려 주고, 벡터·payload·id를 함께 업로드합니다.

metadata_with_docs = [
    {"document": doc, **meta} for doc, meta in zip(docs, metadata)
]

client.upload_collection(
    collection_name="demo_collection",
    vectors=[models.Document(text=doc, model=model_name) for doc in docs],
    payload=metadata_with_docs,
    ids=ids,
)

이 호출 안에서 Qdrant 클라이언트는 FastEmbed로 텍스트 임베딩을 생성해 payload와 함께 컬렉션에 업로드해요. 지정한 모델 BAAI/bge-small-en-v1.5를 사용하죠.

INDEX TIME: Sequence Diagram for Qdrant and FastEmbed

6단계: 쿼리 실행

마지막으로 저장된 문서를 대상으로 쿼리를 실행합니다. 쿼리 텍스트도 같은 방식으로 models.Document로 감싸고 query_points로 검색하면 돼요.

search_result = client.query_points(
    collection_name="demo_collection",
    query=models.Document(text="This is a query document", model=model_name),
).points
print(search_result)

내부적으로는 쿼리 문서를 먼저 임베딩으로 변환한 뒤 그 임베딩으로 벡터 인덱스를 검색합니다.

QUERY TIME: Sequence Diagram for Qdrant and FastEmbed integration

이 단계들을 따라가면 FastEmbed와 Qdrant의 결합된 능력을 온전히 활용해 임베딩 생성과 검색 작업을 정리할 수 있어요.

Qdrant는 수십억 개의 데이터 포인트를 다루는 대규모 데이터셋을 위해 설계되었어요. 바이너리 양자화스칼라 양자화 같은 기법을 효율적인 저장·검색에 활용하죠. 여기에 FastEmbed의 CPU 우선 설계와 가벼움을 더하면, 저지연을 유지하면서 매끄럽게 확장되는 시스템이 완성됩니다.

요약

FastEmbed와 Qdrant가 검색 작업을 얼마나 수월하게 만들어 주는지 궁금하다면 직접 시험해 보는 게 가장 좋아요. 시작하는 쉬운 방법 두 가지를 소개할게요.

  1. 클라우드(Cloud): Qdrant Cloud에서 무료 플랜으로 시작해 보세요.
  2. 도커 컨테이너(Docker Container): 직접 해 보는 걸 좋아한다면 자기 머신에서 전부 구성할 수 있어요. Docker로 빠르게 시작하기 가이드를 확인해 보세요.

한번 시험 운전해 보세요. 여러분의 의견이 정말 궁금합니다!

마지막으로, FastEmbed가 유용하다고 느껴진다면 GitHub 저장소에 스타를 달아 주시면 큰 힘이 돼요: 저장소에 스타 달기.

FastEmbed에 관한 질문이 있다면 Qdrant Discord에서 언제든 물어봐 주세요.

더 알아보기 (Learn more)