Stwórz asystenta do rozmów w Wikipedia RAG przy użyciu LlamaIndex i ReAct
Indeks strony Wikipedia na żądanie, wstawianie fragmentów za pomocą małego kodera oraz umożliwienie agentowi ReAct wywoływania narzędzia silnika zapytań, dzięki czemu odpowiedzi Chainlit opierają się na uzyskanych dowodach.
Wprowadzenie
Wielkie modele językowe potrafią swobodnie komunikować się, ale ta biegłość nie oznacza umiejętności oceny, czy odpowiedź jest dokładna lub aktualna. Mogą tworzyć wiarygodne kłamstwa, gdy pytanie wykracza poza zakres treningu lub gdy pewność siebie przewyższa dostępne dowody.
Praktyczny asystent do rozmów w Wikipedii oparty na technologii RAG eliminuje tę luki, łącząc indeksowanie stron na żądanie, semantyczne wyszukiwanie, pakowanie dowodów, agenta ReAct, który decyduje, kiedy przeprowadzić wyszukiwanie, oraz interfejs konwersacyjny, który odpowiada na podstawie znalezionego tekstu. Materiały źródłowe do jego stworzenia znajdują się w repozytorium GitHub data-etl-ml, w sekcji agentic-ai wiki RAG sample.
Dlaczego RAG?
Bez mechanizmu wyszukiwania droga do uzyskania informacji jest krótka, ale krucha:
User Question
↓
LLM
↓
Answer
Wszystko zależy od tego, co model zapamiętał podczas treningu.
Z wykorzystaniem RAG dowody są wprowadzane przed generowaniem odpowiedzi:
User Question
↓
Retriever
↓
Relevant Documents
↓
LLM
↓
Grounded Answer
Model odpowiada na podstawie pobranych fragmentów tekstu. Oznacza to zazwyczaj mniej halucynacji, bardziej aktualne fakty, brak konieczności dopracowywania modelu w celu odświeżenia wiedzy oraz łatwy sposób na zmianę lub rozszerzenie korpusu.
Cel projektu
Należy stworzyć asystenta do rozmów, który odpowiada na podstawie stron Wikipedii wybranych przez użytkownika do indeksowania. Przykład zapytania:
Please index:
2023 United States banking crisis
Następnie należy zadać pytanie:
Which bank experienced the fastest bank run
in US history during 2023?
Odpowiedź powinna odwoływać się do treści pobranej strony, a nie do pamięci modelu.
Zarys architektury
Na wyższym poziomie system wygląda w ten sposób:
Wikipedia Pages
│
▼
WikipediaReader
│
▼
SentenceSplitter
│
▼
Embeddings
BAAI/bge-small-en
│
▼
VectorStoreIndex
│
▼
Query Engine
│
▼
QueryEngineTool
│
▼
ReAct Agent
│
▼
Chainlit UI
Istotne są dwa procesy: proces indeksowania, który tworzy przechowalnię wektorów umożliwiającą wyszukiwanie, oraz proces przetwarzania zapytań, który pobiera fragmenty tekstu i generuje odpowiedzi.
Krok 1: Odczyt klucza API OpenAI
Dane uwierzytelniające nie powinny znajdować się w źródle kodu. Unikaj ich hardkodowania:
api_key = "xxxxx"
Zamiast tego załaduj z pliku konfiguracyjnego:
def get_apikey():
with open("apikeys.yml") as file:
config = yaml.safe_load(file)
return config["OPENAI_API_KEY"]
Tajne dane pozostają oddzielone od logiki aplikacji.
Krok 2: Zrozumienie struktury kodu
Projekt składa się z trzech modułów w Pythonie:
utils.py
index_wikipages.py
chat_agent.py
utils.py załadowuje klucze API oraz konfigurację. index_wikipages.py analizuje żądania stron, pobiera tekst z Wikipedii, wstawia fragmenty i tworzy indeksy. chat_agent.py łączy agenta ReAct, narzędzie do przetwarzania zapytań oraz interfejs Chainlit.
Krok 3: Wyodrębnianie stron Wikipedii przy użyciu strukturyzowanego wyniku
Użytkownicy mogą wpisywać listy w dowolnej formie:
Please index:
London, Birmingham, New York
Indeksator potrzebuje uporządkowanego arraya:
[
"London",
"Birmingham",
"New York"
]
Zamiast niestabilnego dzielenia na łańcuchy, model Pydantic przechowuje strukturyzowany wynik:
class WikiPageList(BaseModel):
pages: List[str]
Model automatycznie przekształca język naturalny na uporządkowaną listę stron.
Krok 4: Ładowanie stron Wikipedia
LlamaIndex dostarcza wygodny narzędzie do ładowania:
WikipediaReader
Proces importu zajmuje zaledwie kilka linijek kodu:
loader = WikipediaReader()
documents = loader.load_data(
pages=["2023 United States banking crisis"]
)
W tym momencie pipeline przechowuje surowe dokumenty stron.
Krok 5: Dzielenie dokumentów na fragmenty
Modele słabo radzą sobie z dużymi stronami jako jednym całościowym obiektem. Należy je podzielić na nakładające się fragmenty:
SentenceSplitter(
chunk_size=150,
chunk_overlap=45
)
Nakładanie się pomaga zachować informacje znajdujące się na granicach fragmentów:
Chunk A:
---------------------
Paragraph 1
Paragraph 2
Chunk B:
---------------------
Paragraph 2
Paragraph 3
Krok 6: Tworzenie embeddingów
Surowy tekst nie wystarcza do wyszukiwania semantycznego. Każdy fragment staje się wektorem. Model embeddingów używany tutaj to:
BAAI/bge-small-en
Zapytanie w postaci:
"What is Databricks?"
przekształca się w gęsty wektor:
[0.21, -0.44, 0.87 ...]
Fragmenty semantycznie powiązane gromadzą się w pobliżu siebie w tym przestrzeni.
Krok 7: Tworzenie indeksu wektorowego
LlamaIndex obsługuje proces tworzenia takiego indeksu:
index = VectorStoreIndex(nodes)
Wynikiem jest indeks wektorowy w pamięci, który może odpowiadać na zapytania o podobieństwo w następujący sposób:
Find chunks similar to:
"fastest bank run in history"
Krok 8: Tworzenie silnika wyszukiwania
Ujawnij indeks jako silnik zapytań:
query_engine = index.as_query_engine(
response_mode="compact",
similarity_top_k=10,
verbose=True
)
similarity_top_k = 10
Return 10 most relevant chunks
similarity_top_k określa, ile sąsiednich fragmentów ma trafić do odpowiedzi.
Krok 9: Budowa agenta ReAct
ReAct oznacza:
Reason + Act
Naiwny bot przechodzi bezpośrednio od pytania do odpowiedzi:
Question
→ Answer
Agent ReAct włącza rozumowanie i wykorzystanie narzędzi:
Question
↓
Reason
↓
Choose Tool
↓
Observe Output
↓
Answer
Pobieranie informacji staje się dynamiczne, zamiast być ciągłe lub całkowicie wyłączone.
Tworzenie narzędzi
Otocz silnik zapytań jako narzędzie, które agent może wywołać:
QueryEngineTool(
query_engine=query_engine,
metadata=ToolMetadata(
name="Wikipedia"
)
)
Następnie agent wie, że istnieje możliwość wyszukiwania w Wikipedii.
ReAct Loop
The agent internally performs:
Wewnętrznie pętla wygląda następująco:
Thought:
Need information about the banking crisis.
Action:
Wikipedia Tool
Observation:
Found relevant passages.
Answer:
Grounded response.
Taki model jest bardziej niezawodny niż zwykłe uzupełnianie treści w czacie bez żadnych narzędzi.
Krok 10: Budowa interfejsu użytkownika przy użyciu Chainlit
Chainlit oferuje interfejs czatu z minimalną ilością kodu szablonowego. Panel ustawień umożliwia dostęp do:
Model
Wikipedia Pages
Przykład konfiguracji:
MODEL:
gpt-5-nano
Wikipedia Pages:
Please index:
2023 United States banking crisis
Ustawienia inicjalizują indeks wektorowy przed rozpoczęciem rozmowy.
Demo
Po indeksowaniu:
2023 United States banking crisis
pytanie takie jak:
Which bank experienced the fastest
bank run in US history?
przynosi odpowiedź opartą na faktach, np.:
Silicon Valley Bank (SVB)
Approximately $42 billion
was withdrawn in 10 hours.
Liczby pochodzą z odzyskanych dowodów, a nie są wynikiem dowolnej fikcji.
Wnioski
To, co zadziałało dobrze
LlamaIndex sprawia, że proces indeksowania jest krótki:
Documents
→ Nodes
→ Index
Agenty ReAct poprawiają decyzje dotyczące momentu pobierania danych, dzięki czemu wyszukiwanie odbywa się tylko wtedy, gdy jest to konieczne. Chainlit pozostaje jedną z najszybszych dróg do stworzenia użytecznego interfejsu czatu opartego na sztucznej inteligencji.
Wyzwania
Zgodność z Pythonem 3.13 sprawiła problemy kilku zestawom narzędzi — kombinacje Chainlit, Pydantic i LlamaIndex były niestabilne. Użycie wersji ustalonych:
Python 3.11
było znacznie bardziej niezawodne.
Jakość pobierania danych ma decydujące znaczenie dla jakości odpowiedzi. Niskiej jakości fragmenty danych prowadzą do słabych „sąsiadów” i w rezultacie do kiepskich odpowiedzi. Ważna lekcja: jakość pobierania danych często jest ważniejsza niż to, jaki model czatu jest używany.
Budujące się ulepszenia
Naturalnymi kolejnymi krokami są wyszukiwania hybrydowe:
Keyword Search
+
Semantic Search
Ponowna sortowanie wyników po pierwszym etapie szerokiego pobierania danych — pobierz:
Top 50
Następnie skompresuj to do najlepszych kilku wariantów. Cytaty, które pokazują akapity za każdym twierdzeniem. A także baza danych wektorowych o trwałym przechowywaniu zamiast tymczasowej:
VectorStoreIndex
z opcjami takimi jak Chroma, Pinecone, Weaviate lub Milvus.
Ostateczne uwagi
Projekt stanowi zwięzły przegląd nowoczesnych wzorców agentowych: RAG, embeddingi, wyszukiwanie wektorowe, narzędzia ReAct, interfejs Chainlit oraz orkiestracja LlamaIndex. Kluczowe jest tu połączenie różnych elementów, a nie sama rozbudowa liczby parametrów modelu. Sklonuj przykład 6_wiki_rag_react_project znajdujący się w folderze agentic-ai projektu GitHub data-etl-ml, aby przeprowadzić eksperymenty z całym tym zestawem narzędzi.