Strona główna / Artykuły

Jak naprawić puste wyniki wyszukiwania, gdy system RAG nie zwraca żadnych danych

System RAG, który nie zwraca żadnych wyników, naprawiany krok po kroku: pobieranie danych, progi oceny, filtry, przepisywanie zapytań, wyszukiwanie hybrydowe, ponowna klasyfikacja i rozwiązania awaryjne.

Wydawca: REACTAPP.TOP9 min czytania2016 słów

Źródła: **Part II — When RAG Returns Nothing**

Generowanie wzbogacone o wyszukiwanie dostarcza modelowi językowemu informacje pochodzące spoza danych treningowych, dzięki czemu nie musi odpowiadać wyłącznie na podstawie tych danych, co oznacza, że ostateczna odpowiedź jest tak dobra, jak tylko informacje uzyskane przez wyszukiwanie. Gdy wyszukiwanie nie przynosi nic przydatnego, model ma niewiele lub żadnych dowodów. Może zastosować ogólną odpowiedź, odmówić lub wymyślić szczegóły. Poniżej omówiono, skąd pochodzą puste lub prawie puste wyniki, oraz jak je znaleźć.

Wyszukiwanie może zawieść się na wielu etapach

Pusty wynik to nie jeden rodzaj awarii. Kandydat na odpowiedź może zniknąć podczas przetwarzania, tworzenia wektorów, wyszukiwania wektorowego, filtrowania metadanych, ustalania progów lub sortowania. Naprawa błędów przebiega szybciej, gdy sprawdzamy każdy etap osobno i przestajemy traktować całą architekturę RAG jako jedną czarną skrzynkę.

1. Zacznij od indeksowania i wektorów

Zanim dotkniesz narzędzia do wyszukiwania, upewnij się, że baza wiedzy zawiera to, co według ciebie powinna. Pomyślny proces przetwarzania pokazuje logiczną sekwencję: od dokumentów źródłowych przez tekst zinterpretowany, aż po fragmenty, embeddingi i przechowywane wektory. Jeśli utworzono 2000 fragmentów, a do bazy trafiło tylko 200 wektorów, żadna optymalizacja narzędzia nie pomoże.

  • Ręcznie otwórz kilka przechowywanych fragmentów. Powinny zawierać czytelny tekst, stabilne identyfikatory, embeddingi oraz wszelkie metadane, od których zależą twoje filtry.
  • Używaj tych samych modeli i wymiarów embeddingów zarówno dla dokumentów, jak i dla zapytań użytkowników. Zmiana modelu zapytania bez ponownego budowania indeksu sprawi, że wyniki podobieństwa stracą sens.
  • Ocenić należy również parser. Pliki PDF, skany, tabele i strony HTML mogą zamienić się w puste lub uszkodzone fragmenty, mimo że system nadal podaje, iż operacja zakończyła się pomyślnie.

2. Sprawdź progi, znaczenie wyników i filtry

Agresywne progi ocen są częstą przyczyną braku wyników. Oceny embeddingowe nie są procentami pewności, a ich przydatny zakres zmienia się w zależności od modelu, metryki odległości, danych oraz bazy danych wektorowej. Podczas debugowania wybierz najlepsze 10 lub 20 kandydatów bez żadnych progów i sprawdź ich surowe oceny:

results = vector_store.search(query_embedding, top_k=10)
for r in results:
    print(r.score, r.metadata.get('source'))

Następnie sprawdź, w jakim kierunku są przypisywane oceny. Niektóre API zwracają podobieństwo kosinowe, przy którym im wyższa wartość, tym lepiej. Inne zwracają odległość kosinową lub euklidesową, przy których im niższa wartość, tym lepiej. Użycie niewłaściwego kryterium porównania potajemnie odrzuca twoje najlepsze kandydaty i zachowuje te słabsze. Zasadniczo nie wpisywaj żadnych warunków progowych, dopóki nie potwierdzisz zasady przypisywania ocen w bazie danych i nie przejrzysz rzeczywistych rozkładów ocen z reprezentatywnych zapytań.

Filtrzy mogą usuwać dobre wyniki

Filtrowanie metadanych jest kluczowe w systemach wielu najemców, przy uprawnieniach, zakresach produktów, datach, językach i typach dokumentów, a jednocześnie należy do najprostszych sposobów na uzyskanie pustego zbioru wyników. Typowymi przyczynami są porównywanie ciągów znaków z liczbami całkowitymi, niespójna pisownia, starsze rekordy bez metadanych, błędne identyfikatory najemców oraz filtry, które pojedynczo są poprawne, ale razem są niemożliwe do zastosowania.

3. Przegląd przepisywania zapytania i jakości fragmentów

Przepisywanie zapytania może pomóc w jego wyszukiwaniu, ale może również usunąć właśnie ten termin, który sprawił, że zapytanie mogło zostać odnalezione. Wyobraźmy sobie kogoś, kto pyta, jak sformatować X500, podczas gdy narzędzie przepisywania zamienia to na „przywrócenie domyślnej konfiguracji serii X”. Jeśli instrukcja ma nazywać się „Sformatowanie X500”, to własne sformułowanie użytkownika najprawdopodobniej lepiej do niej pasuje. Zapisz zarówno oryginalne, jak i przepisane zapytanie i przetestuj każde z nich. W przypadku dokładnych identyfikatorów, kodów błędów, nazw produktów oraz parametrów API zachowaj dosłowne tokeny, nawet jeśli reszta zapytania zostanie znormalizowana.

Podział na fragmenty zawodzi w podobny sposób. Nagłówek taki jak „Szybkie ustawienie routera X500” nie powinien być oddzielony od instrukcji poniżej niego. Dziel dokument zgodnie z jego strukturą, aby nagłówek, jego akapity, pozycje listy oraz otaczający je kontekst pozostały nierozdzielone. Odpowiednia wielkość fragmentu zależy od obciążenia, choć rozsądny zakres początkowy to około 500 do 1 000 tokenów z umiarkowanym nakładaniem się, a następnie ocena na rzeczywistych zapytaniach.

Co mierzyć: weź małą grupę oznaczonych zapytań i zapisz, czy oczekiwany źródło pojawia się w wynikach top-k. Ten test skupiony na odzyskiwaniu informacji jest lepszy niż wybieranie wielkości fragmentów lub progów na podstawie intuicji.

4. Mieszanie wyszukiwania leksykalnego i wektorowego

Wyszukiwanie wektorowe sprawdza się wtedy, gdy użytkownik i dokument wyrażają tę samą ideę w inny sposób. Wyszukiwanie leksykalne, takie jak BM25, jest skuteczne, gdy istotne są dokładne tokeny. Ponieważ trudne zapytania rzadko należą wyłącznie do jednego typu, systemy produkcyjne często wykorzystują oba podejścia. BM25 zazwyczaj przewyższa inne metody w przypadku kodów błędów (np. ERR-XK-1042), numerów SKU, numerów faktur, nazw produktów, nazw klas, kluczy konfiguracyjnych oraz nazw parametrów API. Wyszukiwanie wektorowe dodaje bliskie pod względem koncepcyjnym wyniki, natomiast BM25 zapewnia, że nie zostaną przeoczone dokładne dane leksykalne. Typowy projekt najpierw pozyskuje szeroki zbiór kandydatów, a następnie stosuje silniejszy algorytm ponownego rankowania w celu uzyskania większej precyzji.

5. Pozyskaj szeroki zbiór wyników, a następnie przeprowadź ponowne rankowanie

Urządzenie do wyszukiwania na pierwszym etapie oraz narzędzie do ponownego rankowania pełnią różne funkcje. Urządzenie do wyszukiwania powinno maksymalizować stopień odnalezienia odpowiedzi, zbierając wszystko, co może na nią wskazywać. Narzędzie do ponownego rankowania powinno maksymalizować dokładność, porównując zapytanie z tymi kandydatami i wysuwając na czoło najlepsze dowody.

Często stosuje się schemat, w którym ze szukania wektorowego i leksykalnego gromadzi się od 20 do 50 kandydatów, łączy się je i usuwa duplikaty, a następnie ponownie rankuje, pozostawiając najlepsze 5 do 10 elementów. Kodery krzyżowe są wydajne i przeznaczone do oceny istotności, natomiast narzędzie do ponownego rankowania oparte na LLM może realizować bardziej złożone instrukcje, ale zazwyczaj jest wolniejsze i droższe.

Nie należy wcześnie odrzucać kandydatów. Jeśli twardy próg zostanie zastosowany przed narzędziem do ponownego rankowania, element, który naprawdę mógłby pomóc, może nigdy nie zostać rozpatrzony przez silniejszy model oceny istotności. Często lepszy efekt daje pierwsze, luźne przeszukanie, po którym następuje ponowne rankowanie, niż poleganie wyłącznie na wyniku wektorowym do ustalenia całej kolejności.

Fuzja i usuwanie duplikatów

Gdy łączy się wyniki wektorowe z wynikami BM25, jeden fragment może pojawić się w obu listach, a skale ocen nie są zgodne. Należy zastosować metodę fuzji, taką jak fuzja na podstawie wzajemnego rankingu, znormalizowane oceny ważone lub proste łączenie rankingów, a także usunąć duplikaty za pomocą stabilnych identyfikatorów fragmentów lub dokumentów przed procesorem ponownego rankowania. Celem projektu jest dostosowanie pierwszego etapu do poprawy wskaźnika召回, pozwalając jednocześnie procesorowi ponownego rankowania oraz logice wyboru kontekstu na zapewnienie dokładności, co ułatwia dostosowanie i ocenę całego procesu.

6. Rozszerzenie zapytania z zaplanowanym rozwiązaniem awaryjnym

Ludzie i dokumenty rzadko dzielą ten sam słownictwo. Osoba pisząca „Nie mogę się zalogować” może potrzebować stron z tytułami takimi jak „błąd autoryzacji”, „rozwiązywanie problemów z logowaniem” lub „dostęp do konta”. Narzędzie to generuje kilka alternatywnych zapytań, przetwarza je wszystkie, a następnie usuwa duplikaty i ponownie sortuje wyniki. Trzeba to kontrolować: nie ingerować w nazwane entity i dokładne identyfikatory, unikać tworzenia wielu niemal identycznych zapytań oraz ograniczyć liczby prób, aby jedno trudne zapytanie nie wywołało kosztownego pętli.

Tylko luzować to, co można bezpiecznie luzować. Filtry bezpieczeństwa, dotyczące użytkowników i uprawnień nigdy nie są opcjonalne i muszą pozostać włączone. Elementy takie jak opcjonalna kategoria dokumentu, wąski zakres dat lub dodatkowe tagi mogą zostać złagodzone, jeśli to pozwalają zasady aplikacji. Prosta sekwencja działań:

docs = retrieve(query)
if not useful(docs): docs = retrieve(expand(query), hybrid=True)
if not useful(docs): return ask_for_clarification_or_no_answer()

Pusty wynik versus błędne wyszukiwanie

Te dwa przypadki wymagają różnych rozwiązań. Jeśli nic nie zostanie znalezione, sprawdź możliwość przetworzenia danych, filtry, uprawnienia, progi, interpretację wyników lub dostępność indeksu. Jeśli wyniki pojawiają się, ale są nieodpowiednie, przyjrzyj się podziale na fragmenty, jakości embeddingów, brakom w słowniku, ograniczonej liczbie słów lub algorytmom rankingu.

7. Bardziej odporna architektura produkcyjna

Zaawansowany system RAG nie kieruje każdej zapytania tą samą ścieżką wyszukiwania. Klasyfikuje żądanie i wybiera strategię wyszukiwania odpowiadającą jego potrzebom: zapytania z dokładnymi identyfikatorami wykorzystują wyszukiwanie leksykalne, szerokie pytania konceptualne – wyszukiwanie wektorowe, a zapytania niejednoznaczne lub mieszane – oba rodzaje wyszukiwania.

Następnie krok agregacji umożliwia połączenie źródeł w jednym miejscu, usunięcie duplikatów, zastosowanie reguł metadanych i uprawnień, które muszą być przestrzegane, oraz wysłanie pojedynczej, spójnej listy kandydatów do ponownego sortowania. Pewność siebie nie powinna opierać się wyłącznie na jednym wyniku wektorowym. Lepszymi wskaźnikami są wynik ponownego sortowania, rozrzut między najlepszymi wynikami, liczba źródeł, które przyczyniają się do wyniku, to, czy entity potrzebne do odpowiedzi rzeczywiście pojawiają się w kontekście, oraz to, czy kilka fragmentów tekstowych jest zgodnych.

Pewność siebie decyduje o kolejnym kroku

Gdy pewność siebie jest wystarczająca, najlepiej ocenione dowody trafiają do modelu LLM. Przy niskiej pewności system może rozszerzyć lub przeformułować zapytanie, spróbować ponownie lub zadać użytkownikowi pytanie uzupełniające. To lepsze niż zawsze udzielanie odpowiedzi, ponieważ model otrzymuje jasny sygnał, gdy dowody są zbyt słabe, by umożliwić uzasadnioną odpowiedź.

Unikaj angażowania bezpieczeństwa w pętlę prób

Każdy projekt awaryjny musi trzymać zasady istotności oddzielnie od zasad autoryzacji. Rozszerzenia mogą złagodzić sformułowania, a opcjonalne filtry tematyczne czasami mogą zostać usunięte, ale granice użytkowników, ACL-y, uprawnienia na poziomie wierszy oraz polityki prywatności pozostają niezmienne przy każdej próbie. Ścieżka ponownej próby nigdy nie może stać się sposobem obejścia kontroli dostępu.

8. Umożliwienie obserwacji procesu pobierania

Gdy w dziennikach znajduje się tylko ostateczna odpowiedź, debugowanie RAG zamienia się w zgadywanie. Warstwa pobierania powinna generować wystarczająco dużo danych, aby można było odtworzyć to, co wydarzyło się przy każdym zapytaniu. Należy zarejestrować przynajmniej: oryginalne zapytanie, przepisane lub rozszerzone wersje, filtry, model embedding z jego wymiarami, który mechanizm pobierania został użyty, metodę top-k, liczbę surowych kandydatów, które wróciły, ich oceny, wybrane fragmenty, oceny mechanizmu ponownego rankingu, opóźnienie oraz który mechanizm awaryjny został uruchomiony.

log({
  'query': query, 'rewritten': rewritten_query, 'filters': filters,
  'candidate_count': len(raw_results), 'scores': scores,
  'selected_chunk_ids': selected_ids, 'fallback': fallback_stage
})

Rozsądna kolejność debugowania

Gdy wystąpi problem z pustymi wynikami wyszukiwania, należy zacząć od najtańszych i najbardziej deterministycznych sprawdzeń, przechodząc stopniowo do bardziej subiektywnych metod oceny. Dzięki temu zespoły nie będą dostosowywać promptów czy embeddingów, gdy rzeczywistym problemem jest brak indeksu lub niemożliwy filtr.

  1. Najpierw sprawdzenie procesu pobierania danych: liczba dokumentów, przetworzony tekst, liczba fragmentów, przechowywane wektory oraz kilka rekordów, o których wiadomo, że powinny istnieć.
  2. Następnie surowe wyszukiwanie: wysłać oryginalną zapytanie bez żadnych opcjonalnych filtrów i progów, a potem przeczytać najlepsze wyniki oraz ich oceny.
  3. Po kolei przywracać filtry, co pozwoli określić dokładnie ten filtr, który powoduje puste wyniki.
  4. Sprawdzić semantykę ocen: czy wyższa czy niższa wartość jest lepsza, oraz czy zastosowano jakąś normalizację?
  5. Porównać oryginalne i przepisane zapytania, zachowując dokładne identyfikatory, aby sprawdzić, czy przepisanie pomaga lub szkodzi dokładności wyników.
  6. Przeprowadź ocenę hybrydowego wyszukiwania i ponownego rankowania na podstawie zaznaczonego zbioru zapytań, sprawdzając, czy oczekiwane źródła pojawiają się w grupach top-k i top-n po ponownym rankowaniu.
  7. Przetestuj mechanizm awaryjny, wywołując puste lub słabe wyniki, aby upewnić się, że system wyjaśnia sytuację lub odrzuca zapytanie, a nie tworzy fałszywych informacji.

Co mierzyć

Jakość odpowiedzi sama w sobie nie dostarcza wystarczających informacji na temat skuteczności wyszukiwania. Należy śledzić wskaźnik recall@k (czy oczekiwane źródło znalazło się w zestawie kandydatów?), precyzję po ponownym rankowaniu, częstotliwość pojawiania się pustych wyników, wskaźnik mechanizmu awaryjnego, opóźnienia oraz udział zapytań wymagających uzupełnienia lub wyjaśnienia. Należy to rozdzielić według typu zapytania, takiego jak pytania semantyczne w porównaniu z identyfikatorami dokładnymi, oraz według użytkownika, języka i kolekcji dokumentów, ponieważ ogólne średnie mogą ukrywać problemy w poszczególnych grupach.

Nie obwiniaj najpierw modeli językowych

Gdy RAG nie zwraca żadnych wyników, unikaj wskazywania winy na model. Przyczyna zazwyczaj leży wcześniej w procesie wyszukiwania: niekompletne przetwarzanie danych, niekompatybilne embeddingi, zbyt restrykcyjne progi, błędne filtry metadanych, błędna ocena wyników, agresywne przepisywanie zapytań lub strategia pozyskiwania informacji nieodpowiednia do danego zapytania. Niezawodne systemy łączą skuteczne indeksowanie z hybrydową strategią pozyskiwania danych, szeroką generacją kandydatów, ponownym sortowaniem, kontrolowanym rozszerzaniem zapytań, wyraźnym zachowaniem awaryjnym oraz rozbudowaną telemetrią. Przydatnym modelem myślowym jest to, że RAG to przede wszystkim problem wyszukiwania i sortowania, a dopiero potem problem generowania treści. Gdy warstwa pozyskiwania informacji niezawodnie dostarcza istotne, uprawnione dane i wie, kiedy tego nie może zrobić, model staje się dokładniejszy, łatwiejszy do wyjaśnienia i mniej podatny na halucynacje.

Literatura pokrewna

  • Dartboard RAG: Co robić, gdy Top-K zwraca ten sam fragment trzy razy — Zwykłe wyodrębnianie elementów za pomocą Top-K może zwracać niemal identyczne fragmenty. Dartboard RAG bierze pod uwagę zarówno istotność, jak i różnorodność; oto algorytm, kod oraz sytuacje, w których należy go stosować.
  • Zaawansowane RAG w produkcji: architektura, narzędzia i kompromisy — Przegląd zastosowań RAG w środowisku produkcyjnym: pobieranie danych, analiza, dzielenie na fragmenty, tworzenie wektorów, przechowywanie wektorów, hybrydowe metody wyodrębniania elementów, ponowna sortowanie, ocena efektywności oraz zasady bezpieczeństwa, wraz z kompromisami związanymi z każdą z tych metod.
  • RAG w czasie zapytania przy dziesięciu milionach dokumentów: lejki, routery, agenci i metryki oceny — Lejek wyszukiwania poniżej 200 ms z filtrami SQL, hybrydowym wyszukiwaniem i ponownym rankowaniem, a także routowaniem zapytań, orkiestracją agentów, metrykami oceny oraz skryptem pipeline Qdrant.
  • Notatki praktyczne: Poprawa wydajności RAG — Część 2: HyDE (hipotetyczny dokument) — Szczegółowy przewodnik po notatkach praktycznych: Poprawa wydajności RAG — Część 2: HyDE (hipotetyczny dokument), wraz z przykładami umów, sprawdzeń oraz miejscami na kod do wdrożenia dla zespołów stosujących ten model.