Wyszukiwanie gęste a rzadkie: kompromisy
Poznaj sytuacje, w których gęste embeddingi pomijają dokładne dopasowania słów kluczowych, a BM25 pomija semantyczne parafrazy, oraz dowiedz się, dlaczego połączenie obu metod konsekwentnie przewyższa każdą z nich stosowaną osobno.
Wyszukiwanie gęste a rzadkie: kompromisy to bezpłatna lekcja AI Engineering Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Engineering Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Engineering Academy zawiera 4 lekcji w sumie.
Dwa zasadniczo różne sygnały pobierania
Współczesne systemy pobierania opierają się na dwóch odrębnych sygnałach: pobieranie gęste koduje znaczenie w ciągłych przestrzeniach wektorowych, natomiast pobieranie rzadkie zlicza dokładne wystąpienia terminów. Sygnały te uzupełniają się, ale nie można ich stosować zamiennie. Zrozumienie mocnych i słabych stron każdego z nich to pierwszy krok do zbudowania systemu, który skutecznie wykorzystuje oba.
Jak działają embeddingi gęste
Pobieranie gęste odwzorowuje zarówno zapytanie, jak i każdy dokument na wielowymiarowy wektor za pomocą enkodera neuronowego. Podobieństwo mierzy się za pomocą odległości cosinusowej lub iloczynu skalarnego wektorów. Ponieważ enkoder został wytrenowany na dużych korpusach tekstowych, frazy powiązane semantycznie trafiają blisko siebie w przestrzeni wektorowej, nawet jeśli nie mają wspólnych słów — to kluczowa zaleta pobierania gęstego.
from openai import OpenAI
import numpy as np
client = OpenAI()
def embed(text: str) -> list[float]:
resp = client.embeddings.create(
model='text-embedding-3-small',
input=text,
)
return resp.data[0].embedding
def cosine_similarity(a, b):
a, b = np.array(a), np.array(b)
return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))
q = embed('How do I cancel my subscription?')
d = embed('Steps to unsubscribe from the service')
print(cosine_similarity(q, d)) # high similarity despite different wordsKiedy pobieranie gęste zawodzi
Modele gęste mają trudności z rzadkimi terminami, które były niedostatecznie reprezentowane podczas trenowania enkodera. Zapytanie zawierające konkretny numer modelu produktu, taki jak RTX-4090-Ti-OC, nazwę leku lub zastrzeżony wewnętrzny identyfikator, często nie dopasuje właściwego dokumentu, ponieważ enkoder nie ma wyuczonej reprezentacji dla tej sekwencji tokenów. Wektor trafia po prostu w nieprzydatne miejsce przestrzeni embeddingów.
Jak działa pobieranie BM25 metodą rzadką
BM25 (Best Matching 25) to probabilistyczna funkcja rankingowa, która ocenia dokumenty na podstawie częstości występowania terminów zapytania w dokumencie, normalizując wynik względem długości dokumentu i osłabiając wpływ nasycenia częstości terminów. Tworzy rzadki wektor wyników — większość wymiarów ma wartość zero, ponieważ dokumenty zawierają tylko niewielką część słownika.
# BM25 scoring formula (conceptual)
# score(D, Q) = sum over query terms t of:
# IDF(t) * (tf(t,D) * (k1 + 1)) / (tf(t,D) + k1 * (1 - b + b * |D|/avgdl))
# k1 controls term frequency saturation (typically 1.2-2.0)
# b controls document length normalization (typically 0.75)
# IDF(t) = log((N - df(t) + 0.5) / (df(t) + 0.5))
# N = total documents, df(t) = documents containing term t
# tf(t,D) = frequency of t in document D, |D| = doc length, avgdl = average doc lengthMocne strony BM25: dokładne terminy i żargon
BM25 świetnie sprawdza się w zapytaniach zawierających dokładne terminy techniczne, nazwy produktów, kody błędów i identyfikatory liczbowe, które powinny zostać precyzyjnie dopasowane. Zapytanie o ORA-01017 (kod błędu Oracle) umieści dokumenty zawierające dokładnie ten ciąg znacznie wyżej niż dokumenty, które jedynie ogólnie omawiają uwierzytelnianie w bazie danych. Jest to niemożliwe dla modelu gęstego, który nigdy nie widział tego konkretnego kodu.
from rank_bm25 import BM25Okapi
corpus = [
'Oracle database ORA-01017 invalid username or password logon denied',
'Database authentication and connection troubleshooting guide',
'How to resolve login errors in Oracle and MySQL databases',
]
tokenized_corpus = [doc.lower().split() for doc in corpus]
bm25 = BM25Okapi(tokenized_corpus)
query = 'ORA-01017 error fix'
scores = bm25.get_scores(query.lower().split())
print(dict(zip(range(len(corpus)), scores)))
# doc 0 scores highest because it contains ORA-01017Kiedy BM25 zawodzi: parafrazy i synonimy
BM25 nie rozpoznaje parafraz semantycznych. Dokument o naprawie silnika samochodowego otrzyma wynik zero dla zapytania o konserwację motoru auta, ponieważ żadne dokładne słowa się nie pokrywają. Ten problem niedopasowania słownictwa, nazywany czasem luką leksykalną, oznacza, że wyszukiwanie oparte wyłącznie na słowach kluczowych pomija ogromną ilość istotnych treści, które po prostu używają innych słów do wyrażenia tej samej idei.
from rank_bm25 import BM25Okapi
corpus = [
'automobile engine repair and maintenance tips',
'car motor maintenance guide for beginners',
'vehicle powertrain service intervals',
]
tokenized = [doc.split() for doc in corpus]
bm25 = BM25Okapi(tokenized)
scores = bm25.get_scores(['car', 'motor', 'maintenance'])
print(scores)
# doc 1 scores high, doc 0 and 2 score lower despite being semantically relatedDowody z benchmarków: hybryda konsekwentnie wygrywa
Benchmarki przeprowadzone na zbiorach BEIR, MS MARCO i zbiorach firmowych pytań i odpowiedzi konsekwentnie pokazują, że pobieranie hybrydowe przewyższa samo pobieranie gęste lub rzadkie o 5–15 procent według NDCG@10. Poprawa jest największa w zbiorach zawierających zarówno zapytania faktograficzne (w których pomaga BM25), jak i zapytania będące parafrazami (w których pomagają embeddingi gęste). Żadna pojedyncza metoda pobierania nie dominuje dla wszystkich typów zapytań.
Analiza typu zapytania: który retriever wygrywa
Można przewidzieć, który retriever zadziała lepiej, analizując typ zapytania. Pobieranie gęste wygrywa w przypadku pytań konceptualnych, parafraz i ogólnych zapytań tematycznych. BM25 wygrywa w przypadku zapytań zawierających nazwy własne, numery wersji, fragmenty kodu, akronimy i rzadkie terminy techniczne. Hybryda zawsze wygrywa, gdy typ zapytania nie jest znany z góry — a w środowisku produkcyjnym jest tak niemal zawsze.
# Query type heuristics
def predict_retriever_advantage(query: str) -> str:
tokens = query.split()
has_numbers = any(t[0].isdigit() for t in tokens)
has_uppercase_acronyms = any(t.isupper() and len(t) > 2 for t in tokens)
is_short = len(tokens) <= 4
if has_numbers or has_uppercase_acronyms:
return 'BM25 likely wins (exact terms)'
elif is_short:
return 'Dense likely wins (semantic matching needed)'
else:
return 'Hybrid recommended (mixed signals)'Problem niezgodności wyników
Łączenie wyników gęstych i rzadkich nie jest trywialne, ponieważ ich wyniki są obliczane w niezgodnych skalach. Podobieństwo cosinusowe przyjmuje wartości od -1 do 1, natomiast BM25 generuje nieograniczone dodatnie wyniki zależne od rozmiaru korpusu. Nie można ich po prostu dodać. Standardowym rozwiązaniem jest użycie fuzji opartej na rangach zamiast fuzji opartej na wynikach — łączenie uporządkowanych list zamiast surowych wyników.
Praktyczna decyzja: kiedy używać poszczególnych metod
Retrievalu tylko gęstego należy używać, gdy korpus obejmuje wąską dziedzinę, ma spójne słownictwo, a potrzebne jest uogólnianie znaczeniowe na parafrazy. Tylko BM25 należy stosować, gdy zapytania mają głównie charakter wyszukiwawczy i zawierają dokładne identyfikatory, a zbiór danych jest na tyle mały, że wyszukiwanie metodą brute-force jest wykonalne. Retrieval hybrydowy należy stosować we wszystkich produkcyjnych systemach RAG, w których typy zapytań są zróżnicowane — narzut jest niewielki, a poprawa recallu znacząca.
Kompromisy dotyczące wydajności i infrastruktury
Retrieval gęsty wymaga akcelerowanego przez GPU przybliżonego wyszukiwania najbliższych sąsiadów lub bazy wektorowej, co zwiększa koszty infrastruktury. BM25 działa w całości na CPU, korzystając z indeksu odwróconego, i jest wyjątkowo szybki. Retrieval hybrydowy wymaga obu komponentów infrastruktury oraz etapu fuzji. Dodatkowa złożoność jest uzasadniona poprawą recallu w większości produkcyjnych zastosowań, ale należy ją zestawić z budżetem infrastruktury.
Szybki sprawdzian
Sprawdź swoją wiedzę na temat kompromisów między retrievalem gęstym a rzadkim omówionych w tej lekcji.
Podsumowanie lekcji
W tej lekcji poznali Państwo: retrieval gęsty odwzorowuje znaczenie semantyczne, ale zawodzi w przypadku rzadkich, dokładnych terminów; rzadki retrieval BM25 obsługuje dokładne słowa kluczowe, ale nie radzi sobie z parafrazami; natomiast retrieval hybrydowy konsekwentnie przewyższa każdą z tych metod stosowaną osobno dla różnorodnych typów zapytań. Ich wyniki są niezgodne i należy je łączyć za pomocą fuzji rang, a nie przez dodawanie wyników. W następnej części zaimplementujemy wyszukiwanie słów kluczowych BM25 w języku Python.
Często zadawane pytania
Czy lekcja „Wyszukiwanie gęste a rzadkie: kompromisy” jest bezpłatna?
Tak — pełny tekst „Wyszukiwanie gęste a rzadkie: kompromisy” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Engineering Academy, przejdź na CoddyKit PRO. Kurs AI Engineering Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Wyszukiwanie gęste a rzadkie: kompromisy”?
Poznaj sytuacje, w których gęste embeddingi pomijają dokładne dopasowania słów kluczowych, a BM25 pomija semantyczne parafrazy, oraz dowiedz się, dlaczego połączenie obu metod konsekwentnie przewyższ… Ćwiczysz AI Engineering Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć AI Engineering Academy?
Nie wymagamy żadnego doświadczenia. AI Engineering Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.
Ile czasu zajmuje lekcja „Wyszukiwanie gęste a rzadkie: kompromisy”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji AI Engineering Academy?
Tak. Każda lekcja AI Engineering Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Wyszukiwanie gęste a rzadkie: kompromisy
- Implementacja wyszukiwania słów kluczowych BM25
- Reciprocal Rank Fusion do łączenia wyników
- Wyszukiwanie hybrydowe w Pinecone i pgvector