✨ Świeża dostawa•nowe kody na kinetyka.pl: Gemini Pro 18 mies. 170 zł•Cursor, ElevenLabs, Lovable i więcej, roczne plany AI w ułamku ceny Zobacz →
Przejdź do treści
Artykuły

RAG krok po kroku: czat z własnymi dokumentami w Pythonie

Czat z PDF-ami od zera: podział na artykuły, embeddingi lokalnie, wyszukiwanie i odpowiedzi z cytatami. Test na Kodeksie pracy i dwóch innych ustawach.

14 min czytania
Logo Ollamy - RAG krok po kroku, czat z polskimi ustawami

👁 115 przeczytań

// w skrócie
  • RAG zbudowany w ok. 70 liniach Pythona poprawnie odpowiedział na 8 z 10 pytań, które miały odpowiedź w dokumentach, i ani razu nie zmyślił.
  • System podzielił trzy ustawy (łącznie 149 stron) na 920 kawałków po maks. 1200 znaków, a embeddingi liczył lokalnie modelem bge-m3 w Ollama 0.35.1.
  • Koszt 11 odpowiedzi przez model openai/gpt-5.6-luna na OpenRouter wyniósł łącznie 0,0072 USD, a lokalne embeddingi były bezpłatne.

RAG (retrieval-augmented generation) to czat z własnymi dokumentami: program najpierw wyszukuje w nich fragmenty pasujące do pytania, a dopiero potem model odpowiada na ich podstawie i podaje źródło. Zbudowałem to od zera w około 70 liniach Pythona: trzy polskie ustawy w PDF, embeddingi liczone lokalnie w Ollamie, baza wektorowa w numpy (i dla porównania w Chroma). Na 11 pytaniach zadanych potocznym językiem model odpowiedział dobrze w 8 przypadkach, w 2 uczciwie przyznał, że nie znalazł odpowiedzi, i ani razu nie zmyślił. Poniżej cały kod, wszystkie wyniki i dwie poprawki, które sprawdziłem. Tekst jest częścią ścieżki Agenci AI od zera.

Stan na 4 października 2026

  • Dokumenty: Kodeks pracy (tekst jednolity Dz.U. 2026 poz. 1245, 97 stron), ustawa o ochronie praw lokatorów (Dz.U. 2023 poz. 725, 23 strony), ustawa o prawach pacjenta (Dz.U. 2024 poz. 581, 29 stron). Pobrane z api.sejm.gov.pl.
  • Embeddingi: bge-m3 w Ollamie 0.35.1 na RTX 4090. Model odpowiadający: openai/gpt-5.6-luna przez OpenRouter.
  • Indeks: 920 kawałków po maks. 1200 znaków. Koszt 11 odpowiedzi: 0,0072 USD łącznie. Embeddingi lokalnie: 0 zł.
  • Kod: paczka promptowy-agenci-starter, pliki 04_rag.py i 04b_rag_chroma.py.

Jak działa RAG w czterech krokach

  1. Podział: dokumenty tniesz na kawałki (u mnie: jeden artykuł ustawy, długie artykuły na części z zakładką).
  2. Embeddingi: każdy kawałek zamieniasz na wektor liczb, który oddaje jego znaczenie. Robisz to raz.
  3. Wyszukiwanie: pytanie też zamieniasz na wektor i szukasz kawałków o najbliższych wektorach.
  4. Odpowiedź: 5 najlepszych kawałków doklejasz do polecenia i każesz modelowi odpowiadać tylko na ich podstawie, ze wskazaniem źródła.

Czym są embeddingi i bazy wektorowe, tłumaczę bez kodu w tekście Embeddingi i bazy wektorowe po ludzku. Teoretyczne wprowadzenie do RAG i jego słabych punktów jest w starszym tekście RAG: jak działa.

Krok 1: przygotowanie

  1. Zainstaluj Ollamę i pobierz model embeddingów: ollama pull bge-m3 (1,2 GB na dysku, w pamięci karty u mnie 664 MB).
  2. W środowisku Pythona: pip install numpy pypdf requests openai python-dotenv.
  3. Wrzuć PDF-y do folderu dane/ustawy. Teksty ustaw nie są chronione prawem autorskim (art. 4 ustawy o prawie autorskim), więc możesz ich swobodnie użyć do testów.

Embeddingi możesz też liczyć przez API (OpenAI, Google, Mistral), ale lokalnie nie płacisz nic, a dokumenty nie opuszczają komputera. Bez karty graficznej Ollama policzy je na procesorze, tylko wolniej.

Krok 2: cały kod

"""04 - RAG krok po kroku: czat z własnymi dokumentami (PDF), embeddingi lokalnie w Ollamie, baza = numpy.
Krok 1 (raz):   python 04_rag.py indeksuj dane/ustawy
Krok 2 (pytaj): python 04_rag.py pytaj "Ile dni urlopu ma pracownik po 12 latach pracy?"
Wymaga: Ollama z modelem embeddingów (ollama pull bge-m3) i klucza OpenRouter do odpowiedzi.
"""
import json, os, pathlib, re, sys
import numpy as np
import requests
from dotenv import load_dotenv
from openai import OpenAI
from pypdf import PdfReader

load_dotenv()
EMBED = os.getenv("EMBED_MODEL", "bge-m3")          # albo nomic-embed-text
MODEL = os.getenv("MODEL", "openai/gpt-5.6-luna")
INDEKS = pathlib.Path(f"indeks-{EMBED.replace(':', '_')}.npz")
OLLAMA = os.getenv("OLLAMA_URL", "http://localhost:11434")

# --- 1. Tekst z PDF i podział na kawałki (tu: po artykułach ustawy) ------------
def kawalki(plik: pathlib.Path, max_zn=1200):
    tekst = "\n".join(p.extract_text() or "" for p in PdfReader(plik).pages)
    tekst = re.sub(r"Dziennik Ustaw\s*\W\s*\d+\s*\W\s*Poz\. \d+", " ", tekst)    # stopki stron
    czesci = re.split(r"\s(?=Art\. \d+[a-z]?(?:\[\d+\])?\. )", tekst)              # nowy artykuł = nowy kawałek
    for cz in czesci:
        cz = re.sub(r"\s+", " ", cz).strip()
        art = (re.match(r"Art\. (\d+[a-z]?(?:\[\d+\])?)\.", cz) or [None, "wstęp"])[1]
        for i in range(0, len(cz), max_zn - 200):    # długie artykuły tniemy z zakładką 200 znaków
            yield {"plik": plik.name, "art": art, "tekst": cz[i:i + max_zn]}
            if i + max_zn >= len(cz): break

# --- 2. Embeddingi: tekst -> wektor liczb (lokalnie, przez Ollamę) -------------
def embed(teksty, prefiks=""):
    wektory = []
    for i in range(0, len(teksty), 32):
        r = requests.post(f"{OLLAMA}/api/embed", json={"model": EMBED, "input": [prefiks + t for t in teksty[i:i + 32]]}, timeout=600)
        wektory += r.json()["embeddings"]
    v = np.array(wektory, dtype=np.float32)
    return v / np.linalg.norm(v, axis=1, keepdims=True)   # normalizacja: iloczyn skalarny = podobieństwo cosinusowe

PREF_DOK, PREF_PYT = ("search_document: ", "search_query: ") if "nomic" in EMBED else ("", "")

def indeksuj(katalog):
    k = [x for p in sorted(pathlib.Path(katalog).glob("*.pdf")) for x in kawalki(p)]
    v = embed([x["tekst"] for x in k], PREF_DOK)
    np.savez(INDEKS, wektory=v, meta=np.array([json.dumps(x, ensure_ascii=False) for x in k]))
    print(f"zapisano {len(k)} kawałków, wektory {v.shape[1]}-wymiarowe -> {INDEKS}")

# --- 3. Wyszukiwanie: pytanie -> wektor -> najbliższe kawałki -------------------
def szukaj(pytanie, k=5):
    d = np.load(INDEKS)
    podob = d["wektory"] @ embed([pytanie], PREF_PYT)[0]
    top = np.argsort(-podob)[:k]
    return [{**json.loads(d["meta"][i]), "podobienstwo": round(float(podob[i]), 3)} for i in top]

# --- 4. Odpowiedź modelu tylko na podstawie znalezionych fragmentów -------------
def pytaj(pytanie):
    fragmenty = szukaj(pytanie)
    kontekst = "\n\n".join(f"[{f['plik']}, art. {f['art']}]\n{f['tekst']}" for f in fragmenty)
    client = OpenAI(base_url="https://openrouter.ai/api/v1", api_key=os.environ["OPENROUTER_API_KEY"])
    r = client.chat.completions.create(model=MODEL, messages=[
        {"role": "system", "content": "Odpowiadasz wyłącznie na podstawie fragmentów ustaw podanych niżej. Na końcu podaj "
         "źródło w nawiasie: [plik, art.]. Jeśli we fragmentach nie ma odpowiedzi, napisz: Nie ma tego w dokumentach."},
        {"role": "user", "content": f"FRAGMENTY:\n{kontekst}\n\nPYTANIE: {pytanie}"}])
    for f in fragmenty:
        print(f"  znaleziono: {f['plik']} art. {f['art']} (podobieństwo {f['podobienstwo']})")
    print(f"\nODPOWIEDŹ: {r.choices[0].message.content}\n(koszt: {getattr(r.usage, 'cost', 0) or 0:.5f} USD)")

if __name__ == "__main__":
    {"indeksuj": indeksuj, "pytaj": pytaj}[sys.argv[1]](sys.argv[2])

Najważniejsze decyzje w tym kodzie:

  • Podział po artykułach. Wyrażenie regularne szuka „Art. 154.” albo „Art. 167[2].” (tak pypdf zapisuje indeksy górne z Dziennika Ustaw). Jeden artykuł to zwykle jedna myśl prawna, więc to lepszy podział niż cięcie co 1000 znaków w połowie zdania.
  • Usunięcie stopek „Dziennik Ustaw - 23 - Poz. 1245”, które inaczej trafiają w środek artykułów.
  • Normalizacja wektorów: po niej zwykłe mnożenie macierzy daje podobieństwo cosinusowe. Całe „wyszukiwanie wektorowe” to tu jedna linijka: d["wektory"] @ embed([pytanie])[0].
  • Polecenie systemowe z wyjściem awaryjnym: „Jeśli we fragmentach nie ma odpowiedzi, napisz: Nie ma tego w dokumentach”. To ono sprawiło, że w moim teście model nie zmyślał.

Krok 3: indeksowanie

Polecenie python 04_rag.py indeksuj dane/ustawy pocięło 149 stron na 920 kawałków i zapisało wektory (1024 liczby na kawałek) do pliku indeks-bge-m3.npz. Trwało to 155 sekund, ale karta była w tym czasie mocno obciążona przez inny program, więc na wolnej karcie będzie szybciej. Robisz to raz, a potem tylko pytasz.

Krok 4: pytania i odpowiedzi

Zadałem 11 pytań językiem, jakim pyta zwykły człowiek, a nie prawnik. Dziesięć ma odpowiedź w ustawach, jedno (o prędkości na autostradzie) celowo nie.

PytanieWłaściwy artykułGdzie w wynikach wyszukiwaniaOdpowiedź modeluOcena
Pracuję od 12 lat. Ile dni urlopu mi przysługuje?KP art. 154poza top 5 (14. miejsce)„Nie ma tego w dokumentach”bezpieczna porażka
Jaki mam okres wypowiedzenia, jeśli jestem w firmie 4 lata?KP art. 361.3 miesiącedobrze
Ile dni urlopu na żądanie mogę wziąć w roku?KP art. 167[2]1.4 dni w roku kalendarzowymdobrze
Szef każe mi zostać po godzinach w nocy. Ile wynosi dodatek?KP art. 151[1]2.100% wynagrodzenia plus dodatek nocny 20%dobrze
Ile maksymalnie może wynosić kaucja za mieszkanie na wynajem?art. 62.do 12-krotności czynszu, przy najmie instytucjonalnym do 6-krotnościdobrze, ale pominął najem okazjonalny
Kiedy właściciel musi mi oddać kaucję po wyprowadzce?art. 64.w ciągu miesiąca od opróżnienia lokaludobrze
Czy właściciel może mnie wyrzucić, jak nie płacę czynszu 3 miesiące?art. 111.tak, po pisemnym uprzedzeniu i dodatkowym miesięcznym terminiedobrze
Ile kosztuje kopia mojej dokumentacji medycznej?art. 281.pierwsza kopia bezpłatnie, kolejne do 0,00007 przeciętnego wynagrodzenia za stronędobrze
Nie zgadzam się z orzeczeniem lekarza. Gdzie i do kiedy mogę się odwołać?art. 311.sprzeciw do Komisji Lekarskiej przy RPP, 30 dnidobrze
Czy mama może być ze mną w gabinecie podczas badania?art. 21poza top 5 (31. miejsce)„Nie ma tego w dokumentach”bezpieczna porażka
Jaka jest dozwolona prędkość na autostradzie?brak w dokumentachnajwyższe podobieństwo tylko 0,43„Nie ma tego w dokumentach”dobrze

Wynik: 8 dobrych odpowiedzi na 10 pytań, które mają odpowiedź w dokumentach, plus poprawna odmowa przy pytaniu spoza tematu. Obie porażki wzięły się z wyszukiwania, nie z modelu. Model dostał złe fragmenty i powiedział wprost, że w nich odpowiedzi nie ma. Tak ma działać dobrze ustawiony RAG.

Tak wygląda pełny przebieg dla pytania o nadgodziny:

> python 04_rag.py pytaj "Szef każe mi zostać po godzinach w nocy. Ile wynosi dodatek?"
  znaleziono: kodeks-pracy-DU-2026-1245.pdf art. 151[8] (podobieństwo 0.682)
  znaleziono: kodeks-pracy-DU-2026-1245.pdf art. 151[1] (podobieństwo 0.663)
  znaleziono: kodeks-pracy-DU-2026-1245.pdf art. 151[6] (podobieństwo 0.644)
  znaleziono: kodeks-pracy-DU-2026-1245.pdf art. 151[7] (podobieństwo 0.621)
  znaleziono: kodeks-pracy-DU-2026-1245.pdf art. 151[4] (podobieństwo 0.616)

ODPOWIEDŹ: Za każdą godzinę nadliczbową przypadającą w nocy przysługuje dodatek w wysokości **100% wynagrodzenia**. Ponadto za każdą godzinę pracy w porze nocnej przysługuje dodatek nocny w wysokości **20% stawki godzinowej wynikającej z minimalnego wynagrodzenia za pracę**. Pora nocna obejmuje 8 godzin między 21:00 a 7:00. [kodeks-pracy-DU-2026-1245.pdf, art. 151[1] § 1 pkt 1 lit. a, art. 151[8] § 1, art. 151[7] § 1]
(koszt: 0.00084 USD)

Model połączył trzy fragmenty (dodatek za nadgodziny, dodatek nocny, definicję pory nocnej) i przy każdym podał przepis. A tak wygląda porażka wyszukiwania:

> python 04_rag.py pytaj "Pracuję od 12 lat. Ile dni urlopu mi przysługuje?"
  znaleziono: kodeks-pracy-DU-2026-1245.pdf art. 167[3] (podobieństwo 0.693)
  znaleziono: kodeks-pracy-DU-2026-1245.pdf art. 167[2] (podobieństwo 0.685)
  znaleziono: kodeks-pracy-DU-2026-1245.pdf art. 186 (podobieństwo 0.669)
  znaleziono: kodeks-pracy-DU-2026-1245.pdf art. 182[3] (podobieństwo 0.664)
  znaleziono: kodeks-pracy-DU-2026-1245.pdf art. 172 (podobieństwo 0.66)

ODPOWIEDŹ: Nie ma tego w dokumentach. Z podanych fragmentów wynika jedynie, że urlop na żądanie może wynosić maksymalnie 4 dni w roku kalendarzowym; nie określono natomiast pełnego wymiaru urlopu wypoczynkowego dla osoby pracującej 12 lat. [kodeks-pracy-DU-2026-1245.pdf, art. 167[2]-167[3]]
(koszt: 0.00063 USD)

Wyszukiwarka znalazła przepisy o urlopie na żądanie i urlopie rodzicielskim, bo pytanie „ile dni urlopu” jest do nich bardzo podobne. Artykuł 154 zaczyna się od słów „Wymiar urlopu wynosi: 20 dni… 26 dni”, czyli innym słownictwem niż pytanie.

Poprawka 1: przepisanie pytania na język ustawy

Nie przepłacaj za te subskrypcje

Prowadzę sklep z rocznymi dostępami do narzędzi AI - te same konta, o których piszę wyżej, tylko taniej niż w cenniku producenta.

Zobacz, co jest dostępne

Popularna technika (query rewriting) polega na tym, że przed wyszukiwaniem model przepisuje pytanie na język dokumentów. Sprawdziłem ją na 10 pytaniach:

Pytanie potocznePo przepisaniuMiejsce przedMiejsce po
Pracuję od 12 lat. Ile dni urlopu mi przysługuje?Jaki wymiar urlopu wypoczynkowego przysługuje pracownikowi legitymującemu się 12-letnim okresem zatrudnienia?14.5.
Szef każe mi zostać po godzinach w nocy. Ile wynosi dodatek?W jakiej wysokości przysługuje pracownikowi dodatek do wynagrodzenia z tytułu pracy w godzinach nadliczbowych przypadających w porze nocnej…2.1.
Ile dni urlopu na żądanie mogę wziąć w roku?Jaki jest maksymalny wymiar urlopu wypoczynkowego udzielanego na żądanie pracownika w roku kalendarzowym?1.2.
Czy mama może być ze mną w gabinecie podczas badania?Czy matka pacjenta jest uprawniona do obecności w pomieszczeniu, w którym przeprowadzane jest badanie?31.44.

Pozostałe 6 pytań nie zmieniło pozycji. W sumie: właściwy artykuł w pierwszej piątce w 9 przypadkach na 10 (wcześniej 8). Pytanie o mamę pokazuje granicę tej metody: ustawa mówi o „osobie bliskiej”, a ani pytanie, ani jego przepisana wersja tego słowa nie mają. Tu pomogłoby wyszukiwanie hybrydowe (słowa kluczowe plus wektory) albo słownik synonimów. Przepisanie kosztowało 0,0017 USD za 10 pytań i dodaje około sekundy do każdej odpowiedzi.

Poprawka 2: próg podobieństwa

Przy pytaniu o autostradę najlepszy kawałek miał podobieństwo 0,43, a przy pytaniach z odpowiedzią w dokumentach 0,64-0,72. To naturalny próg: jeśli najlepszy wynik jest poniżej około 0,5, program może od razu odpowiedzieć „nie mam tego w dokumentach”, bez pytania modelu. Próg trzeba dobrać do swojego modelu embeddingów i dokumentów. Dla nomic-embed-text na tych samych ustawach wszystkie wyniki, także bezsensowne, mieściły się między 0,69 a 0,77, więc taki próg nie miałby sensu.

To samo w bazie Chroma

Numpy wystarcza do kilkudziesięciu tysięcy kawałków. Przy większej liczbie albo gdy chcesz filtrować po metadanych (np. „szukaj tylko w Kodeksie pracy”), wygodniejsza jest baza wektorowa. Ten sam RAG na Chroma 1.5.9:

"""04b - Ten sam RAG, ale z bazą wektorową Chroma zamiast numpy (zapis na dysku, filtrowanie po metadanych).
python 04b_rag_chroma.py indeksuj dane/ustawy
python 04b_rag_chroma.py szukaj "Ile maksymalnie może wynosić kaucja?" [plik.pdf]
"""
import importlib, pathlib, sys
import chromadb

rag = importlib.import_module("04_rag")          # bierzemy podział na kawałki i embeddingi z 04_rag.py
baza = chromadb.PersistentClient(path="chroma_db")
kolekcja = baza.get_or_create_collection(f"ustawy-{rag.EMBED.replace(':', '_')}", metadata={"hnsw:space": "cosine"})

def indeksuj(katalog):
    k = [x for p in sorted(pathlib.Path(katalog).glob("*.pdf")) for x in rag.kawalki(p)]
    v = rag.embed([x["tekst"] for x in k], rag.PREF_DOK)
    for i in range(0, len(k), 500):  # Chroma przyjmuje dane partiami
        kolekcja.upsert(ids=[f"{x['plik']}#{n}" for n, x in enumerate(k[i:i + 500], i)],
                        embeddings=v[i:i + 500].tolist(), documents=[x["tekst"] for x in k[i:i + 500]],
                        metadatas=[{"plik": x["plik"], "art": x["art"]} for x in k[i:i + 500]])
    print(f"w kolekcji {kolekcja.count()} kawałków")

def szukaj(pytanie, plik=None):
    w = kolekcja.query(query_embeddings=rag.embed([pytanie], rag.PREF_PYT).tolist(), n_results=3,
                       where={"plik": plik} if plik else None)   # filtr po metadanych: tylko jedna ustawa
    for meta, odl, tekst in zip(w["metadatas"][0], w["distances"][0], w["documents"][0]):
        print(f"{meta['plik']} art. {meta['art']} (podobieństwo {1 - odl:.3f}): {tekst[:110]}...")

if __name__ == "__main__":
    indeksuj(sys.argv[2]) if sys.argv[1] == "indeksuj" else szukaj(sys.argv[2], *sys.argv[3:4])
> python 04b_rag_chroma.py indeksuj dane/ustawy
w kolekcji 920 kawałków
(indeksowanie trwało 126 s)

> python 04b_rag_chroma.py szukaj "Ile maksymalnie może wynosić kaucja za mieszkanie na wynajem?"
ochrona-praw-lokatorow-DU-2023-725.pdf art. 19f (podobieństwo 0.673): emcę kaucji zabez- pieczającej pokrycie należności z tytułu najmu instytucjonalnego lokalu przysługujących wła...
ochrona-praw-lokatorow-DU-2023-725.pdf art. 6 (podobieństwo 0.639): Art. 6. 1. Zawarcie umowy najmu może być uzależnione od wpłacenia przez najemcę kaucji zabezpieczającej pokryc...
ochrona-praw-lokatorow-DU-2023-725.pdf art. 19k (podobieństwo 0.615): ści oświadczenie najemcy, w którym najemca poddał się egzekucji i zobowiązał się do opróżnienia i wy- dania lo...

> python 04b_rag_chroma.py szukaj "Czy mama może być ze mną w gabinecie podczas badania?" prawa-pacjenta-DU-2024-581.pdf
prawa-pacjenta-DU-2024-581.pdf art. 17 (podobieństwo 0.530): Art. 17. 1. Pacjent, w tym małoletni, który ukończył 16 lat, ma prawo do wyrażenia zgody na przeprowadzenie ba...
prawa-pacjenta-DU-2024-581.pdf art. 14 (podobieństwo 0.520): - jącej zawód medyczny. Osoba wykonująca zawód medyczny może wystąpić z wnioskiem do sądu także w przypadku uz...
prawa-pacjenta-DU-2024-581.pdf art. 18 (podobieństwo 0.518): Art. 18. 1. W przypadku zabiegu operacyjnego albo zastosowania metody leczenia lub diagnostyki stwarzających p...

Wyniki i podobieństwa są identyczne jak w numpy, bo to te same wektory. Baza wektorowa nie poprawia jakości wyszukiwania, tylko wygodę: zapis na dysku (u mnie 11 MB), dopisywanie nowych dokumentów bez przeliczania wszystkiego i filtry. Drugie zapytanie pokazuje filtr po pliku: nawet ograniczone do ustawy o prawach pacjenta wyszukiwanie nie trafiło w art. 21, co potwierdza, że problemem jest słownictwo, a nie mieszanie ustaw.

Co psuje RAG najczęściej

  • Zły podział tekstu. Kawałki ucięte w połowie zdania albo zbyt duże (cały rozdział) to najczęstsza przyczyna słabego wyszukiwania.
  • Model embeddingów, który słabo zna polski. Na moich ustawach bge-m3 znalazł właściwy artykuł w pierwszej piątce w 8 przypadkach na 10, a nomic-embed-text tylko w 4. Porównanie jest w tekście o embeddingach.
  • Różnica słownictwa między pytającym a dokumentem („mama” kontra „osoba bliska”).
  • Brak wyjścia awaryjnego w poleceniu. Bez zdania „jeśli nie ma, powiedz” model chętnie dopowiada z własnej wiedzy.
  • Nieaktualne dokumenty. RAG odpowiada na podstawie tego, co mu dasz. Tekst jednolity ustawy o ochronie praw lokatorów z 2023 roku nie uwzględnia późniejszych zmian.

Następny krok: RAG jako narzędzie agenta

Funkcję szukaj() możesz dać agentowi jako narzędzie. Wtedy agent sam decyduje, czy szukać, w której ustawie, i może zadać kilka wyszukiwań, zanim odpowie (to się nazywa agentic RAG). Jak podpiąć funkcję jako narzędzie, pokazuję w tekście Jak zbudować agenta AI w Pythonie, a jak wystawić ją wszystkim klientom AI naraz, w tekście Własny serwer MCP.

Najczęstsze pytania

Co to jest RAG w prostych słowach?

Ściąga dla modelu. Zanim model odpowie, program wyszukuje w Twoich dokumentach pasujące fragmenty i daje mu je do przeczytania. Model odpowiada na ich podstawie, a nie z pamięci.

RAG czy fine tuning?

Do odpowiadania na pytania z dokumentów prawie zawsze RAG: jest tańszy, aktualizujesz go wrzuceniem nowego pliku i widać źródło odpowiedzi. Fine tuning zmienia styl i zachowanie modelu, ale słabo nadaje się do wkuwania faktów.

Czy RAG działa po polsku?

Tak, jeśli model embeddingów zna polski. Mój test na polskich ustawach z bge-m3 dał 8 dobrych odpowiedzi na 10 pytań z odpowiedzią w dokumentach.

Czy mogę zrobić RAG całkiem lokalnie, bez internetu?

Tak. Embeddingi i tak liczyłem lokalnie, a zamiast modelu z OpenRoutera możesz użyć modelu z Ollamy (w kodzie zmieniasz adres i nazwę modelu). Przy słabszych modelach lokalnych odpowiedzi będą prostsze i częściej nieprecyzyjne.

Ile kosztuje RAG?

U mnie embeddingi nic (lokalnie), a 11 odpowiedzi 0,0072 USD, czyli około 0,00065 USD za pytanie. Największy koszt to tokeny wejściowe: 5 fragmentów po 1200 znaków przy każdym pytaniu.

Jaka baza wektorowa na start?

Do nauki numpy (zero instalacji). Do małego projektu Chroma albo SQLite z rozszerzeniem wektorowym. Do dużych zbiorów i wielu użytkowników: pgvector w PostgreSQL, Qdrant albo usługi chmurowe.

Google · Twoje źródłaPromptowy wyżej w Twoim Google - jednym kliknięciemDodaj do preferowanych źródeł →

Źródła i data sprawdzenia

// Newsletter

Cały tydzień w AI, w jednym mailu

Wybrane premiery, narzędzia i analizy. Raz w tygodniu, prosto do skrzynki.

Zapisz się za darmo →
Za darmo. Wypisujesz się jednym kliknięciem.
// czytaj też

Podobne tematy na Promptowym

Piotr Olszewski

Piotr Olszewski

AUTOR I WYDAWCA

Piotr Olszewski - twórca i autor Promptowego, polskiego serwisu o sztucznej inteligencji. Codziennie śledzi premiery modeli, narzędzia i regulacje AI, i tłumaczy je prostym, konkretnym językiem.

// mapa strony

🛒 Sklep Kinetyka Google AI Gemini Pro 170 zł CapCut Pro 460 zł/rok Lovable Pro 400 zł/rok Zobacz wszystko →
promptowy w liczbach 0tekstów w archiwum0newsów z ostatnich 7 dni0modeli wideo w obserwatorium0zagadek w grach
× ‹ powiększenie ›