Qdrant의 관련성 피드백

Qdrant의 관련성 피드백 (Relevance Feedback Retrieval in Qdrant)

⏱️ 소요 시간 30분 | 난이도: 중급 | 산출물: GitHub 출처: Qdrant 공식 문서 — using-relevance-feedback

여러분, Qdrant 1.17에서 새로 나온 Relevance Feedback Query를 소개해요. 이는 검색에 관련성 피드백을 통합하는, 확장 가능하고 최초의 벡터 인덱스 네이티브 방식이에요.

이 튜토리얼에서는 다음을 배울 수 있어요:

  1. Qdrant 컬렉션, retriever(검색기), 피드백 모델에 맞게 Relevance Feedback Query를 커스터마이징하기.
  2. 커스터마이징한 Relevance Feedback Query를 검색 파이프라인에 추가하기.
  3. 그것이 이 파이프라인에 가져다주는 이득을 평가하기.

관련성 피드백 (Relevance Feedback)

관련성 피드백은 현재 검색 결과의 관련성에 관한 신호를 다음 검색 반복으로 증류해서, 시간이 지남에 따라 더 나은 결과를 표면화해요.

Relevance Feedback Query는 검색 결과에 대한 소량의 모델 생성 피드백을 사용해 다음 검색 반복에서 retriever가 전체 벡터 공간을 안내하도록 해요. 검색을 더 관련성 높은 결과 쪽으로 밀어붙이죠. 작동 방식에 대한 자세한 설명은 Qdrant의 관련성 피드백 문서에서 볼 수 있어요.

전략 (Strategy)

피드백을 사용해 벡터 공간에서 retriever를 안내하는 전략은 여러 가지가 있을 수 있어요. 지금은 naive 전략만 사용 가능해요 — 간단한 3-매개변수 공식으로 피드백에 따라 유사도 점수를 조정하는 방식이에요.

이 전략이 잘 동작하려면 이 naive 공식의 매개변수가 여러분의 데이터, retriever, 피드백 모델에 맞게 커스터마이징되어야 해요. 편의를 위해 사용 사례에 맞는 매개변수를 제공하는 qdrant-relevance-feedback Python 패키지를 제공해요.

이 튜토리얼은 그것을 Relevance Feedback Query API와 함께 사용하는 방법을 보여줄게요.

사용 사례에 맞게 커스터마이징하기

설정 (Setup)

앞서 언급한 패키지를 설치해요 (Qdrant Client를 의존성으로 자동 설치해요):

pip install qdrant-relevance-feedback

Qdrant Cloud Free Tier Cluster(버전 1.17.0+인지 확인)와 그 Free Tier Cluster에서 사용 가능한 Free Embedding Inference를 사용할 거예요.

Qdrant Free Tier Cluster를 생성하고 Qdrant Client를 초기화해요:

from qdrant_client import QdrantClient

client = QdrantClient(
    url=<QDRANT_URL>,
    api_key=<QDRANT_API_KEY>,
    cloud_inference=True  # Qdrant Cloud의 무료 임베딩 추론을, 편의와 지연 감소를 위해 사용
)

데이터셋

Qdrant Cluster UI에서 제공하는 데이터셋 중 하나를 사용할 거예요.

  1. Cluster UI -> Datasets로 이동해요.
  2. 거기 있는 3개 데이터셋 중 첫 번째인 "Qdrant Web Documentation"을 골라요. 이는 문서 웹사이트의 작은 텍스트 청크로 구성돼요.
  3. Import 버튼을 누르고 컬렉션 이름 documentation을 입력해요.

몇 초 후에 그린 상태 "Snapshot successfully imported"가 떠오르고, 모든 컬렉션 목록에 documentation이라는 컬렉션이 나타나는 걸 볼 수 있어요.

이제 작업할 컬렉션과 의미론적 검색을 최적화할 컬렉션이 생겼어요.

COLLECTION_NAME = "documentation"

Retriever (검색기)

retriever는 원시 데이터를 의미론적 유사도 검색용 벡터로 변환하는 임베딩 모델이에요. Relevance Feedback Query는 retriever가 데이터에서 관련성 있는 결과를 찾는 능력을 최적화하도록 도와줘요.

우리의 retriever는 이미 컬렉션에 정의되어 있어요. 데이터셋의 "VECTORS CONFIG"에 있는 all-MiniLM-L6-v2 태그가 보여주듯, 컬렉션의 벡터는 all-MiniLM-L6-v2 모델로 만들어졌어요.

이것을 qdrant-relevance-feedback 프레임워크에서 정의해볼게요.

from qdrant_relevance_feedback.retriever import QdrantRetriever

retriever = QdrantRetriever("sentence-transformers/all-minilm-l6-v2")

QdrantRetriever는 모든 Qdrant Cloud Inference 및 FastEmbed 모델을 지원하며, all-MiniLM-L6-v2는 Qdrant Free Tier Cloud Inference로 커버됩니다. 커스텀 retriever도 정의하고 제공할 수 있어요.

이 컬렉션의 point 하나가 어떻게 생겼는지 확인해보세요.

우리 문서 컬렉션에는 point당 벡터가 하나뿐이에요 — Default vector. 하지만 Qdrant에서는 point당 여러 명명된 벡터(named vectors)를 가질 수 있어요.

피드백으로 최적화하려는 retriever와 연관된 벡터 이름을 제공해야 해요.

RETRIEVER_VECTOR_NAME = None  # default vector이거나 Qdrant 컬렉션의 명명된 벡터 핸들

또한 retriever 모델로 벡터화되는 원시 데이터를 프레임워크에 알려줘야 해요. 여기서 원시 데이터는 point의 payload에 있는 text 필드예요. 간단히 말해, 벡터화된 형태의 text 스니펫을 검색하는 거예요.

PAYLOAD_KEY = "text"

원시 데이터가 Qdrant 밖에 저장되어 있다면 qdrant-relevance-feedbackpayload_retrieval 부분을 재정의할 수 있어요.

피드백 모델 (Feedback Model)

피드백 모델은 retriever가 제공한 결과를 보고 그것이 얼마나 관련성 있는지 점수를 매겨요. retriever는 Relevance Feedback Query 인터페이스를 통해 이 피드백을 사용해 벡터 공간에서 더 잘 방향을 잡고 더 관련성 높은 문서를 표면화해요.

이 튜토리얼의 피드백 모델 제공자로는 Qdrant의 경량 추론 라이브러리인 FastEmbed를 사용할 거예요.

pip install fastembed

all-MiniLM-L6-v2는 작은(384차원뿐) 약한 모델이므로, 너무 강하거나 비싼 피드백 모델을 고를 필요가 없어요. 그런 작은 retriever는 정교한 피드백을 잘 받아들이지 못할 거예요.

그래서 간단하게는 더 큰 차원의 bi-encoder, 예를 들어 1024차원의 mxbai-embed-large-v1을 사용할 수 있어요.

from qdrant_relevance_feedback.feedback import FastembedFeedback

feedback = FastembedFeedback("mixedbread-ai/mxbai-embed-large-v1")

이 코드는 로컬 추론을 위해 mxbai-embed-large-v1을 다운로드할 거예요.

우리는 모든 FastEmbed 모델로 FastembedFeedback을 제공해요. 하지만 커스텀 피드백 모델도 정의하고 제공할 수 있어요. bi-encoder, late interaction 모델, cross-encoder, LLM 무엇이든 될 수 있어요.

컬렉션, Retriever, 피드백 모델 연결하기

이제 모든 게 준비됐어요: retriever, 컬렉션, 피드백 모델.

from qdrant_relevance_feedback import RelevanceFeedback

relevance_feedback = RelevanceFeedback(
    retriever=retriever,
    feedback=feedback,
    client=client,
    collection_name=COLLECTION_NAME,
    vector_name=RETRIEVER_VECTOR_NAME,
    payload_key=PAYLOAD_KEY,
)

이 트리플렛을 위해 데이터를 수집하고 Relevance Feedback Query 매개변수(naive 전략)를 조정하는 작은 학습 과정을 실행할 수 있어요.

학습 (Training)

학습 데이터

관련성 피드백 공식이 여러분의 데이터에 얼마나 잘 맞는지는 학습 데이터의 양과 품질(사용 사례에 얼마나 현실적인가)에 달려 있어요.

일반적으로 아주 적은 양(50~300개 질의면 충분해요)만 필요해요. 3개의 매개변수만 학습하면 되니까요.

우리는 Claude Code로 "Qdrant의 웹사이트를 탐색할 때 개발자가 입력할 법한 짧은 검색 질의 50개(각 3~10단어)를 생성해줘"라는 프롬프트로 50개 질의를 생성했어요.

학습 질의 (요약) — 예시 일부:

train_queries = [
    "qdrant filtering nested object payload",
    "vector database for fraud detection",
    "qdrant golang client example",
    "sparse dense fusion ranking qdrant",
    "qdrant write ahead log explained",
    # ... 총 50개 질의
]

학습 데이터 크기를 제어하는 또 다른 매개변수는 질의당 컬렉션에서 가져오는 응답 수예요.

TRAIN_LIMIT = 25

TRAIN_LIMIT이 클수록 공식이 받는 학습 데이터가 많아지지만, 학습이 더 비싸고 느려져요.

학습을 위해 피드백 모델이 ground-truth 관련성 점수를 제공해야 하므로, #queries * TRAIN_LIMIT, 여기서는 50 * 25 = 1250개의 질의-문서 쌍을 재스코링해요. 학습 예산에 따라 조정하세요.

학습 과정

이제 학습을 실행할 수 있어요:

formula_params = relevance_feedback.train(
    queries=train_queries,
    limit=TRAIN_LIMIT,
)

50개 질의에서 "Building training data" 과정이 실행되는 걸 볼 수 있어요. 추가로 프레임워크가 새너티 체크(sanity check)를 제공해요.

평가 (Evaluation)

학습이 끝났으면 테스트 집합에서 평가를 실행해서, 피드백 모델이 질의당 CONTEXT_LIMIT개의 결과를 받아 피드백을 제공할 때 얼마나 이득을 얻는지 확인할 수 있어요.

from qdrant_relevance_feedback.evaluate import Evaluator

N = 10  # metric@N에서처럼
evaluator = Evaluator(relevance_feedback=relevance_feedback)
results = evaluator.evaluate_queries(
    at_n=N,
    formula_params=formula_params,  # 위에서 나온 것
    eval_queries=test_queries,
    eval_context_limit=CONTEXT_LIMIT  # 위에서 나온 것
)

이런 출력을 얻게 되는데, N(여기서는 10)에서의 *상대적 결과 관련성 이득(relative results relevance gain)*과 할인 누적 이득(DCG) 승률을 제공해요.

On the 2nd retrieval iteration, over this test set:
Relevance feedback retrieval surfaced 44 more relevant results (according to the feedback model)
Vanilla retrieval surfaced 39 more relevant results (according to the feedback model)
Relative results relevance gain over this test set is: 12.82051282051282%
DCG win rates (which approach ranks results better):
Vanilla retrieval: 38.0% wins
Relevance feedback retrieval: 48.0% wins
Ties: 14.0%

상대적 결과 관련성 이득: 이 50개 생성 질의 테스트 집합에서, 관련성 피드백 기반 검색은 컬렉션에서 retriever가 "눈치채지" 못한 관련 문서를 5개(44 - 39) 더 끌어왔어요. 일반 검색 대비 13% 향상이에요.

DCG 승률: 질의의 약 절반(48%)에서, 관련성 피드백 기반 검색이 평가 창 N 안에서 retriever보다 더 잘 랭킹해요. 14%의 질의에서는 두 방법이 동일하고, 38%에서는 관련성 피드백이 retriever를 혼란스럽게 해요.

메트릭에 대한 자세한 설명은 문서에 있으며, 시각화도 함께 있어요.

결론 (Conclusion)

이 튜토리얼에서는 관련성 피드백을 텍스트 데이터에 사용해 검색 파이프라인의 결과 관련성을 높이는 방법을 시연했어요. 기억할 점은 다음과 같아요:

  • 여러분의 데이터에 적응 가능 — 텍스트뿐 아니라 다른 모달리티에서도 동작해요. 예를 들어 이미지에도 똑같이 할 수 있어요.
  • 유연한 모델 선택 — Cloud Inference와 FastEmbed에서 지원하는 미리 정의된 retriever와 피드백 모델을 사용하거나, LLM과 커스텀 LTR 모델을 포함해 자신만의 것을 정의할 수 있어요.
  • 내장 평가 — 이 프레임워크로 프로덕션에 넣기 전에 Relevance Feedback Query 사용의 잠재 이득을 평가할 수도 있어요.

Relevance Feedback Query 사용에 대한 조언이 필요하거나 이 방법을 개선할 아이디어가 있다면 Discord 커뮤니티에 연락해주세요.

더 알아보기 (Learn more)