Większość samouczków RAG kończy się dokładnie tam, gdzie zaczyna się produkcja. Dzielisz swoje dokumenty na fragmenty po 512 tokenów, przepuszczasz je przez pojedynczy model osadzeń (embedding model) i wywołujesz bazę danych wektorowych za pomocą prostego pobierania top-k. W wersji demonstracyjnej wygląda to przekonująco. Zapytaj bota o politykę urlopową firmy, a on zwróci spójny akapit. Wszyscy przytakują. Niestety, demonstracje kłamią.

Produkcja obnaża każdy skrót. Stałe fragmenty przecinają umowy prawne w samym środku klauzul odszkodowawczych. Dokumentacja API zmienia się w nakładający się szum, który zagłusza sygnał, którego faktycznie potrzebujesz. Opóźnienia rosną, aż użytkownicy porzucają zapytanie, zanim pojawi się odpowiedź. Trafiliśmy na tę ścianę i musieliśmy przebudować system. Nasza warstwa pobierania ewoluowała z modelu „semantycznego wyszukiwania i nadziei” w mierzalny, monitorowany potok (pipeline). Efektem był 95-procentowy recall i 40-procentowa redukcja opóźnień. Oto co faktycznie zadziałało.

Dopasuj strategię fragmentacji do dokumentu

Domyślna wartość 512 tokenów utrzymuje się, ponieważ jest łatwa, a nie dlatego, że jest poprawna. Różne dokumenty niosą znaczenie w różny sposób, a Twoja strategia fragmentacji powinna to odzwierciedlać.

W przypadku umów prawnych użyj fragmentacji rekurencyjnej, która szanuje granice strukturalne. Język prawniczy jest zagnieżdżony. Klauzula zależy od sekcji znajdującej się powyżej, a sztywne cięcie w połowie zdania niszczy logikę zobowiązania. Fragmentacja rekurencyjna najpierw próbuje dzielić tekst w oparciu o naturalne separatory — najpierw akapity, potem zdania — zanim narzuci limit tokenów. Dzięki temu klauzule odszkodowawcze lub dotyczące odpowiedzialności pozostają nienaruszone.

W przypadku dokumentacji API zastosuj fragmentację uwzględniającą funkcje (function-aware chunking). Programiści nie szukają przypadkowych akapitów; szukają punktów końcowych (endpoints), parametrów i sygnatur błędów. Fragment powinien zawierać pełną sygnaturę funkcji, jej opis oraz schemat zwracany jako jedną logiczną jednostkę. Jeśli podzielisz ten blok na pół, system wyszukiwania zwróci połowę kontekstu, a model generatywny zhalucynuje resztę.

W przypadku zgłoszeń wsparcia polegaj na fragmentacji semantycznej, która podąża za turami rozmowy. Wątki wsparcia są liniowe i powtarzalne. Klient powtarza problem, agent prosi o logi, klient je załącza. Każda tura stanowi własną jednostkę semantyczną. Fragmentacja według tur zachowuje informację o tym, kto i kiedy co powiedział, co ma znaczenie, gdy użytkownik pyta: „Co agent zasugerował we wtorek?”

W przypadku wewnętrznych wiki wypróbuj fragmentację agentową (agentic chunking). Przekaż sekcję modelowi LLM i poproś go o zdecydowanie, gdzie kończy się jeden temat, a zaczyna kolejny. Kosztuje to więcej podczas ingestu, ale wiki bywają chaotyczne. Strony zawierają niepowiązane aktualizacje od różnych zespołów, a granice zdefiniowane przez człowieka rzadko pomagają. Pozwolenie modelowi na wyznaczanie granic na podstawie zmian tematu drastycznie redukuje szum.

Uruchamianie wielu strategii w jednym potoku wymaga tagowania dokumentów według typu podczas ingestu. Ta niewielka dyscyplina w zakresie schematu zwraca się natychmiast.

Łącz metody wyszukiwania, zamiast wybierać jedną

Wyszukiwanie wektorowe rozumie intencję, ale regularnie zawodzi przy dokładnych dopasowaniach. Jeśli poprosisz o kod błędu ERR_CONNECTION_REFUSED lub konkretny numer SKU, gęste osadzenia (embeddings) często zwracają wyniki koncepcyjnie podobne, ale błędne pod względem faktów. BM25, klasyczna metoda rzadkiego wyszukiwania słów kluczowych, świetnie radzi sobie z dokładnymi ciągami znaków, ale pomija niuanse semantyczne. Potrzebujesz obu tych metod.

Zastosuj wyszukiwanie hybrydowe. Uruchom wyszukiwanie wektorowe i BM25 równolegle, a następnie połącz je za pomocą Reciprocal Rank Fusion (RRF). RRF premiuje dokumenty, co do których obie metody zgadzają się, że są istotne, jednocześnie wyłaniając silnych kandydatów z każdego z podejść. Matematyka jest prosta, a wynik stabilny: żadna pojedyncza metoda pobierania nie dominuje w końcowym rankingu.

Po fuzji dodaj reranker typu cross-encoder. Pierwszy etap — wyszukiwanie wektorowe plus rzadkie — jest szybki i szeroki. Następnie cross-encoder ocenia każdą parę zapytanie-dokument z pełną uwagą, co oznacza, że faktycznie analizuje kandydata w odniesieniu do oryginalnego pytania. Tak, to zwiększa opóźnienie. W naszym przypadku o około pięćdziesiąt do stu milisekund. Jednak zysk na precyzji jest na tyle duży, że wymiana ta jest oczywista. Nie możesz sobie pozwolić na pominięcie tego kroku, jeśli zależy Ci na recallu.

Napraw zapytanie, zanim naprawisz indeks

Użytkownicy nie piszą zapytań dla Twojej wyszukiwarki. Piszą je dla ludzi. „To nie działa” to częste zapytanie do wsparcia. Niejasny opis funkcji to częste wyszukiwanie w wewnętrznym wiki. Jeśli przeszukasz indeks za pomocą takiego surowego tekstu, otrzymasz śmieci.

Przekształć zapytanie, zanim trafi do retrievera.

Użyj rozszerzania zapytań (query expansion), aby wygenerować wiele wersji pytania użytkownika. Jeśli ktoś wpisze „server down”, Twój system powinien wyszukać również „service unavailable”, „502 error” oraz „connection timeout”. Uwzględnienie tych wariantów intencji zwiększyło nasz recall z 78% do 96%. To pojedynczy krok, który kosztuje niemal nic w porównaniu z uzyskanym zyskiem.

Zastosuj dekompozycję zapytań (query decomposition) dla złożonych pytań. Gdy użytkownik pyta o coś w stylu: „Jak mogę przejść z legacy billing API na nowe i jakie zmiany naruszające kompatybilność (breaking changes) dotyczą kont korporacyjnych?”, rozbij to pytanie na podpytania. Jedno podpytanie dotyczy kroków migracji. Inne dotyczy zmian naruszających kompatybilność specyficznych dla klientów korporacyjnych. Każde z nich trafia w inny fragment indeksu. Model językowy w dalszym etapie (downstream) syntetyzuje ostateczną odpowiedź z dobrze pobranych fragmentów (chunks), zamiast zgadywać w szumiącym oknie kontekstowym.

Przestań zgadywać hiperparametry

Gdy masz już wiele strategii dzielenia tekstu (chunking), hybrydowe wyszukiwanie (retrieval) i transformację zapytań, stajesz przed problemem kombinatorycznym. Rozmiar fragmentu (chunk size), nakładanie się (overlap), wagi fuzji, głębokość rerankera i liczba rozszerzeń – wszystkie te parametry na siebie oddziałują. Dostrajanie jednego z nich w izolacji psuje pozostałe. Przeszukiwanie siatkowe (grid search) tej przestrzeni jest marnotrawne i powolne.

Zamiast tego użyj optymalizacji bayesowskiej. Potraktuj to jak zadanie dostrajania modelu uczenia maszynowego. Jasno zdefiniuj swój cel: maksymalizuj recall, utrzymując opóźnienie (latency) poniżej określonego limitu. Zbuduj „golden dataset” — kilkaset reprezentatywnych pytań, przy których dokładnie wiesz, które fragmenty powinny zostać pobrane. Następnie pozwól wyszukiwaniu bayesowskiemu efektywnie przeszukiwać przestrzeń konfiguracji. Buduje ono model probabilistyczny tego, co działa, a następnie testuje najbardziej obiecujące obszary.

Każda kandydacka konfiguracja musi przejść przez golden dataset, zanim trafi do środowiska stagingowego. Jeśli nowy rozmiar fragmentu obniża recall lub cięższy reranker przekracza budżet opóźnień, optymalizacja automatycznie to wychwyci. To eliminuje subiektywne opinie. Przestajesz debatować, czy 256 czy 512 tokenów jest „lepsze”, i zaczynasz czytać wyniki.

Wynik

Zmiany w potoku (pipeline) skumulowały się dokładnie tak, jak się spodziewaliśmy.

  • Recall@10 wzrósł z 78% do 95%.
  • Opóźnienie P95 spadło z 850 ms do 320 ms.
  • Wskaźnik halucynacji spadł z 12% do 3%.
  • Koszt zapytania spadł o 38%, głównie dlatego, że lepsze wyszukiwanie pozwoliło nam użyć mniejszego modelu generatywnego i mniejszej liczby tokenów promptu.

Redukcja opóźnień zaskoczyła niektórych członków zespołu. Dodanie rerankerów i rozszerzania zapytań brzmi jak coś, co powinno spowolnić proces. Jednak dzięki poprawie jakości wyszukiwania, model generatywny potrzebował mniej promptowania, mniej spekulacji i mniej ponowień. Dobre wyszukiwanie sprawia, że wszystko w dalszym etapie jest tańsze.

Traktuj wyszukiwanie jak infrastrukturę

Wyszukiwanie (retrieval) to nie notatnik, który uruchamiasz raz i o nim zapominasz. To infrastruktura i powinna być zarządzana jak kod. Wersjonuj swoje strategie chunkingu. Gdy zespół prawny udostępnia nowy szablon umowy, przetestuj swój rekurencyjny splitter, zanim trafi on na produkcję. Utrzymuj swój golden dataset jako żywy dokument, a nie statyczny plik CSV z zeszłego kwartału. Automatyzuj ewaluacje w CI, aby każdy pull request modyfikujący model embeddingowy lub wagę fuzji otrzymywał komentarz z liczbami dotyczącymi recallu i opóźnień, zanim jeszcze człowiek go przejrzy.

Twoi użytkownicy nigdy nie zapytają, jakiego modelu embeddingowego używasz. Nie będą ich obchodzić twoje heurystyki chunkingu ani architektura rerankera. Będzie ich obchodzić, czy odpowiedź jest poprawna, czy przychodzi szybko i czy mogą jej zaufać. Zbuduj potok, który zasługuje na to zaufanie, mierz go uczciwie i przestań traktować wyszukiwanie jako coś, o czym myśli się na samym końcu.

Źródło: Optimizing RAG At Scale
Dołącz do dyskusji: GyaanSetu AI Community