LlamaIndex w praktyce: dokumenty, indeks, zapytania

Wprowadzenie
W pierwszej części ustaliliśmy teorię: RAG to indeksowanie dokumentów pociętych na chunki z embeddingami oraz odpowiadanie na pytania z pomocą znalezionych fragmentów. Dziś przekładamy te pojęcia na konkretne klasy biblioteki LlamaIndex — omawiamy dokładnie te (i tylko te) elementy, z których w trzeciej części złożymy działające API.
Czym jest LlamaIndex?
LlamaIndex to biblioteka Pythona, która implementuje cały przepływ RAG: wczytywanie dokumentów, cięcie na chunki, liczenie embeddingów, budowę indeksu i odpytywanie z pomocą LLM. Bez niej każdy z tych kroków trzeba by napisać ręcznie; z nią — cały minimalny RAG mieści się w kilkunastu linijkach.
Instalacja w środowisku wirtualnym:
| |
Trzy pakiety, bo LlamaIndex jest modularny: rdzeń (core), integracja z modelem językowym przez OpenRouter i lokalny model embeddingów.
Document — dokument w rękach biblioteki
Podstawowa jednostka danych. Nasze API dostanie ścieżkę do pliku Markdown, więc wczytamy jego treść i opakujemy w Document:
| |
metadata to zwykły słownik — LlamaIndex przenosi go na chunki, dzięki czemu przy odpowiedzi wiadomo, z którego pliku pochodzi znaleziony fragment.
Settings — jaki model liczy embeddingi, jaki odpowiada
RAG używa dwóch różnych modeli i warto je świadomie rozdzielić:
- model embeddingów — zamienia tekst na wektory; u nas mały, darmowy model uruchamiany lokalnie,
- LLM — generuje odpowiedź na podstawie znalezionych fragmentów; u nas model wywoływany przez OpenRouter, czyli jedno API dające dostęp do wielu modeli różnych dostawców.
Globalna konfiguracja przez Settings:
| |
Zwróć uwagę na os.environ — klucz API nie pojawia się w kodzie ani w repozytorium. Przed uruchomieniem ustawiamy go w terminalu ($env:OPENROUTER_API_KEY = "..." w PowerShell).
VectorStoreIndex — indeks w pamięci
Serce całości. Przyjmuje listę dokumentów i robi wszystko, o czym była mowa w teorii — tnie na chunki, liczy embeddingi, zapisuje w indeksie:
| |
Domyślnie indeks żyje w pamięci — dokładnie tak, jak zaplanowaliśmy: zero konfiguracji baz danych, po restarcie indeksujemy od nowa. Kolejne dokumenty można dodawać do istniejącego indeksu:
| |
Query engine — zadajemy pytanie
Ostatni klocek zamienia indeks w kompletny mechanizm pytanie-odpowiedź:
| |
Jedno wywołanie query() wykonuje cały przepływ z części pierwszej: embedding pytania → znalezienie similarity_top_k=3 najbliższych chunków → wysłanie ich z pytaniem do LLM → zwrócenie odpowiedzi. W source_nodes dostajemy użyte fragmenty — dzięki metadanym widać, z którego pliku pochodzą.
Podsumowanie
Cztery klocki: Document (treść pliku), Settings (model embeddingów lokalnie + LLM przez OpenRouter, klucz ze zmiennej środowiskowej), VectorStoreIndex (indeks w pamięci) i query engine (pytanie → odpowiedź ze źródłami). To dosłownie wszystko, czego potrzebuje najprostszy RAG. W ostatniej części serii opakujemy te klocki w API na FastAPI: jeden endpoint do indeksowania plików Markdown z dysku, drugi do zadawania pytań.