Systemy RAG: Jak rerankery zwiększają precyzję odpowiedzi dużych modeli językowych
Duże modele językowe (LLM) wykazują imponujące zdolności do generowania tekstu, jednak ich skłonność do „halucynacji” – czyli dostarczania fałszywych lub niepotwierdzonych informacji – pozostaje poważnym problemem. Aby rozwiązać ten problem, aktywnie stosuje się architekturę Retrieval-Augmented Generation (RAG). Pozwala ona LLM-om opierać się na zewnętrznych, zweryfikowanych źródłach danych, co znacząco zwiększa wiarygodność i trafność generowanych odpowiedzi. Ten artykuł zagłębia się w zasady działania RAG, omawiając kluczowe komponenty, takie jak embeddingi, wektorowe bazy danych, retrievery, a w szczególności – rolę rerankerów w osiąganiu równowagi między szybkością wyszukiwania a precyzją dostarczanych informacji.
Podstawy RAG: Od halucynacji do faktów
Problem halucynacji LLM wynika z faktu, że modele te są trenowane na ogromnych zbiorach danych i potrafią generować wiarygodnie brzmiący tekst, nawet jeśli nie posiadają konkretnej wiedzy na zadany temat. Systemy RAG rozwiązują to, zapewniając modelowi dostęp do aktualnych i trafnych informacji z zewnętrznej bazy wiedzy. Proces ten obejmuje dwa główne etapy: wyszukiwanie (Retrieval) i generowanie (Generation). Na etapie wyszukiwania system wydobywa z bazy danych fragmenty tekstu, które najbardziej odpowiadają zapytaniu użytkownika, a następnie przekazuje je do LLM jako dodatkowy kontekst do wygenerowania odpowiedzi.
Aby efektywnie wykorzystać dane zewnętrzne, należy je odpowiednio przygotować. Długie dokumenty są dzielone na mniejsze, semantycznie spójne fragmenty, czyli chunks. Jest to konieczne, ponieważ LLM-y mają ograniczone okno kontekstowe, czyli maksymalną objętość tekstu, którą mogą przetworzyć jednocześnie. Aby zachować spójność informacji między sąsiednimi chunkami, stosuje się technikę overlap (nakładki), gdzie niewielka część poprzedniego fragmentu jest włączana na początek następnego. Pomaga to modelowi lepiej rozumieć kontekst podczas pracy z poszczególnymi częściami tekstu.
Wektorowe bazy danych i embeddingi: Wyszukiwanie semantyczne
Sercem systemu RAG jest mechanizm wyszukiwania trafnych fragmentów danych. Komputery nie są w stanie bezpośrednio rozumieć znaczenia słów; operują liczbami. Dlatego teksty są przekształcane w reprezentacje liczbowe, zwane embeddingami (osadzeniami) lub wektorami. Embedding to wielowymiarowy wektor (sekwencja liczb), który koduje semantyczne znaczenie słowa, frazy lub całego fragmentu tekstu. Słowa lub frazy podobne pod względem znaczenia będą miały wektory położone blisko siebie w przestrzeni wielowymiarowej.
Proces tworzenia embeddingów odbywa się za pomocą wyspecjalizowanych modeli embeddingowych, które są trenowane na ogromnych korpusach tekstowych. Uczą się one mapować słowa i ich kontekst na unikalne reprezentacje liczbowe. Na przykład, jeśli weźmiemy wektory dla słów „król”, „mężczyzna” i „kobieta”, to wektor „królowa” będzie bardzo bliski wynikowi operacji „wektor(król) - wektor(mężczyzna) + wektor(kobieta)”. To pokazuje zdolność embeddingów do wychwytywania złożonych relacji semantycznych i syntaktycznych w języku.
Uzyskane embeddingi są przechowywane w wektorowych bazach danych. Bazy te są zoptymalizowane pod kątem szybkiego wyszukiwania najbliższych wektorów. Gdy użytkownik zadaje pytanie, jego zapytanie również jest przekształcane w embedding, a następnie wektorowa baza danych znajduje fragmenty tekstu, których embeddingi są maksymalnie podobne do embeddingu zapytania. Podobieństwo wektorów jest zazwyczaj mierzone za pomocą metryk, takich jak podobieństwo kosinusowe.
Oto przykład kodu w Pythonie, demonstrujący tworzenie embeddingu za pomocą API OpenAI:
# Dla działania przykładu należy zainstalować bibliotekę openai i uzyskać klucz API
from openai import OpenAI
import os
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
text = "Kotek Mruczek Wielobajtowicz lubi opowiadać o mnichach z Cejlonu"
response = client.embeddings.create(
model="text-embedding-3-small",
input=text,
dimensions=768 # jawnie określamy wymiarowość
)
vector = response.data[0].embedding
print(f"Wymiarowość wektora: {len(vector)}") # wyświetli 768
print("Pierwsze 20 liczb:", vector[:20])
print("... i tak dalej aż do 768. liczby")
Ten kod przekształca frazę tekstową w wektor liczbowy składający się z 768 elementów, który następnie może być użyty do wyszukiwania w wektorowej bazie danych.
Retrievery i skalowanie: Wyzwania wydajności
Retriever to komponent systemu RAG, odpowiedzialny za wydobywanie początkowego zestawu trafnych dokumentów lub fragmentów z wektorowej bazy danych. Wykorzystuje on embedding zapytania użytkownika do wyszukiwania najbardziej podobnych embeddingów przechowywanych chunków. W przypadku małych kolekcji dokumentów retriever może wykonywać pełne przeszukiwanie, porównując embedding zapytania ze wszystkimi przechowywanymi wektorami. Jednak wraz ze wzrostem objętości danych (miliardy fragmentów) takie podejście staje się nieefektywne i zbyt wolne.
Aby rozwiązać problem skalowania, stosuje się różne algorytmy przybliżonego wyszukiwania najbliższych sąsiadów (Approximate Nearest Neighbor, ANN). Algorytmy te tworzą specjalne indeksy, takie jak IVF (Inverted File Index), HNSW (Hierarchical Navigable Small World) lub LSH (Locality Sensitive Hashing). Indeksy ANN pozwalają znacząco przyspieszyć wyszukiwanie, poświęcając przy tym niewielki ułamek dokładności. Znajdują one nie absolutnie dokładnych, ale bardzo bliskich sąsiadów w znacznie krótszym czasie. W ten sposób pojawia się kompromis między recall (kompletnością, czyli zdolnością do znalezienia wszystkich istotnych elementów) a latency (opóźnieniem, czyli szybkością odpowiedzi).
Mimo optymalizacji szybkości, wyniki zwracane przez retrievera nie zawsze są idealne. Retrievery mogą wydobywać fragmenty, które są semantycznie bliskie zapytaniu, ale nie są najbardziej trafne ani precyzyjne do sformułowania ostatecznej odpowiedzi. Wynika to z faktu, że embeddingi używane do wyszukiwania są często jednokierunkowe (bi-encoder), to znaczy zapytanie i dokumenty są kodowane niezależnie, a następnie ich wektory są porównywane. Jest to efektywne dla szybkiego wyszukiwania, ale może pomijać subtelne powiązania kontekstowe.
Zwiększanie precyzji za pomocą rerankerów
Aby przezwyciężyć ograniczenia retrieverów i zwiększyć precyzję odpowiedzi systemów RAG, stosuje się rerankery. Reranker to dodatkowy komponent, który otrzymuje od retrievera niewielki zestaw (np. 10-100) potencjalnie trafnych fragmentów i zmienia ich kolejność na podstawie głębszej oceny trafności. Działa on jak filtr, który odrzuca mniej użyteczne wyniki i podnosi te najbardziej znaczące na szczyt listy.
W przeciwieństwie do modeli embeddingowych używanych przez retrievery, rerankery często wykorzystują cross-encodery. Cross-encodery przyjmują jako dane wejściowe pary „zapytanie-dokument” i wspólnie je przetwarzają, oceniając ich wzajemną trafność. Pozwala to im wychwytywać bardziej złożone i subtelne interakcje między zapytaniem a kontekstem niż proste porównania wektorów. Chociaż cross-encodery są znacznie wolniejsze niż modele embeddingowe typu bi-encoder, są one stosowane do już przefiltrowanego, niewielkiego zestawu dokumentów, co sprawia, że ich użycie jest obliczeniowo akceptowalne.
W ten sposób rerankery pomagają znaleźć optymalny balans między szybkością a precyzją. Szybki retriever z indeksami ANN sprawnie wybiera szeroki zakres potencjalnie trafnych chunków, a następnie wolniejszy, ale dokładniejszy reranker ponownie ocenia ten ograniczony zestaw, zapewniając, że LLM otrzyma najbardziej jakościowy kontekst do wygenerowania odpowiedzi. To wieloetapowe podejście znacząco poprawia jakość i wiarygodność informacji dostarczanych przez system RAG, minimalizując ryzyko halucynacji i zwiększając ogólne zadowolenie użytkownika.
Co ważne
- Systemy RAG pozwalają LLM-om wykorzystywać dane zewnętrzne do generowania precyzyjnych i wiarygodnych odpowiedzi, zwalczając problem „halucynacji”.
- Embeddingi przekształcają tekst w wektory liczbowe, kodujące semantyczne znaczenie, co umożliwia wyszukiwanie na podstawie podobieństwa w wektorowych bazach danych.
- Retrievery wykorzystują embeddingi i indeksy ANN do szybkiego wydobywania początkowego zestawu trafnych fragmentów, zapewniając kompromis między szybkością a kompletnością (recall).
- Rerankery (często oparte na cross-encoderach) ponownie oceniają wyniki retrievera, odrzucając mniej trafne fragmenty i zwiększając precyzję kontekstu dla LLM.
- Połączenie szybkiego retrievera i precyzyjnego rerankera pozwala osiągnąć optymalny balans między wydajnością a jakością w systemach RAG.
— Editorial Team
Brak komentarzy.