Blog JSystems - uwalniamy wiedzę!
Blog JSystems - uwalniamy wiedzę!
Najczęstszy zarzut wobec firmowych asystentów AI brzmi: świetnie gada, ale o naszej firmie nie wie nic. Model nie zna Twoich procedur, dokumentacji produktu, historii zgłoszeń ani regulaminów, bo nigdy ich nie widział. RAG, czyli generowanie wzbogacone wyszukiwaniem (Retrieval-Augmented Generation), zmienia tę sytuację: zanim model odpowie, system podsuwa mu pasujące fragmenty Twoich dokumentów. Ten artykuł nie jest kolejnym tutorialem krok po kroku. Jest o tym, co dzieje się między pierwszym prototypem a działającym wdrożeniem: jakie decyzje podjąć, ile to realnie kosztuje, gdzie wdrożenia się wykładają i kiedy w ogóle nie warto budować RAG.
Wyobraź sobie egzaminatora, który pozwala zdającemu zajrzeć do podręcznika. RAG działa podobnie. Sam model językowy zostaje nietknięty, to gotowy, ogólny silnik. Dokładasz do niego Twoją bazę wiedzy: dokumenty firmy są dzielone na fragmenty (chunki), zamieniane na osadzenia (embeddingi), czyli liczbowe reprezentacje znaczenia tekstu, i zapisywane w bazie wektorowej (vector store). Gdy ktoś zadaje pytanie, system wyszukuje w tej bazie kilka najbardziej pasujących fragmentów i wkłada je do polecenia obok pytania. Model odpowiada na podstawie tego, co dostał, a nie na podstawie ogólnej wiedzy z internetu. Tyle teorii. Reszta artykułu jest o tym, jak doprowadzić to do stanu, w którym faktycznie działa w firmie.
RAG nie jest rozwiązaniem szukającym problemu. Sprawdza się tam, gdzie firma ma dużo wiedzy zapisanej w tekście, a ludzie tracą czas na jej przeszukiwanie. Trzy najczęstsze scenariusze:
Dokumentacja techniczna, instrukcje wdrożeniowe, baza zgłoszeń wsparcia. Zamiast przeklikiwać się przez intranet, pracownik pyta naturalnym językiem: jak skonfigurować integrację z systemem płatności? Asystent znajduje właściwy fragment w setkach stron dokumentacji i odpowiada, wskazując źródło. Działa nawet na dużych zbiorach dokumentów, bo wyszukiwanie zawęża kontekst do tego, co istotne.
Chatbot, który zamiast sztywnego drzewka FAQ przeszukuje pełną bazę wiedzy i odpowiada na nietypowe pytania. Gdy zmienia się regulamin albo specyfikacja produktu, aktualizujesz dokument w bazie i odpowiedzi zmieniają się natychmiast, bez przepisywania scenariuszy rozmów. To samo działa po stronie wewnętrznej: asystent dla zespołu pierwszej linii, który podpowiada odpowiedzi na podstawie aktualnych procedur.
Polityki kadrowe, procedury bezpieczeństwa, ustalenia z projektów, notatki ze spotkań. Ta wiedza zwykle jest rozsiana po dokumentach, których nikt nie pamięta. Asystent zbudowany na RAG pełni rolę firmowej pamięci: nowy pracownik pyta o procedurę urlopową, a doświadczony o szczegóły decyzji architektonicznej sprzed roku. W obu przypadkach kluczowa jest kontrola dostępu, do której wrócimy przy pułapkach produkcyjnych.
Wdrożenie da się rozłożyć na sześć etapów. Pierwsze cztery dotyczą przygotowania danych i wykonujesz je raz (a potem cyklicznie odświeżasz), dwa ostatnie dzieją się przy każdym pytaniu.
Najbardziej niedoceniany etap i jednocześnie ten, który najmocniej decyduje o jakości. RAG nie naprawi bałaganu w danych. Jeśli dokumenty są sprzeczne, nieaktualne albo zeskanowane jako obrazki bez warstwy tekstowej, asystent będzie odpowiadał równie chaotycznie. Zanim cokolwiek zaindeksujesz: ustal, które źródła są wiarygodne, usuń duplikaty i wersje archiwalne, a z plików PDF wyciągnij czysty tekst (skany wymagają rozpoznawania tekstu, czyli OCR). To etap nudny, ale zwrot z włożonej tu pracy jest najwyższy.
Model dostaje nie całe dokumenty, lecz ich fragmenty. Dzielenie tekstu (chunking) wydaje się trywialne, a jest jedną z głównych dźwigni jakości. Fragment za krótki gubi kontekst, za długi rozmywa trafność i podnosi koszty. Dobry podział respektuje strukturę dokumentu (akapity, nagłówki, sekcje) zamiast ciąć tekst w połowie zdania. Zwykle stosuje się też zakładkę (overlap), czyli powtórzenie końcówki poprzedniego fragmentu na początku kolejnego, żeby nie urwać myśli na granicy.
from langchain.text_splitter import RecursiveCharacterTextSplitter
# Dzielimy z poszanowaniem struktury: najpierw po akapitach,
# potem po zdaniach. chunk_overlap zachowuje ciaglosc na granicy.
splitter = RecursiveCharacterTextSplitter(
chunk_size=800, # ~ jeden, dwa akapity
chunk_overlap=120, # zakladka, by nie urwac mysli
separators=["\n\n", "\n", ". ", " "],
)
fragmenty = splitter.split_documents(dokumenty)
print(f"Podzielono na {len(fragmenty)} fragmentow")
Każdy fragment zamieniasz na osadzenie (embedding), czyli wektor liczb, który reprezentuje znaczenie tekstu. Dwa fragmenty o podobnym sensie mają zbliżone wektory, nawet jeśli używają innych słów. To dzięki temu zapytanie o zwroty produktu trafia we fragment mówiący o reklamacjach. Model osadzający wybierasz raz i konsekwentnie używasz tego samego do dokumentów i do pytań, inaczej porównania nie mają sensu.
Osadzenia trafiają do bazy wektorowej (vector store), która potrafi błyskawicznie znaleźć wektory najbliższe wektorowi pytania. Wybór bazy to decyzja, do której wrócimy: od lekkich rozwiązań do prototypu, po skalowalne bazy i rozszerzenia istniejących baz relacyjnych. Na tym etapie kończy się indeksowanie: dokumenty są pocięte, osadzone i gotowe do przeszukiwania.
Tu zaczyna się obsługa pytania. Wyszukiwacz (retriever) zamienia pytanie na osadzenie i pobiera z bazy kilka najbardziej zbliżonych fragmentów (parametr zwany top-k). To serce jakości całego systemu: jeśli wyszukiwacz poda nietrafne fragmenty, najlepszy model i tak odpowie kiepsko, bo dostał zły materiał. Dlatego wokół tego etapu narosło najwięcej technik poprawy: filtrowanie po metadanych, ponowne sortowanie wyników (re-ranking) czy łączenie wyszukiwania znaczeniowego ze zwykłym wyszukiwaniem słów kluczowych.
Pobrane fragmenty trafiają do polecenia obok pytania, a model formułuje odpowiedź. Kluczowa jest instrukcja systemowa: każ modelowi odpowiadać wyłącznie na podstawie dostarczonego kontekstu i wprost przyznawać, gdy odpowiedzi w nim nie ma. To prosta zmiana, która znacząco ogranicza zmyślanie. Poniżej szkielet całego przepływu w LangChain, który spina etapy od ładowania dokumentów po odpowiedź.
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Chroma
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
# --- ETAPY 1-4: indeksowanie (wykonywane raz / cyklicznie) ---
dokumenty = PyPDFLoader("procedury_firmowe.pdf").load()
splitter = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=120)
fragmenty = splitter.split_documents(dokumenty)
embeddingi = OpenAIEmbeddings(model="text-embedding-3-small")
baza = Chroma.from_documents(fragmenty, embeddingi, persist_directory="./baza")
# --- ETAPY 5-6: wyszukanie + generowanie (przy kazdym pytaniu) ---
szablon = PromptTemplate.from_template(
"Odpowiadaj WYLACZNIE na podstawie kontekstu ponizej. "
"Jesli nie ma w nim odpowiedzi, napisz: 'Nie wiem na podstawie dokumentow'.\n\n"
"Kontekst:\n{context}\n\nPytanie: {question}\nOdpowiedz:"
)
qa = RetrievalQA.from_chain_type(
llm=ChatOpenAI(model="gpt-4o-mini", temperature=0),
retriever=baza.as_retriever(search_kwargs={"k": 4}),
chain_type_kwargs={"prompt": szablon},
return_source_documents=True,
)
wynik = qa.invoke({"query": "Jak wyglada procedura zwrotu sprzetu?"})
print(wynik["result"])
for zrodlo in wynik["source_documents"]:
print("Zrodlo:", zrodlo.metadata.get("source"))
Większość różnicy między RAG, który robi wrażenie na demie, a takim, który działa na produkcji, kryje się w kilku decyzjach. Nie ma tu uniwersalnie dobrych odpowiedzi, każda zależy od skali, danych i wymagań firmy.
Mniejsze fragmenty to precyzyjniejsze trafienia, ale ryzyko utraty kontekstu. Większe odwrotnie. Liczba pobieranych fragmentów (top-k) to z kolei kompromis między kompletnością a kosztem i szumem: więcej fragmentów to większa szansa, że trafna informacja się znajdzie, ale też dłuższe polecenie, wyższy koszt i ryzyko, że model zgubi się w nadmiarze. Te dwa parametry dobiera się empirycznie, mierząc jakość, nie zgadując.
To decyzja o prywatności i skali jednocześnie. Rozwiązanie open source na własnym serwerze daje pełną kontrolę nad danymi, co bywa wymogiem przy wrażliwych dokumentach. Usługa zarządzana w chmurze upraszcza utrzymanie i lepiej skaluje. Jeśli firma już używa bazy relacyjnej, rozszerzenie dodające obsługę wektorów pozwala trzymać wszystko w jednym miejscu. Wybór warto powiązać z polityką bezpieczeństwa, a nie wyłącznie z wygodą.
Modele osadzające różnią się jakością, kosztem i tym, czy działają lokalnie czy przez usługę zewnętrzną. Po stronie generowania częstym i opłacalnym wzorcem jest podejście mieszane: tańszy, szybszy model do prostych pytań i mocniejszy do złożonych. Ważne, by raz wybrany model osadzający stosować konsekwentnie. Jego zmiana wymaga ponownego osadzenia całej bazy.
| Decyzja | Opcja lekka | Opcja produkcyjna | Co ważysz |
|---|---|---|---|
| Baza wektorowa | Lokalna, open source (prototyp) | Skalowalna baza lub rozszerzenie bazy relacyjnej | Prywatność, skala, koszt utrzymania |
| Wielkość fragmentu | Krótki, precyzyjny | Dobrany do typu dokumentu i mierzony | Trafność kontra koszt i kompletność |
| Model generujący | Jeden, tańszy | Mieszany: tani plus mocny wg trudności | Koszt na zapytanie kontra jakość |
| Wyszukiwanie | Czyste znaczeniowe | Plus filtry, re-ranking, słowa kluczowe | Złożoność kontra precyzja |
Prototyp RAG działa zaskakująco szybko. Problemy zaczynają się dopiero, gdy system styka się z prawdziwymi danymi, prawdziwymi użytkownikami i prawdziwym rachunkiem. Oto pułapki, które najczęściej wywracają wdrożenia.
Aktualizacja bazy wiedzy. Dokumenty żyją: zmieniają się regulaminy, powstają nowe instrukcje, stare tracą ważność. Jeśli baza wektorowa nie odświeża się automatycznie, asystent po kilku tygodniach zaczyna odpowiadać na podstawie nieaktualnych treści, brzmiąc przy tym równie pewnie. Potrzebujesz procesu odświeżania (cyklicznego lub wyzwalanego zmianą dokumentu) oraz usuwania fragmentów, które zniknęły ze źródła.
Halucynacje mimo RAG. RAG ogranicza zmyślanie, ale go nie eliminuje. Gdy wyszukiwacz poda słabo dopasowane fragmenty albo odpowiedzi po prostu nie ma w bazie, model potrafi wymyślić wiarygodnie brzmiącą nieprawdę. Obrona to instrukcja, by odpowiadał wyłącznie na podstawie kontekstu i przyznawał niewiedzę, pokazywanie źródeł, by człowiek mógł zweryfikować, oraz nieustanna praca nad jakością wyszukiwania.
Koszty. Na demie nie widać rachunku. W produkcji każde pytanie to wywołanie modelu, a koszt rośnie z liczbą i długością pobieranych fragmentów. Najwięcej oszczędzisz, ograniczając top-k do niezbędnego minimum, kierując proste pytania do tańszego modelu i, gdzie to możliwe, buforując odpowiedzi na powtarzalne pytania.
Prywatność i kontrola dostępu. Najpoważniejsza pułapka biznesowa. Jeśli każdy fragment jest dostępny dla każdego pytającego, asystent z radością wyjawi dane kadrowe albo poufne ustalenia osobie, która nie powinna ich widzieć. Uprawnienia muszą działać na poziomie wyszukiwania (filtrowanie fragmentów po roli czy dziale), a nie dopiero w odpowiedzi. Do tego dochodzi pytanie, gdzie trafiają dane wysyłane do modelu zewnętrznego, co przy wrażliwych dokumentach przesądza o wyborze rozwiązania lokalnego.
Bez pomiaru wdrożenie zamienia się w zgadywanie. Najgorsze, co możesz zrobić, to oceniać system na zasadzie wydaje się, że działa. Jakość RAG mierzy się na dwóch poziomach, bo dwa różne elementy mogą zawieść.
Po pierwsze, jakość wyszukiwania: czy wśród pobranych fragmentów w ogóle znalazł się ten właściwy? Do tego buduje się zestaw testowy, czyli reprezentatywne pytania ze wskazanymi poprawnymi fragmentami, i sprawdza, jak często trafny fragment ląduje w pobranych wynikach. Jeśli tu jest słabo, nie ma sensu poprawiać modelu generującego, bo problem leży wcześniej.
Po drugie, jakość odpowiedzi: czy odpowiedź faktycznie wynika z kontekstu (a nie z fantazji modelu) i czy odnosi się do pytania. Te wymiary ocenia się ręcznie na próbce albo automatycznie, używając mocniejszego modelu jako sędziego, który porównuje odpowiedź z dostarczonym kontekstem. Poniżej szkielet prostej pętli ewaluacyjnej liczącej, jak często trafny fragment znajduje się w wynikach wyszukiwania.
# Prosty pomiar trafnosci wyszukiwania na zestawie testowym.
# Kazdy przypadek: pytanie + fraza, ktora MUSI sie pojawic we fragmentach.
przypadki = [
{"pytanie": "Ile dni mam na zwrot sprzetu?", "oczekiwane": "14 dni"},
{"pytanie": "Kto zatwierdza urlop?", "oczekiwane": "przelozony"},
]
trafienia = 0
for p in przypadki:
fragmenty = baza.similarity_search(p["pytanie"], k=4)
tekst = " ".join(f.page_content.lower() for f in fragmenty)
if p["oczekiwane"].lower() in tekst:
trafienia += 1
print(f"Trafnosc wyszukiwania: {trafienia}/{len(przypadki)}")
Taki zestaw testowy rozbudowujesz w czasie. Każde realne pytanie, na które asystent odpowiedział źle, dopisujesz jako nowy przypadek. Dzięki temu każda zmiana (inny podział fragmentów, inny model, inne top-k) jest mierzalna, a nie oceniana na wyczucie.
Najbardziej dojrzała decyzja w całym temacie to czasem decyzja, by RAG nie budować. Trzy ścieżki, czyli lepsze polecenie, RAG i dostrajanie modelu, rozwiązują różne problemy.
Czasem wystarczy lepsze polecenie (prompt). Jeśli cała potrzebna wiedza mieści się w jednym czy kilku krótkich dokumentach, nie buduj infrastruktury wektorowej. Wklej te treści wprost do polecenia i poproś model o odpowiedź na ich podstawie. RAG ma sens dopiero, gdy dokumentów jest dużo, zmieniają się i nie da się ich zmieścić naraz w jednym zapytaniu.
Czasem potrzeba dostrajania modelu (fine-tuningu). RAG dokłada wiedzę, ale nie zmienia natury modelu. Jeśli problemem nie jest brak informacji, lecz styl, format czy specyficzny żargon odpowiedzi, tu pomaga dostrajanie, czyli dotrenowanie modelu na przykładach. W praktyce oba podejścia bywają łączone: dostrajanie ustawia sposób odpowiadania, a RAG dostarcza aktualną wiedzę.
| Podejście | Co rozwiązuje | Kiedy wybrać | Koszt i złożoność |
|---|---|---|---|
| Lepsze polecenie | Mało wiedzy, mieści się w zapytaniu | Kilka krótkich, stabilnych dokumentów | Najniższy |
| RAG | Dużo wiedzy, zmienna w czasie | Setki i więcej dokumentów, częste zmiany | Średni |
| Dostrajanie modelu | Styl, format, zachowanie modelu | Potrzeba spójnego tonu lub struktury, nie wiedzy | Najwyższy |
RAG to dziś najbardziej praktyczny sposób, by AI zaczęło mówić językiem Twojej firmy i opierać się na jej dokumentach. Prototyp powstaje szybko, ale wartość tkwi w szczegółach: w jakości danych, w przemyślanym podziale na fragmenty, w wyszukiwaniu, które trafia, w procesie aktualizacji, w kontroli dostępu i w pomiarze, który zamienia wrażenie na liczby. Zacznij od jednego, dobrze ograniczonego zastosowania, na przykład asystenta po dokumentacji jednego zespołu, zmierz jakość, dopiero potem skaluj. I za każdym razem zadaj sobie szczere pytanie: czy ten problem na pewno wymaga RAG, czy wystarczy lepsze polecenie albo dostrajanie modelu. Trafny wybór narzędzia to połowa sukcesu wdrożenia.
Komentarze (0)
Brak komentarzy...