Bazy wektorowe i RAG w Pythonie — jak to działa i jak to zbudować

Piotr Dul

02-10-2026

(aktualizacja: 02-10-2026)

RAG i bazy wektorowe pozwalają modelom AI odpowiadać na podstawie Twoich własnych danych. Wyjaśniamy, jak to działa, skąd biorą się błędy embeddingów i jak zbudować pierwszy pipeline w Pythonie z Qdrant.

Bazy wektorowe i RAG w Pythonie — jak to działa i jak to zbudować
RAG (Retrieval-Augmented Generation) to technika, która pozwala modelowi językowemu odpowiadać na podstawie Twoich własnych danych, zamiast tylko wiedzy, na której był trenowany — a baza wektorowa to miejsce, gdzie te dane przechowuje się jako punkty w przestrzeni liczbowej (embeddingi), żeby błyskawicznie znajdować te najbardziej podobne znaczeniowo do pytania użytkownika. W Pythonie typowy pipeline RAG łączy model embeddingowy, bazę wektorową (np. Qdrant) i model językowy, który na końcu generuje odpowiedź na podstawie znalezionych fragmentów.

Model językowy, nawet najlepszy, zna tylko to, na czym był trenowany — nie wie nic o Twojej dokumentacji wewnętrznej, bazie wiedzy firmy czy danych sprzed tygodnia. RAG to sposób, żeby to obejść bez kosztownego douczania modelu od zera: zamiast tego, przy każdym pytaniu, najpierw wyszukuje się najbardziej trafne fragmenty Twoich własnych danych, a dopiero potem prosi się model językowy o odpowiedź na ich podstawie.

Czym jest RAG i baza wektorowa?

RAG (Retrieval-Augmented Generation, czyli "generowanie wzbogacone o wyszukiwanie") to architektura łącząca dwa kroki: najpierw wyszukanie (retrieval) odpowiednich informacji, a potem wygenerowanie (generation) odpowiedzi przez model językowy na ich podstawie. Kluczowy jest ten pierwszy krok — żeby wyszukiwanie działało dobrze, potrzebny jest sposób na znalezienie fragmentów tekstu podobnych znaczeniowo do pytania, a nie tylko takich, które zawierają te same słowa.

Właśnie do tego służy baza wektorowa. Zamiast przechowywać tekst jako zwykłe zdania, zamienia go na wektory liczbowe (embeddingi) — a potem pozwala błyskawicznie znaleźć, które wektory leżą najbliżej siebie w przestrzeni. "Blisko" w tej przestrzeni oznacza "podobne znaczeniowo", nie "zawiera te same litery" — to fundamentalna różnica względem tradycyjnego wyszukiwania pełnotekstowego.

Typowy pipeline RAG w Pythonie wygląda tak:

# 1. Zamiana tekstu na wektor (embedding)
embedding = embedding_model.encode("Jak zresetować hasło?")

# 2. Wyszukanie najbardziej podobnych fragmentów w bazie wektorowej
results = vector_db.search(embedding, limit=5)

# 3. Przekazanie znalezionych fragmentów do modelu językowego
answer = llm.generate(question="Jak zresetować hasło?", context=results)

Matematyka przestrzeni latentnych — dlaczego to w ogóle działa

Embedding to po prostu lista liczb (np. 1536 liczb dla jednego z modeli OpenAI) reprezentująca znaczenie fragmentu tekstu. Model embeddingowy został wytrenowany tak, by fragmenty o podobnym znaczeniu trafiały w blisko siebie położone punkty tej wielowymiarowej przestrzeni — nazywanej przestrzenią latentną (ukrytą), bo te wymiary nie odpowiadają niczemu, co człowiek mógłby nazwać wprost (to nie jest "wymiar emocji" czy "wymiar tematu"), tylko wzorcom wyuczonym statystycznie z ogromnej ilości tekstu.

Żeby zmierzyć, jak blisko leżą dwa wektory, najczęściej liczy się podobieństwo kosinusowe — kąt między dwoma wektorami, a nie ich odległość w linii prostej. Dwa teksty o identycznym znaczeniu, ale różnej długości, mogą mieć bardzo różną "długość" wektora, ale niemal identyczny kierunek — dlatego to kąt, nie dystans, jest tu właściwą miarą podobieństwa.

To wyjaśnia też jeden z najczęstszych błędów, na jaki trafiają osoby budujące swój pierwszy system RAG: błąd niezgodności wymiarów (np. "embedding dimension 384 does not match collection dimensionality 1536"). Każdy model embeddingowy generuje wektory o ściśle określonej, stałej liczbie wymiarów — zmieszanie wektorów z dwóch różnych modeli (np. zaindeksowanie danych jednym modelem, a wyszukiwanie zapytania innym) jest matematycznie bez sensu, bo te liczby opisują zupełnie różne przestrzenie. To jeden z realnych, bardzo często zgłaszanych problemów przy pierwszym kontakcie z tematem — rozwiązanie jest proste (konsekwentnie używać tego samego modelu embeddingowego do indeksowania i wyszukiwania), ale dopóki nie rozumie się dlaczego wymiary muszą się zgadzać, błąd bywa mylący.

Indeksowanie w Qdrant

Qdrant to jedna z popularniejszych otwartoźródłowych baz wektorowych, z natywnym klientem Pythona. Podstawowy przykład indeksowania danych:

from qdrant_client import QdrantClient
from qdrant_client.models import VectorParams, Distance, PointStruct

client = QdrantClient(url="http://localhost:6333")

client.create_collection(
    collection_name="dokumenty",
    vectors_config=VectorParams(size=1536, distance=Distance.COSINE),
)

client.upsert(
    collection_name="dokumenty",
    points=[
        PointStruct(
            id=1,
            vector=embedding_model.encode("Jak zresetować hasło?"),
            payload={"tekst": "Jak zresetować hasło?", "zrodlo": "faq.md"},
        )
    ],
)

wyniki = client.search(
    collection_name="dokumenty",
    query_vector=embedding_model.encode("zapomniałem hasła"),
    limit=3,
)

Kolekcja (collection_name) to odpowiednik tabeli w bazie relacyjnej — grupuje wektory o tym samym rozmiarze i metryce podobieństwa (tu: Distance.COSINE, zgodnie z poprzednią sekcją). payload to zwykłe, ustrukturyzowane dane dołączone do każdego wektora (oryginalny tekst, źródło, metadane) — zwracane razem z wynikiem wyszukiwania, żeby wiedzieć, skąd faktycznie pochodzi dopasowany fragment.

Co dalej, gdy podstawy już działają

Powyższy pipeline wystarczy na pierwszy, działający system RAG — ale produkcyjne wdrożenia zwykle idą dalej w kilku kierunkach: **wyszukiwanie hybrydowe** (łączenie wyszukiwania wektorowego z klasycznym, słowo-kluczowym, bo czasem dokładne dopasowanie frazy jest ważniejsze niż podobieństwo znaczeniowe) razem z rerankingiem (dogrywaniem kolejności wyników drugim, dokładniejszym modelem po wstępnym wyszukiwaniu), staranny podział dłuższych, nieustrukturyzowanych dokumentów (PDF-y, strony HTML) na fragmenty, które niosą pełny sens bez urywania w połowie myśli, oraz kontrolę dostępu (RBAC) na poziomie samej bazy wektorowej, gdy różni użytkownicy systemu powinni mieć dostęp tylko do części zaindeksowanych danych. To tematy, które dokładniej omawiamy w ramach mentoringu z Pythona i AI — jeśli wdrażasz RAG komercyjnie, to naturalny kolejny krok po opanowaniu podstaw opisanych wyżej.

Konsultacja i warsztaty devmentor.pl

Masz pytania?