RAG dla firmy pęka w przewidywalnej kolejności
Standardowe demo to pięć kroków: potnij dokumenty, zamień fragmenty na wektory, zapisz je, pobierz najbliższe dopasowania, podaj modelowi. Na małym, czystym zbiorze to działa i powód nie leży w pipelinie. Przy stu dokumentach rzadko istnieją dwa, które odpowiadają na to samo pytanie inaczej, więc prawie każdy retrieval trafia w ten jeden właściwy fragment.
Prowadzimy taki system nad bazą wiedzy z 500 tys.+ rekordów i najciekawsza nigdy nie była ścieżka szczęśliwa. Ciekawa była kolejność, w jakiej rzeczy się psuły, gdy zbiór rósł. Najpierw sens tracą chunki, potem po cichu degraduje się ranking, bo on przecież dalej coś zwraca i nic nie wygląda na zepsute. Wieloznaczność encji i nieaktualność przychodzą później. Zaufanie idzie na końcu i tylko ono wraca miesiącami.
Ani jedna z poprawek poniżej nie jest lepszym modelem. Wszystkie dotyczą retrievalu, ingestii i kontroli owiniętej wokół obu, czyli tej mniej efektownej połowy, której nikt nie pokazuje na demie. Jedno pytanie stoi wcześniej niż to wszystko: czy ten proces w ogóle warto było automatyzować. Ten tekst zakłada, że odpowiedź już padła i zostaje inżynieria.
Firmowa baza wiedzy to nie wiki, tylko archiwum z historią
Zbiór, na którym w polskiej firmie faktycznie stawia się RAG, wygląda inaczej niż dokumentacja produktu. To procedury w trzech wersjach, regulaminy z datą obowiązywania, polityki wewnętrzne po nowelizacji i przed, umowy z aneksami, instrukcje w PDF-ach, które kiedyś były skanem. Połowa tego jest aktualna, druga połowa nie, a w treści nie ma nic, co by je od siebie odróżniało - poza datą, której nikt nie wciągnął do metadanych.
HauerPower w tekście o RAG dla firmy wymienia listę ryzyk wdrożenia i dwa punkty z niej są dokładnie o tym: brak strategii aktualizacji i ignorowanie jakości dokumentów. Do tego dochodzi trzeci, o którym łatwo zapomnieć na etapie prototypu - uprawnienia. Jeśli baza zawiera dane kadrowe albo wynagrodzenia, filtr uprawnień musi działać na poziomie pobierania fragmentów, a nie w promptcie. Model, który dostał chunk do kontekstu, już go widział.
Jest jeszcze rzecz specyficzna dla naszego rynku: sporo firm trzyma dokumentację po polsku, a specyfikacje techniczne i maile z centrali po angielsku. To nie jest automatycznie problem, ale jest to rzecz do zmierzenia, a nie do założenia. Zadaj pytanie po polsku o treść, która istnieje wyłącznie w angielskim dokumencie, i sprawdź, czy w ogóle wraca. Jeśli nie wraca, wiesz to teraz, a nie po wdrożeniu.
Pierwszy pęka chunk
Chunking to moment, w którym dokument przestaje być dokumentem. Akapit „termin wynosi 30 dni od dostawy” ma sens na swojej stronie i nie znaczy nic osobno: który produkt, który rynek, która wersja warunków. Przy małym zbiorze zdradzą to sąsiednie fragmenty. Przy dużym masz czterysta chunków o terminach trzydziestodniowych i nic, co by je rozróżniało.
Anthropic opublikował liczby dokładnie o tym w tekście o contextual retrieval. Dopisanie do każdego chunku krótkiego, wygenerowanego opisu, gdzie ten fragment siedzi w dokumencie, zbiło wskaźnik nietrafionego pobrania z 5,7% do 3,7%. Dołożenie BM25 obok embeddingów dało 2,9%, a reranking scalonych wyników 1,9%. To ich liczby na ich zbiorze ewaluacyjnym, nie prawo natury, ale kierunek zgadza się z tym, co widzimy: tanie poprawki strukturalne ruszają wynik wcześniej niż cokolwiek wyrafinowanego.
Dane ustrukturyzowane psują chunking mocniej niż proza. Baza, przy której pracujemy, trzyma ID przedmiotów, tabele dropu w strefach, czasy respawnu i historię patchy, każde w innym schemacie, a pocięcie tabeli dropu po liczbie znaków niszczy wiersz, który stanowił całą jej wartość. Tnij wzdłuż własnej struktury dokumentu - wiersz tabeli, paragraf, sekcja - i do każdego chunku dokładaj metadane: dokument źródłowy, sekcję, wersję, datę obowiązywania. Wszystkie cztery pola wrócą w dalszej części tekstu.
Podobieństwo semantyczne to nie to samo co przydatność
Naiwne wyszukiwanie po embeddingach zwraca tekst najbardziej podobny do pytania, a nie tekst, który na nie odpowiada. Zapytaj nasz system o najlepszy sposób farmienia konkretnego materiału, a zwykłe wyszukiwanie wektorowe podniesie wszystko, co wspomina o farmieniu, i zgubi tę jedną tabelę dropu, która rozstrzyga sprawę. Wyniki nie są dokładnie błędne. Są trafione tematycznie i bezużyteczne, co jest gorsze, bo wygląda jak działający system.
Xenoss opisuje to strukturalnie w tekście o architekturze RAG dla przedsiębiorstw: waniliowy RAG traktuje wszystkie dokumenty równo, bez mechanizmu, który przedłożyłby źródło regulacyjne nad materiał pomocniczy, a sztywne top-k po cichu utożsamia podobieństwo semantyczne z trafnością. W firmowej bazie znaczy to tyle, że prezentacja onboardingowa i podpisana polityka konkurują na równych prawach, a prezentacja często wygrywa, bo jest napisana tym samym potocznym rejestrem co pytanie.
Wektory są najsłabsze dokładnie tam, gdzie firmowe pytania są najmocniejsze: przy identyfikatorach. Numer części, kod błędu, sygnatura umowy, dwie nazwy produktu różniące się jednym członem - to problemy leksykalne, a BM25 rozwiązuje je za grosze. Dlatego retrieval w naszej bazie jest hybrydowy: dense i BM25 łączone, potem reranking scalonego zbioru, żeby trafienie po dokładnej nazwie i trafienie semantyczne miały równą szansę na wejście do kontekstu.
Największą różnicę zrobiło jednak coś innego: odmowa szukania od razu. Retrieval działa w dwóch etapach. Pierwszy parsuje zapytanie w poszukiwaniu nazw i mapuje je na kanoniczne ID przez ustrukturyzowany lookup w realnych tabelach. Drugi robi wyszukiwanie semantyczne po treści, ograniczone tymi ID jako filtrem w metadanych. Twoje encje to nie przedmioty i strefy, tylko klienci, indeksy magazynowe, numery umów, maszyny, polityki - i już masz je w tabelach. To jest sedno: rozpoznanie encji jest zapytaniem do bazy, nie wywołaniem modelu, więc to najtańsza dokładność w całym pipelinie. Znika przy okazji cała klasa pomyłek, w której pytanie o zamówienie 4471 dostaje odpowiedź z zamówienia 4417, bo oba osadzają się niemal identycznie.
Czasem żaden pojedynczy fragment nie zawiera odpowiedzi
Część pytań nie ma fragmentu, który by na nie odpowiadał. Przykład, który ukształtował nasz projekt, z pozoru jest banalny: najlepszy sposób farmienia konkretnego materiału wymaga skrzyżowania ID przedmiotów, tabel dropu w strefach, czasów respawnu mobów i historii patchy, a każde z tego siedzi w innym schemacie. Żaden chunk nie zawiera odpowiedzi, bo odpowiedź nie istnieje, dopóki nie połączysz czterech źródeł.
Firmowe bazy są pełne tego samego kształtu. Czy możemy wysłać tę konfigurację klientowi w Niemczech na obecnej umowie? To specyfikacja produktu, klasyfikacja eksportowa i zapis umowny, w trzech dokumentach pisanych przez trzy zespoły, które nigdy nie czytały swoich tekstów nawzajem. Top-k zwróci ten najbliższy, a model napisze pewną siebie odpowiedź z jednej trzeciej obrazu.
Pomagają trzy ruchy i drożeją w tej właśnie kolejności. Rozłóż pytanie na podpytania i pobierz materiał do każdego z osobna - to głównie zmiana promptu. Te fragmenty, które naprawdę są odpytaniem tabeli, skieruj do tabeli, zamiast oczekiwać od indeksu wektorowego, że pamięta, czym jest JOIN. Dopiero potem patrz na podejścia grafowe i wchodź tam ze świadomością rachunku: Xenoss opisuje wdrożenie pod EU AI Act, w którym GraphRAG potrzebował 20 razy więcej tokenów niż odpowiednik waniliowy, przy mniej więcej dwukrotnie dłuższym czasie przetwarzania. Bywa też, że odpowiedzi nie ma w dokumentach w ogóle, tylko w systemie, który zna bieżący stan - wtedy retrieval przestaje być wyszukiwaniem i staje się wywołaniem narzędzi, czyli podłączeniem AI do danych na żywo, co ma własny zestaw problemów.
Każ modelowi udowodnić każdą liczbę, którą podaje
Najdroższa awaria to liczba, którą model wyprodukował z pamięci. Zapytaj naszego asystenta o drop rate, a wersja bez osadzenia poda precyzyjny procent - pewnie i precyzyjnie błędnie. To precyzja rozbraja czytelnika. Liczby z dwoma miejscami po przecinku prawie nikt nie sprawdza drugi raz, i tak właśnie błędne przechodzą review, a potem lądują w raporcie.
Dlatego każda liczbowa deklaracja w odpowiedzi - procent, licznik czasu, wymagany poziom - jest weryfikowana względem źródłowego chunku, z którego rzekomo pochodzi, zanim odpowiedź wyjdzie. Deklaracja bez możliwego do pobrania źródła jest pomijana albo oznaczana jako niezweryfikowana, nigdy wygładzana w płynną prozę. To decyzja produktowa tak samo jak inżynierska: system ma prawo powiedzieć, że nie wie, i dopiero to prawo nadaje wartość reszcie jego odpowiedzi.
Cytowanie niesie więcej niż link. Każdy fakt cytuje stronę źródłową, wersję patcha i znacznik czasu zebrania danych, więc czytelnik widzi, jak aktualna jest odpowiedź, bez pytania kogokolwiek. W firmowej bazie przekłada się to na ID dokumentu, wersję, datę obowiązywania i moment pobrania. To nie jest ozdobnik zgodnościowy: art. 14 AI Act wymaga, żeby osoba nadzorująca system wysokiego ryzyka potrafiła poprawnie zinterpretować jego wynik i pozostawała świadoma skłonności do nadmiernego polegania na nim. Bez widocznego źródła i wersji nikt tej odpowiedzi nie zweryfikuje, więc nadzór zostaje na papierze. Które z tych obowiązków wiążą już teraz, a które dopiero w 2027, rozłożyliśmy osobno w tekście o obowiązkach z AI Act.
Ta sama reguła wraca w zupełnie innej dziedzinie. W asystencie rektora zbudowanym dla uczelni model nie ma prawa odpowiadać na pytania o statystyki z pamięci: każda liczba jest pobierana w momencie pytania, decyzje zatwierdza człowiek, a każde działanie jest logowane. Wzorzec pod tym wszystkim mieści się w jednym zdaniu. Jeśli model może coś zadeklarować, każ mu to udowodnić - do tego samego wniosku doszliśmy, rozbierając pięć produkcyjnych awarii.
Odpowiedź, która była poprawna w zeszłym kwartale, jest dziś błędna
Baza wiedzy nie jest zdjęciem stanu, a po cichu gniją dokładnie te systemy, które tak się traktuje. W bazie o grze każdy patch przetasowuje drop rate'y, strefy i mechaniki, więc pipeline ingestii przetwarza dane źródłowe w sposób ciągły, wersjonuje chunki, gdy patch je zmienia, i oznacza nieaktualną treść, zanim ta w ogóle dotrze do retrievalu. Ten ostatni krok brzmi jak sprzątanie i nim nie jest: to reguła, która nie pozwala starej odpowiedzi wrócić jako aktualna.
Dokumenty firmowe zmieniają się wolniej i robią większą szkodę, gdy się rozjadą. Wersja 3 polityki leży w indeksie obok wersji 7, obie osadzają się niemal identycznie, a retrieval nie ma zdania na temat tego, która obowiązuje, dopóki ktoś mu tego zdania nie da. Powstająca awaria nie jest halucynacją i to czyni ją trudną do podważenia. To wierny cytat z dokumentu, który przestał obowiązywać dwie nowelizacje temu.
W praktyce: wersjonuj przy ingeście zamiast dopisywać, trzymaj daty obowiązywania i wygaśnięcia w metadanych chunku, filtruj po nich w momencie zapytania, a przy zmianie dokumentu usuwaj i indeksuj od nowa, zamiast kłaść nową wersję obok starej. Ingestia przestaje być skryptem, który ktoś odpala po obiedzie, i staje się pipeline'em ze stanem. Ten krok większość zespołów lekceważy, a to on rozstrzyga, czy w szóstym miesiącu ktokolwiek jeszcze ufa systemowi.
Skarga, którą słyszysz, rzadko wskazuje na to, co jest zepsute
Użytkownicy nie zgłaszają awarii retrievalu. Zgłaszają, że asystent jest niepewny, co jest prawdą i nie da się na tym pracować. Tabela niżej mapuje zdania, które ludzie faktycznie wypowiadają, na warstwę pod spodem. Kolejność debugowania ma tu znaczenie: naprawianie generowania, gdy problem siedzi w retrievalu, daje system, który ładniej pisze błędne odpowiedzi.
| Co mówią użytkownicy | Co jest naprawdę zepsute | Poprawka | Ile kosztuje |
|---|---|---|---|
| „Odpowiedział regulaminem innego działu” | Chunki straciły kontekst, który je identyfikował | Cięcie po strukturze, metadane przy każdym chunku | Pełne przeindeksowanie i wolniejszy ingest |
| „Nie umie znaleźć po numerze części” | Sam retrieval wektorowy, słaby na dokładnych tokenach | Dołóż BM25, scal wyniki, zrób reranking | Drugi indeks do utrzymania |
| „Odpowiedź jest na temat i bezużyteczna” | Sztywne top-k myli podobieństwo z trafnością | Reranking i filtr po rozpoznanej encji | Dodatkowe wywołanie modelu na zapytanie |
| „Pomylił dwa podobne rekordy” | Brak rozpoznania encji przed wyszukiwaniem | Mapuj nazwy na kanoniczne ID i filtruj po nich | Słownik, który trzeba utrzymywać |
| „Liczba była precyzyjna i nieprawdziwa” | Model odpowiedział z pamięci, nie ze źródła | Weryfikuj każdą deklarację względem chunku | Wolniejsze odpowiedzi, część pytań bez odpowiedzi |
| „Zacytował politykę, którą zmieniliśmy” | Indeks nie ma pojęcia wersji | Wersjonuj przy ingeście, filtruj po dacie | Ingestia staje się pipeline'em, nie skryptem |
| „Nikt już z tego nie korzysta” | Wszystko powyższe, odkryte najpierw przez użytkowników | Zbiór ewaluacyjny i klikalne cytowania | Miesiące, i to jest prawdziwa pozycja w rachunku |
Przejedź kolumnę z poprawkami od góry do dołu i zobacz, czego w niej nie ma. Żaden wiersz nie każe kupić większego modelu ani nowszego embeddingu. Cała lista to hydraulika.
Pięć sond, które odpalisz u siebie w jedno popołudnie
Nie potrzebujesz frameworka ani zewnętrznego zespołu, żeby sprawdzić, którą z tych awarii masz. Wystarczy pięć zapytań i popołudnie, a każda sonda celuje w jedną warstwę, więc porażka wskazuje poprawkę zamiast nastroju. Puszczaj je na systemie, który już działa, nie na świeżym indeksie zbudowanym pod test.
| Sonda | Jak ją zrobić | Jak wygląda porażka |
|---|---|---|
| Dokładny identyfikator | Poproś o rekord po numerze części, sygnaturze umowy albo ID polityki, który występuje raz. | Dostajesz tematycznych sąsiadów zamiast rekordu |
| Nieobowiązująca wersja | Zaindeksuj starą i aktualną wersję jednego dokumentu, zadaj pytanie, na które odpowiadają obie. | Cytuje starą albo wybiera losowo |
| Pytanie przez kilka dokumentów | Zapytaj o coś, na co żaden pojedynczy dokument nie odpowiada samodzielnie. | Płynna odpowiedź z tego jednego, który znalazł |
| Pochodzenie liczby | Poproś o liczbę, potem zapytaj, skąd pochodzi, i otwórz źródło. | Brak cytowania albo źródło bez tej liczby |
| Znane odpowiedzi | Spisz 50 realnych pytań z ludźmi, którzy dziś na nie odpowiadają, i zachowaj odpowiedzi. | Nie umiesz powiedzieć, czy zeszłotygodniowa zmiana pomogła |
Ostatni wiersz zespoły pomijają najczęściej i to on się zwraca. Oceniaj retrieval osobno od generowania: pierwsza liczba, którą warto obserwować, to czy właściwy chunk w ogóle dotarł do kontekstu. Problem retrievalu i problem generowania wyglądają z zewnątrz identycznie, a w środku nie mają ze sobą nic wspólnego. Pięćdziesiąt pytań wystarczy na start. Musi być tylko więcej niż opinia.
Budujemy takie systemy zawodowo, więc odpowiednio zważ to nastawienie - ale sondy kosztują popołudnie i żadnego dostawcy, a powiedzą ci więcej niż kolejna runda poprawiania promptów. Jeśli wolisz drugą parę oczu na to, gdzie konkretna baza najpewniej pęknie, krótki audyt to niskostawkowy sposób, żeby ją mieć.
FAQ
Ile dokumentów wytrzyma naiwny RAG, zanim przestanie działać?
Nie ma jednej liczby, bo kształt zbioru znaczy więcej niż jego rozmiar. Dwieście czystych, różnych dokumentów potrafi działać bez problemu, a pięć tysięcy, w których siedzą trzy wersje każdej procedury i sporo powtarzalnego szablonu, sypie się wcześnie. Sygnały ostrzegawcze to duplikaty, dokumenty wersjonowane i pytania rozstrzygane przez identyfikator - przy którymkolwiek z nich zwykłe top-k po embeddingach zaczyna zwracać pewne siebie pudła.
Czy do firmowej bazy wiedzy potrzebna jest dedykowana baza wektorowa?
Zwykle nie, przynajmniej na start. Opisany tu system nad 500 tys.+ rekordów działa na PostgreSQL z pgvector, obok Pythona, LangChaina i FastAPI, i to nie baza była wąskim gardłem, tylko jakość retrievalu. Wczesne dokładanie wyspecjalizowanego magazynu wektorów kupuje głównie infrastrukturę do utrzymania, a nie odpowiedzi, którym można ufać, więc najpierw warto wyczerpać pracę nad chunkingiem, wyszukiwaniem hybrydowym i rozpoznawaniem encji.
Czy RAG dla firmy da się pogodzić z RODO?
Da się, ale filtr uprawnień musi działać na etapie pobierania fragmentów, a nie w promptcie. Chunk, który trafił do kontekstu modelu, został już ujawniony, więc dostęp trzeba egzekwować w zapytaniu do indeksu, na podstawie roli pytającego. Do tego dochodzi minimalizacja - baza wiedzy rzadko potrzebuje danych kadrowych w pełnym zakresie - oraz ślad, kto o co pytał i z jakiego dokumentu przyszła odpowiedź. To nie jest porada prawna, tylko lista rzeczy, które i tak trzeba zaprojektować w systemie.
Jak powstrzymać system RAG przed cytowaniem nieaktualnych procedur?
Trzeba dać indeksowi pojęcie czasu, bo domyślnie go nie ma. Wersjonuj chunki przy ingeście, trzymaj daty obowiązywania i wygaśnięcia w metadanych, filtruj po nich w momencie zapytania, a zmieniony dokument usuwaj i indeksuj od nowa zamiast kłaść nową wersję obok starej. Potem każ każdej odpowiedzi cytować wersję i datę dokumentu, z którego korzystała - wtedy nieaktualna odpowiedź jest widoczna, a nie tylko błędna.
Co mierzyć, żeby wiedzieć, czy retrieval działa?
Mierz retrieval osobno od odpowiedzi, zaczynając od tego, czy właściwy fragment w ogóle dotarł do kontekstu modelu. Zbuduj zestaw realnych pytań ze znanymi odpowiedziami, spisany razem z ludźmi, którzy dziś na nie odpowiadają, i śledź dwie liczby w czasie: jak często pobierane jest właściwe źródło i jak często finalna odpowiedź jest poprawna oraz ocytowana. Bez tego rozdzielenia błąd wyszukiwania i błąd generowania są nie do odróżnienia, a zespoły tygodniami stroją prompty przeciwko problemowi z wyszukiwaniem.
- 24 lipca 2026Publikacja.