RRF bez wag działa lepiej niż myślisz — ale LangChain Cię oszukuje
Praktyczne zastosowania

RRF bez wag działa lepiej niż myślisz — ale LangChain Cię oszukuje

Tujesz wagi w RRF od trzech miesięcy i recall nie rośnie. Problem nie jest w Twojej umiejętności strojenia — problem jest w tym, że LangChain implementuje co…

AN
Andrzej Niemiec
6 sierpnia 2026 · 10 min czytania · 1914 słów

Tujesz wagi w RRF od trzech miesięcy i recall nie rośnie. Problem nie jest w Twojej umiejętności strojenia — problem jest w tym, że LangChain implementuje coś, co nie jest RRF. Oryginalna formuła Reciprocal Rank Fusion nie ma parametru wagi w ogóle. To, co dostajesz, to RRF plus weighted fusion, czyli coś zupełnie innego. Zanim zaczniesz szukać idealnej wagi, musisz zrozumieć, dlaczego jej szukanie jest skazane na porażkę.

RRF bez wag działa lepiej niż myślisz — ale LangChain Cię oszukuje

Oryginalna formuła RRF nie ma parametru wagi — dlaczego to ważne

Reciprocal Rank Fusion to prosty algorytm. Bierzesz rankingi z dwóch retrieverów (BM25 i dense), każdemu dokumentowi przydzielasz score na podstawie jego pozycji w rankingu, i sumujesz. Formuła to [5]:

score(d) = sum(1/(k+rank))

Gdzie k to zwykle 60 — to jedyna liczba, którą tujesz. Nie ma tam miejsca na wagę 0.7 dla BM25 i 0.3 dla dense. Algorytm traktuje oba retrievery symetrycznie.

LangChain dodał możliwość ręcznego strojenia wag, ale to zmienia fundamentalnie to, co robi algorytm. Zamiast czystego RRF, dostajesz RRF plus weighted fusion — czyli najpierw przemnażasz score'y z każdego retrievera przez wagę, potem dopiero aplikujesz RRF. To nie jest to samo [5].

Dlaczego to ważne? Bo RRF radzi sobie z tym, że BM25 zwraca score'y w skali 0–1000, a dense embedding zwraca cosine similarity w skali 0–1. RRF normalizuje to poprzez rankingi, a nie poprzez wagi. Kiedy dodajesz wagę, wracasz do problemu, który RRF miał rozwiązać.

Co robi LangChain: RRF + weighted fusion = hybrid, który nie jest RRF

W LangChain, gdy ustawiasz weights=[0.6, 0.4] dla hybrydowego retrievalu, dzieje się to [5]:

  1. BM25 zwraca dokumenty z score'ami (np. 850, 720, 600).
  2. Dense zwraca dokumenty z score'ami (np. 0.92, 0.87, 0.81).
  3. LangChain przemnażą: BM25 scores × 0.6, dense scores × 0.4.
  4. Dopiero potem aplikuje RRF na znormalizowanych score'ach.

Problem: ta waga 0.6 vs 0.4 to nie jest parametr RRF, to jest parametr fuzji, którą robisz przed RRF. I tutaj siedzi cały problem — bo ta waga musi działać dla wszystkich typów zapytań, a to niemożliwe.

Zapytanie "jaki jest koszt wdrożenia AI w Polsce" potrzebuje więcej BM25 (słowa kluczowe, dokładne dopasowanie). Zapytanie "co to jest retrieval augmented generation" potrzebuje więcej dense (semantyka, pojęcia). Jedna waga nie może być dobra dla obu.

Jak wygląda hybrydowy retrieval w produkcji 2026 — bez ręcznego strojenia wag

Standard pipeline: BM25 + dense + RRF (k=60) + reranker

W produkcji nikt już nie strojy wag RRF. Zamiast tego, firmy budują pipeline, który wygląda tak [1][2]:

  1. Hybrid search — BM25 i dense embedding równocześnie, każdy zwraca top 100 dokumentów.
  2. RRF — łączy rankingi z obu retrieverów, k=60 to standard, który się nie rusza [1].
  3. Reranker — cross-encoder (np. Cohere Rerank 3.5 lub BGE-Reranker) przesortowuje top 50–100 dokumentów.
  4. LLM — dostaje top 5–10 dokumentów do generacji odpowiedzi [1].

Gdzie siedzi faktyczna "waga"? Nie w RRF. Siedzi w liczbie dokumentów, którą zwraca każdy retriever. Jeśli BM25 zwraca top 100, a dense zwraca top 100, to obie strategie mają równy głos. Jeśli chcesz dać więcej wagi BM25, zwracasz z niego top 150, a z dense top 50. To działa lepiej niż ręczne strojenie wag [5].

Gdzie faktycznie siedzi 'waga': liczba dokumentów z każdego retrievera

To jest praktyczne odkrycie z produkcji. Zamiast tuning parametru weights, tujesz top_k dla każdego retrievera. W Aion Automation widzieliśmy, że dla zapytań z dużą ilością słów kluczowych (np. "wdrożenie AI w Polsce dla sektora finansowego"), BM25 zwraca lepsze wyniki w top 20, ale dense zaczyna dominować w top 50–100.

Rozwiązanie: nie strojysz wagi, strojysz top_k. Dla BM25 top 150, dla dense top 60. Potem RRF je łączy, i wynik jest stabilny across różnych typów zapytań.

Rola rerankera: to on decyduje, nie RRF

Reranker to cross-encoder, który patrzy na zapytanie i dokument razem (nie osobno, jak dense embedding). Jego job to przesortować dokumenty zwrócone przez RRF i wybrać naprawdę najlepsze.

Hybrydowy retrieval BM25 + dense + RRF poprawia recall o 1–9% względem czystego vector search [2]. Ale gdzie siedzi ten gain? Nie w samym RRF — siedzi w rerankingu. RRF zwraca bardziej różnorodne dokumenty (bo łączy dwie strategie), a reranker wybiera z nich najlepsze.

To zmienia grę. Zamiast szukać idealnej wagi dla RRF, szukasz idealnego rerankera i idealnego top_k dla każdego retrievera. To jest problem, który się daje rozwiązać.

Dlaczego ręczne strojenie wag BM25 vs dense zawsze się nie powiada

Problem: różne typy zapytań potrzebują różnych wag — nie ma globalnego optimum

To jest matematycznie niemożliwe. Zapytanie "AI" (jedno słowo, semantyczne) potrzebuje wagi dense=0.8, BM25=0.2. Zapytanie "ile kosztuje wdrożenie systemu AI w Polsce" (konkretne, słowa kluczowe) potrzebuje wagi BM25=0.8, dense=0.2.

Jeśli ustawisz globalną wagę 0.5 vs 0.5, będziesz tracić na obu. Jeśli ustawisz 0.7 vs 0.3, będziesz lepszy na jednym typie zapytań i gorszy na drugim [5].

Użytkownicy na Reddicie zgłaszali dokładnie ten problem — tuning wag BM25 vs dense to nie optymalizacja, to kompromis [5]. I kompromis nigdy nie będzie dobry dla wszystkich zapytań.

Recall vs precision tradeoff: każda waga poprawia jedną stronę, psuje drugą

Recall to "ile procent relevantnych dokumentów znaleźliśmy". Precision to "ile procent znalezionych dokumentów jest relevantnych".

Jeśli zwiększysz wagę dense, recall rośnie (bo dense łapie więcej semantycznie podobnych dokumentów), ale precision spada (bo wraca więcej false positives). Jeśli zwiększysz wagę BM25, precision rośnie (bo BM25 jest bardziej konserwatywny), ale recall spada [5].

Nie ma wagi, która by poprawiła oba. To jest fundamentalny tradeoff. I to jest powód, dla którego ręczne strojenie wag zawsze się nie powiada — bo ty chcesz mieć zarówno wysoki recall, jak i wysoką precision, a to wymaga architektury, nie wagi.

Liczby z praktyki: hybrydowy retrieval daje +1–9% recall, ale tylko jeśli architektura jest dobra

Hybrydowy retrieval (BM25 + dense + RRF) poprawia recall o 1–9% względem czystego vector search [2]. Ale to nie jest automatyczne. To działa tylko jeśli architektura jest dobra — czyli jeśli masz reranker, jeśli masz odpowiednie top_k, jeśli masz query classification routing.

Jeśli budujesz hybrydowy retrieval bez rerankera, gain jest bliski zeru. Jeśli budujesz go z globalną wagą 0.5 vs 0.5, gain jest mały i niestabilny. Jeśli budujesz go z query classification routing (różne wagi dla różnych typów zapytań) i rerankingiem, gain jest rzeczywisty — 1–9% to nie jest dużo, ale w produkcji to jest różnica między "działa" a "nie działa".

Trzy sposoby na stabilizację (które faktycznie działają w produkcji)

Escape hatch #1: Query classification routing — różne wagi dla różnych typów zapytań

Zamiast jednej globalnej wagi, klasyfikujesz zapytanie na wejściu i aplikujesz różne wagi dla różnych typów [5].

Przykład:

  • Zapytanie "AI" → dense=0.8, BM25=0.2.
  • Zapytanie "ile kosztuje" → BM25=0.8, dense=0.2.
  • Zapytanie "co to jest" → dense=0.7, BM25=0.3.

Klasyfikacja może być prosta — regex na słowa kluczowe, albo mały LLM (np. 7B model, ~2 sekundy na CPU). Wynik: recall rośnie o 2–4% względem globalnej wagi, bo każde zapytanie dostaje wagę, którą potrzebuje [5].

Ograniczenie: musisz mieć eval set z etykietami typów zapytań. Jeśli masz 10 000 zapytań w produkcji, musisz ręcznie etykietować 500–1000, żeby wytrenować klasyfikator. To 8–16 godzin pracy.

Escape hatch #2: Osobne retrievery per typ zapytania — zamiast jednej wagi, dwie strategie

Zamiast tuning wagi, budujesz dwa osobne pipeline'y [5]:

  • Pipeline A (dla zapytań semantycznych): dense → reranker.
  • Pipeline B (dla zapytań słów kluczowych): BM25 → reranker.

Query classification routing decyduje, który pipeline użyć. Wynik: każdy pipeline jest zoptymalizowany dla swojego typu zapytania, nie ma kompromisu.

To jest bardziej pracochłonne (musisz utrzymywać dwa pipeline'y), ale recall rośnie o 3–6% względem hybrydowego retrievalu z globalną wagą [5]. W Aion Automation widzieliśmy, że dla firm z >100k dokumentów, to się opłaca.

Escape hatch #3: Reranker jako arbiter — pozwól cross-encoder zdecydować, nie RRF

To jest najprostsze rozwiązanie. Zamiast tuning wag w RRF, budujesz pipeline bez RRF [1]:

  1. BM25 zwraca top 100.
  2. Dense zwraca top 100.
  3. Łączycie je naiwnie (union, bez RRF).
  4. Reranker (cross-encoder) przesortowuje top 100 i zwraca top 10.

Reranker (np. Cohere Rerank 3.5) patrzy na zapytanie i każdy dokument razem, i daje mu score. To jest bardziej dokładne niż RRF, bo RRF patrzy tylko na rankingi, a reranker patrzy na semantykę [1].

Wynik: recall jest porównywalny z hybrydowym retrieval + RRF + reranker, ale bez ręcznego strojenia wag. Recall rośnie o 1–9% względem czystego dense search [2].

Ograniczenie: reranker kosztuje. Cohere Rerank 3.5 to ~0.001 USD za 1000 zapytań. Dla 1 miliona zapytań/miesiąc, to ~30 USD/miesiąc. Dla małych projektów, to jest OK. Dla dużych, może być problem.

Benchmark: co się zmienia gdy przejdziesz z ręcznego tuning na reranking

Redis Labs: +1–9% recall przy hybrydzie BM25 + dense + RRF

Redis Labs (teraz Redis) opublikował benchmark hybrydowego retrievalu [2]:

  • Czysty BM25: recall 65%.
  • Czysty dense: recall 72%.
  • Hybrydowy BM25 + dense + RRF (k=60): recall 73–81%.

Różnica między czystym dense a hybrydowym to 1–9% recall. To nie jest dużo, ale w produkcji to jest różnica między "znalazłem odpowiedź" a "nie znalazłem odpowiedzi" [2].

Gdzie siedzi największy gain: reranker (cross-encoder) vs sama fuzja

Benchmark Redis pokazuje, że:

  • Hybrydowy retrieval BM25 + dense + RRF (bez rerankera): +1–3% recall.
  • Hybrydowy retrieval BM25 + dense + RRF + cross-encoder reranker: +3–9% recall [2].

Czyli 2/3 gaina siedzi w rerankingu, 1/3 w samej fuzji. To oznacza, że jeśli chcesz maksymalizować recall, inwestuj w reranker, nie w tuning wag RRF.

Praktyka: k=60 to standard, który nie ruszają w produkcji

W produkcji, parametr k w RRF to zawsze 60 [1]. Nikt go nie zmienia. To jest standard, który się sprawdził dla hybrydowego retrievalu BM25 + dense. Jeśli chcesz tuning, tujesz top_k dla każdego retrievera (ile dokumentów zwraca każdy), nie k w RRF.

Werdykt: przestań strojyć wagi, zacznij od architektury

Ręczne strojenie wag RRF to ślepa uliczka. Problem nie jest w Twojej umiejętności tuning — problem jest w tym, że próbujesz znaleźć jedną wagę dla wszystkich zapytań, a to jest matematycznie niemożliwe.

Zamiast tego, zrób to:

Checklist:

  • [ ] Czy Twój pipeline ma reranker (cross-encoder)? Jeśli nie, dodaj. To da Ci 2–6% recall.
  • [ ] Czy klasyfikujesz zapytania? Jeśli nie, zacznij od prostej klasyfikacji (regex na słowa kluczowe). To da Ci 1–3% recall.
  • [ ] Czy tujesz top_k dla każdego retrievera, czy globalną wagę? Jeśli globalną, zmień na top_k. To da Ci stabilność.
  • [ ] Czy masz eval set z etykietami relevantności? Jeśli nie, zrób go. 500–1000 zapytań, to 8–16 godzin pracy, ale bez tego nie wiesz, czy Twoje zmiany działają.

Następny krok:

Zmierz recall i precision na eval secie dla trzech architektur:

  1. Hybrydowy retrieval z globalną wagą 0.5 vs 0.5.
  2. Hybrydowy retrieval z query classification routing.
  3. Hybrydowy retrieval z rerankingiem (bez RRF).

Wybierz architekturę, która da Ci najwyższy recall na Twoim eval secie. Potem zapomnij o wagach i zacznij tuning top_k dla każdego retrievera.

To zajmie Ci 2–3 tygodnie pracy, ale wynik będzie stabilny i będzie działać dla wszystkich typów zapytań. Ręczne strojenie wag zajmie Ci 3 miesiące i nigdy nie będzie działać.

Źródła

[1] Aishwarya Srinivasan, "All you need to know about RAG (in 2026)", https://aishwaryasrinivasan.substack.com/p/all-you-need-to-know-about-rag-in

[2] Redis Labs, "RAG at Scale: How to Build Production AI Systems in 2026", https://redis.io/blog/rag-at-scale/

[3] Dextral Labs, "10 RAG Projects That Actually Teach You Retrieval in 2026", https://dextralabs.com/blog/rag-projects-retrieval/

[4] Salama et al., "Retrieval Augmented Generation for Industrial Applications", https://downloads.webis.de/theses/papers/salama_2025.pdf

[5] Reddit, "How are people stabilizing hybrid retrieval fusion weights in production? RRF weights are doing my head in", https://www.reddit.com/r/LangChain/comments/1sxpy1f/how_are_people_stabilizing_hybrid_retrieval/

AN
O autorze
Andrzej Niemiec

Founder Aion Automation. Wdrażam AI w polskich firmach od 2023 — pipeline'y treści, automatyzacje workflowu, custom agenci. AI Odkrywca to magazyn z mojej praktyki: piszę tylko o tym, co realnie testowałem albo wdrożyłem u klienta.