▸ // spis treści
PolDense 1B zdobył 64,11 punktu w benchmarku PIRB i wyprzedził BGE-Multilingual-Gemma2-9B (63,26) oraz Llama-Embed-Nemotron-8B (63,73). Model dziewięć razy mniejszy wygrywa, bo został zrobiony pod polski.
To pierwszy wniosek. Drugi jest mniej wygodny: model nie jest miejscem, w którym twój RAG traci trafność. Traci ją przy cięciu dokumentów, czyli w kroku, który większość ludzi robi domyślnymi ustawieniami i nigdy do niego nie wraca.
Z tego artykułu dowiesz się:
- który polski model embeddingowy wybrać do własnych dokumentów i dlaczego wielojęzyczny przegrywa,
- ile realnie kosztuje zły sposób cięcia tekstu, w punktach trafności z benchmarków,
- kiedy pary pytanie-odpowiedź biją zwykłe chunki, a kiedy są przerostem formy,
- jak wygląda ta sama architektura w n8n z Qdrantem i w Bieliku na Google Cloud,
- w jakich sytuacjach RAG jest złym narzędziem i lepiej odpuścić.
Dlaczego do polskich dokumentów bierzesz polski model
Jestem trenerem Eskadry Bielika i prowadziłem Misję 2, czyli szkolenie o budowaniu RAG-a na polskim modelu. Certyfikaty i resztę ścieżki znajdziesz w zakładce o mnie, a o samym Bieliku pisałem przy okazji humanizacji treści.
Kiedy czytasz, że model embeddingowy „radzi sobie z wieloma językami", to zwykle prawda i zwykle za mało. Wielojęzyczny model dzieli pojemność między sto kilkadziesiąt języków. Polski dostaje ułamek.
Dlatego polski ma własny benchmark: PIRB, czyli Polish Information Retrieval Benchmark. 41 zadań wyszukiwania informacji po polsku, w tym 10 zbiorów wcześniej niepublikowanych, z medycyny, prawa, biznesu, fizyki i lingwistyki.
I dlatego istnieje PolDense.
Co to jest PolDense
Rodzina modeli embeddingowych z AI Lab w Ośrodku Przetwarzania Informacji, zbudowana na architekturze ModernBERT. Sześć wariantów: 17M, 32M, 68M, 150M, 400M i 1B parametrów.
Trening szedł w trzech etapach: dwie destylacje wiedzy i fine-tuning retrievalowy. Nauczycielem było BGE-Multilingual-Gemma2, a ostatni etap korzystał z ocen trafności z BGE-Reranker-v2.5-Gemma2-Lightweight.
Więc co z tego wynika praktycznie: dostałeś do ręki wiedzę z modelu dziewięciomiliardowego zapakowaną w plik, który mieści się na tanim VPS-ie bez karty graficznej.
| Wariant | Poziom, na jakim gra | Kiedy go bierzesz |
|---|---|---|
| PolDense-1B | 64,11 pkt w PIRB, rekord dla polskiego | masz GPU i zależy ci na maksymalnej trafności |
| PolDense-400M | poziom BGE-Multilingual-Gemma2 i Llama-Embed-Nemotron-8B | domyślny wybór do produkcji |
| PolDense-150M | poziom Qwen3-Embedding-8B | średnie zbiory, ograniczony budżet serwera |
| PolDense-68M | poziom BGE-M3 i Snowflake-Arctic-Embed-2.0 | CPU, VPS bez GPU, wdrożenie u klienta |
| PolDense-32M i 17M | klasa mobile i edge | telefon, urządzenie brzegowe, ekstremalny limit pamięci |
Dla porównania punktu wyjścia: MMLW od sdadas, do niedawna standard dla polskiego, ma 56,38 NDCG@10 w wersji retrieval-roberta-base. Nadal działa i nadal jest na Apache 2.0, co bywa argumentem, bo PolDense wychodzi na licencji gemma.
Sprawdź licencję zanim wdrożysz to u klienta. Komercyjnie wolno, ale gemma nakłada ograniczenia użycia, których Apache nie ma.
Pułapka, w którą wpadają prawie wszyscy
Zarówno PolDense, jak i MMLW wymagają prefiksu przed tekstem zapytania. PolDense chce „[query]: " przy wyszukiwaniu i „[sts]: " przy liczeniu podobieństwa. MMLW chce „zapytanie: ".
Bez prefiksu nic się nie wywala. Nie ma błędu, nie ma wyjątku, workflow przechodzi na zielono. Po prostu dostajesz gorsze wyniki i nie masz pojęcia dlaczego.
Konsekwencja jest przewidywalna: porównujesz polski model z OpenAI, wychodzi ci, że polski wypada gorzej, i wracasz do API. A cała różnica siedziała w jednej brakującej linijce przy budowaniu zapytania.
Mechanika RAG w czterech krokach
RAG to nie uczenie modelu. To podsuwanie mu ściągi tuż przed odpowiedzią.
Model nie zmienia się ani o gram. Zmienia się to, co dostaje w prompcie: zamiast samego pytania dostaje pytanie plus trzy fragmenty twoich dokumentów, które akurat pasują.
Cztery kroki:
- zamieniasz pytanie na wektor tym samym modelem, którym zamieniałeś dokumenty,
- szukasz w bazie wektorów najbliższych temu jednemu,
- sklejasz znalezione fragmenty z pytaniem w jeden prompt,
- model generuje odpowiedź, mając kontekst przed oczami.
Na szkoleniu Misja 2 Eskadry Bielika, które prowadziłem, ten pipeline stoi na Google Cloud: Bielik 4.5B v3.0 na Cloud Run z kartą NVIDIA L4 przez Ollamę, EmbeddingGemma na Cloud Run bez GPU, BigQuery Vector Search jako baza i FastAPI z trzema endpointami - jeden na RAG, jeden na gołego LLM-a do porównania, jeden na zasilanie bazy.
I teraz rzecz, która w tym repo rzuca się w oczy dopiero przy drugim czytaniu: nie ma tam żadnej strategii cięcia. Dane wchodzą z pliku CSV, dziewiętnaście reguł hotelowych, każdy wiersz to osobny dokument indeksowany w całości.
To świadome uproszczenie. Do nauki mechaniki idealne, bo nic nie zasłania. Do produkcji bezużyteczne, bo prawdziwe dokumenty nie przychodzą w postaci gotowych, jednozdaniowych faktów.
Cięcie dokumentów, czyli gdzie ginie trafność
Tu są liczby, które warto zapamiętać.
W benchmarku Vecta z lutego 2026, na pięćdziesięciu prawdziwych pracach akademickich, rekursywne cięcie na stałe 512 tokenów dało 69% trafności końcowej. Cięcie semantyczne, czyli to „mądrzejsze", dało 54%.
Ale w ewaluacji Chroma cięcie semantyczne miało 91,9% recall, czyli najwyższy ze wszystkich metod.
Wygląda na sprzeczność, a jest jednym z najciekawszych mechanizmów w całym RAG-u. Cięcie semantyczne robi chunki czyste tematycznie, więc wyszukiwarka trafia w nie bezbłędnie. Tylko że taki chunk jest za wąski - model dostaje właściwy fragment, ale bez otoczenia, którego potrzebuje, żeby zbudować pełną odpowiedź.
Znajduje dobrze. Odpowiada gorzej.
Pięć strategii i kiedy która
| Strategia | Jak działa | Kiedy warto | Gdzie się wywraca |
|---|---|---|---|
| Stała długość | 512 tokenów, zakładka 10-20% albo numeracja i sąsiedzi | domyślny wybór, potwierdzony benchmarkiem | tnie w połowie zdania i w połowie tabeli |
| Po nagłówkach | jeden chunk na sekcję H2 lub H3 | dokumentacja, wiki, regulaminy, instrukcje | sekcja na dwie strony nie zmieści się w kontekście |
| Po akapitach | jeden chunk na akapit, sklejanie krótkich | artykuły, blog, treści redakcyjne | akapit bez tytułu sekcji traci kontekst |
| Pary pytanie-odpowiedź | LLM generuje pytania z akapitu, indeksujesz pytania | FAQ, obsługa klienta, pytania faktograficzne | kosztuje przebieg modelu przez cały korpus |
| Miks | pary QA plus sekcje w jednej kolekcji | duże bazy wiedzy z różnymi typami pytań | trzeba pilnować, żeby nie dublować odpowiedzi |
Zasada praktyczna: zacznij od 512 tokenów, bo to bije większość alternatyw i kosztuje zero pracy. Do warstwy QA przechodź dopiero, gdy zmierzysz, że trafność nie wystarcza.

Metadane, czyli najtańszy zysk w całym pipeline
Dokładanie metadanych do chunków podnosi trafność odpowiedzi z okolic 50-60% do 72-75%. To jest od 15 do 25 punktów, bez zmiany modelu, bazy ani sposobu wyszukiwania.
Metadane to nazwa dokumentu, tytuł sekcji, data, typ treści, dział, klient. Wszystko, co i tak masz w pliku, a wyrzucasz przy cięciu.
Gdzie wszyscy się wykładają: chunk trafia do bazy jako goły tekst. Model dostaje potem zdanie „stawka wynosi 23%" i nie ma pojęcia, czy to z cennika z 2024 roku, czy z aktualnej umowy.
Dorzuć tytuł sekcji na początek każdego chunka. Jedna linijka w pipeline, kilkanaście punktów trafności.
Sąsiednie chunki zamiast zakładki
Metadane otwierają jeszcze jedną możliwość, przez którą cała dyskusja o zakładce robi się bezprzedmiotowa.
Zakładka istnieje po to, żeby zdanie przecięte na granicy chunka nie zginęło. Kosztuje: przy 15% nakładki co siódmy fragment tekstu leży w bazie dwa razy, więc płacisz za to miejscem, czasem liczenia embeddingów i podwójnymi trafieniami w wynikach.
Zamiast tego zapisz w metadanych numer chunka i identyfikator dokumentu. Wtedy po znalezieniu trafienia dociągasz z bazy chunk poprzedni i następny - po numerze, a nie po podobieństwie. To jest jedno zapytanie po kluczu, nie kolejne przeszukiwanie wektorowe.
Efekt: szukasz małym, precyzyjnym fragmentem, a modelowi podajesz trzy razy szerszy kawałek z otoczeniem.
I tu domyka się paradoks z początku sekcji. Cięcie semantyczne miało najwyższy recall i najniższą trafność końcową, bo chunki były czyste, ale za wąskie. Dociąganie sąsiadów zdejmuje to ograniczenie: zostawiasz wysoki recall i oddajesz modelowi kontekst, którego mu brakowało.
Zakładka przestaje być potrzebna. Sąsiedztwo robi to samo, tylko bez duplikowania tekstu w bazie i decyzja o szerokości kontekstu zapada przy zapytaniu, a nie przy zasilaniu. Jednego dnia bierzesz jednego sąsiada z każdej strony, drugiego trzech, bez przeindeksowywania czegokolwiek.
Warunek jest jeden i banalny: numeruj chunki przy zapisie. Kto tego nie zrobi, ten zostaje z zakładką na zawsze.
Pary pytanie-odpowiedź, czyli dlaczego baza ma trzymać pytania
Standardowy RAG ma wbudowaną asymetrię, o której się nie mówi.
Użytkownik wpisuje pytanie: „ile mam czasu na zwrot towaru". W bazie leży odpowiedź: „Konsument może odstąpić od umowy w terminie 14 dni od objęcia rzeczy w posiadanie".
To są wektory z dwóch różnych światów. Jeden brzmi jak pytanie, drugi jak paragraf regulaminu. Odległość między nimi jest większa, niż powinna.
Rozwiązanie jest odwrotne do intuicji: przepuszczasz każdy akapit przez model, każesz mu wygenerować pytania, na które ten akapit odpowiada, i indeksujesz pytania. W wyniku zwracasz oryginalny akapit.
Teraz porównujesz pytanie z pytaniem. Wektory są z tego samego świata.
Prompt do generowania par wygląda tak:
Przeczytaj poniższy fragment dokumentu.
Wypisz od trzech do pięciu pytań, na które ten fragment
odpowiada wprost. Pytania mają być sformułowane tak,
jak zadałby je klient, nie jak napisałby je prawnik.
Nie wymyślaj pytań, na które fragment nie odpowiada.
Nie parafrazuj tego samego pytania kilka razy.
Zwróć samą listę, bez komentarza.
FRAGMENT:
{tresc_akapitu}Ten sam mechanizm od drugiej strony nazywa się HyDE. Zamiast szukać oryginalnym pytaniem, każesz modelowi wygenerować hipotetyczną odpowiedź i szukasz chunków podobnych do niej. Działa z tego samego powodu: embedding odpowiedzi jest bliżej właściwych chunków niż embedding pytania.
Wybierz jedno. Robienie obu naraz to podwójny koszt przy pojedynczym zysku.
Kiedy pary QA są przerostem formy: gdy twoja baza to sto stron i pytań jest kilkanaście typów. Wtedy zwykłe cięcie po sekcjach plus metadane załatwia sprawę i nie palisz tokenów na generowanie pytań do całego korpusu.
Hybrid search i reranking, czyli dwa ostatnie procenty
Wyszukiwanie wektorowe ma jedną słabość: gubi dokładne dopasowania. Numer faktury, kod SKU, nazwisko, symbol prawny. Wektor rozumie znaczenie, a te rzeczy nie mają znaczenia, tylko postać.
Qdrant rozwiązuje to trzymając w jednej kolekcji dwa rodzaje wektorów:
- gęste, z modelu takiego jak PolDense, odpowiadają za semantykę,
- rzadkie, z BM25 albo SPLADE, odpowiadają za dosłowne trafienia w słowa.
Wyniki z obu ścieżek łączy natywne RRF, czyli fuzja rang. Na wierzch trafia to, co wysoko wypadło w obu rankingach naraz.
Na końcu wchodzi reranker. Modele późnej interakcji, jak ColBERT, reprezentują pytanie i dokument jako wiele wektorów zamiast jednego i porównują je na poziomie pojedynczych słów. Jest to za wolne, żeby przeszukać całą bazę, ale idealne do przesortowania dwudziestu wyników, które już masz.
Kolejność ma znaczenie: hybryda daje więcej kandydatów, reranker ustawia ich we właściwej kolejności. Sam reranker bez hybrydy porządkuje tylko to, co i tak znalazłeś.
Jak to spinam w n8n
Na co dzień robię to w n8n z Qdrantem, bo klient dostaje wtedy coś, co widzi i może sam zmienić, a nie plik Pythona, którego nikt poza mną nie otworzy.
Wbudowany node „Qdrant Vector Store" ma opcję rerankingu. Po jej włączeniu podpinasz osobny node rerankera i to wszystko - fuzja siedzi po stronie Qdranta, nie musisz jej pisać.
Dwa workflowy, nie jeden.
Pierwszy zasila bazę i chodzi rzadko. Pobiera dokumenty, parsuje do markdown, tnie, numeruje chunki, dokleja metadane, liczy embeddingi i wrzuca do Qdranta. Odpalasz go po dodaniu nowych plików, nie przy każdym pytaniu.
Drugi obsługuje pytania i chodzi cały czas. Webhook, prefiks do zapytania, wyszukanie hybrydowe, reranking, dociągnięcie sąsiednich chunków po numerze, prompt, odpowiedź.
Do parsowania PDF-ów nie używam modeli wizyjnych, tylko opendataloader-pdf albo anydoc. Oba są deterministyczne - ten sam plik zawsze daje ten sam markdown, bez halucynacji i bez GPU. Przy umowach i cennikach to nie jest luksus, tylko warunek, żeby dało się cokolwiek zweryfikować.
Przy wdrożeniach u klienta najwięcej czasu zjada nie budowa workflow, tylko ustalenie, co właściwie ma trafić do bazy. Trzy foldery na dysku sieciowym, z czego dwa nieaktualne, to normalny punkt wyjścia.
Bielik jako druga połowa układanki
Model embeddingowy odpowiada za znajdowanie. Za odpowiadanie odpowiada LLM i tu też język ma znaczenie.
Bielik jest polski od podstaw, nie przetłumaczony. Odmienia poprawnie, łapie polską składnię i nie produkuje zdań, które brzmią jak kalka z angielskiego. Pisałem o tym szerzej przy okazji humanizacji treści: Bielik do humanizacji treści.
W RAG-u ma dwie role.
Pierwsza jest oczywista: dostaje pytanie plus kontekst i pisze odpowiedź.
Druga jest ciekawsza: generuje pary pytanie-odpowiedź z twoich dokumentów. To zadanie, które przy dużym korpusie kosztuje najwięcej tokenów, a jednocześnie nie wymaga najsilniejszego modelu na rynku. Odpalasz Bielika lokalnie przez Ollamę i przemielasz nim całą bazę bez patrzenia na licznik.
Jest jeszcze argument, który u klientów działa mocniej niż wszystkie benchmarki razem wzięte. Umowy, dane osobowe i cenniki nie wychodzą poza serwer. Cały pipeline - embeddingi, baza, generowanie - da się postawić tak, że żaden fragment dokumentu nie leci do zewnętrznego API.
W Misji 2 pokazywaliśmy to na Google Cloud, więc dane były w chmurze, ale w jednym miejscu, pod kontrolą i bez wysyłania czegokolwiek do OpenAI. Ta sama architektura chodzi na własnym serwerze.
Kiedy RAG nie ma sensu
Trzy sytuacje, w których RAG jest złym narzędziem, a widuję go tam regularnie.
Masz mało danych. Regulamin na dziesięć stron mieści się w kontekście modelu w całości. Wrzuć go do promptu i skończ temat. Budowanie bazy wektorowej pod dwa dokumenty to praca, która wygląda jak praca.
Pytania dotyczą liczb. „Ile sprzedaliśmy w marcu", „który klient ma największe saldo", „pokaż faktury powyżej 10 tysięcy". Wektory nie sumują i nie sortują. Do tego jest SQL, a rolą modelu jest co najwyżej napisanie zapytania.
Pytanie dotyczy całości dokumentu. „Streść tę umowę", „jakie są główne ryzyka w tym raporcie". RAG z definicji zwraca fragmenty, więc dostaniesz streszczenie trzech akapitów podane jako streszczenie całości. To gorsze niż brak odpowiedzi, bo wygląda wiarygodnie.
Czwarta sytuacja, mniej oczywista: kiedy twoje dokumenty są sprzeczne. RAG zwróci fragment, który akurat wypadł wyżej w rankingu, i model odpowie z pełnym przekonaniem. Zanim zbudujesz wyszukiwarkę po bałaganie, uporządkuj bałagan.
Podsumowanie
- do polskich dokumentów bierzesz polski model, bo PolDense-1B z 64,11 punktu w PIRB bije wielojęzyczne modele dziewięć razy większe,
- do produkcji domyślnie 400M, a na VPS bez karty graficznej 68M - obie wersje grają w lidze modeli kilkusetmilionowych,
- prefiks przy zapytaniu jest obowiązkowy i nikt cię o jego braku nie poinformuje,
- cięcie na 512 tokenów bije cięcie semantyczne w trafności końcowej, 69% do 54%,
- metadane na chunkach dokładają od 15 do 25 punktów i są najtańszą rzeczą w całym pipeline,
- ponumeruj chunki, a zamiast zakładki dociągniesz sąsiadów po kluczu - ten sam kontekst bez duplikowania tekstu w bazie,
- pary pytanie-odpowiedź działają, bo porównują pytanie z pytaniem, a nie pytanie z paragrafem regulaminu,
- hybryda plus reranking domykają temat, ale dopiero wtedy, gdy cięcie i metadane są zrobione.
Kolejność ma znaczenie i jest odwrotna do tego, co robi większość. Najpierw sposób cięcia, potem metadane, potem model, na końcu hybryda i reranking.
Wymiana modelu na lepszy przy źle pociętych dokumentach da ci dwa punkty. Naprawienie cięcia da kilkanaście.
P.S. Repo z Misji 2 Eskadry Bielika jest publiczne i na Apache 2.0. Postaw je u siebie, podmień CSV z regułami hotelowymi na własny plik i zobacz, gdzie ten pipeline zaczyna się sypać. Godzina roboty, a nauczysz się z tego więcej niż z tego artykułu.
P.S. 2 Jeśli twoje dokumenty leżą w PDF-ach, zacznij od parsowania, nie od wyboru modelu. Zły markdown na wejściu psuje wszystko, co jest dalej, i żaden reranker tego nie odkręci.
Źródła
- huggingface.co/OPI-PIB/PolDense-400M
- huggingface.co/OPI-PIB/PolDense-68M
- opi.org.pl - PolDense na czele Polish Information Retrieval Benchmark
- arxiv.org/pdf/2402.13350 - PIRB: A Comprehensive Benchmark of Polish Dense and Hybrid Text Retrieval Methods
- arxiv.org/pdf/2405.10138 - PL-MTEB: Polish Massive Text Embedding Benchmark
- huggingface.co/sdadas/mmlw-retrieval-roberta-base
- firecrawl.dev/blog/best-chunking-strategies-rag
- denser.ai/blog/rag-chunking-strategies
- qdrant.tech/documentation/advanced-tutorials/reranking-hybrid-search
- docs.n8n.io - Qdrant Vector Store node
- github.com/avedave/eskadra-bielik-misja2
- github.com/opendataloader-project/opendataloader-pdf
Damian Ślimak. Twój Nawigator w chaosie AI.
