AI Engineering Academy · Lekcja

Wyszukiwanie nadrzędny–podrzędny i od małego do dużego

Przechowuj małe fragmenty podrzędne na potrzeby precyzyjnego wyszukiwania, ale zwracaj ich większe fragmenty nadrzędne do LLM, aby zapewnić bogatszy kontekst i równoważyć precyzję wyszukiwania z jakością generowania.

Lekcja 3 z 413 kroki

Wyszukiwanie nadrzędny–podrzędny i od małego do dużego to bezpłatna lekcja AI Engineering Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Engineering Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Engineering Academy zawiera 4 lekcji w sumie.

Dylemat: precyzja a kontekst

Systemy RAG muszą równoważyć dwie potrzeby: małe fragmenty są pobierane z dużą precyzją, ponieważ każdy z nich koncentruje się na jednej idei, ale brakuje im otaczającego kontekstu potrzebnego LLM-owi do wygenerowania pełnej odpowiedzi. Duże fragmenty zapewniają bogaty kontekst, ale zmniejszają precyzję wyszukiwania, ponieważ słabo pasują do wielu zapytań zamiast silnie pasować do jednego. Dzielenie na fragmenty nadrzędne i podrzędne rozwiązuje ten dylemat.

Architektura nadrzędny–podrzędny

W przypadku dzielenia na fragmenty nadrzędne i podrzędne tworzysz z tego samego dokumentu dwie warstwy fragmentów. Fragmenty podrzędne są małe (np. 1–3 zdania) i są osadzane oraz indeksowane na potrzeby wyszukiwania. Fragmenty nadrzędne to większe sekcje (np. całe akapity lub strony), przechowywane osobno. Gdy zostanie pobrany fragment podrzędny, zamiast niego przekazujesz LLM-owi jego fragment nadrzędny.

Budowanie hierarchii fragmentów

Pierwszym krokiem jest podzielenie dokumentu na duże fragmenty nadrzędne, a następnie podzielenie każdego fragmentu nadrzędnego na mniejsze fragmenty podrzędne. Każdy fragment podrzędny przechowuje odwołanie — zazwyczaj w polu metadanych parent_id — wskazujące jego fragment nadrzędny. To mapowanie pozwala znaleźć pełny fragment nadrzędny na podstawie dowolnego pobranego fragmentu podrzędnego.

from langchain.text_splitter import RecursiveCharacterTextSplitter

parent_splitter = RecursiveCharacterTextSplitter(chunk_size=1500, chunk_overlap=0)
child_splitter = RecursiveCharacterTextSplitter(chunk_size=300, chunk_overlap=30)

parent_chunks = parent_splitter.split_documents(docs)
child_chunks = []
for i, parent in enumerate(parent_chunks):
    children = child_splitter.split_documents([parent])
    for child in children:
        child.metadata['parent_id'] = i
    child_chunks.extend(children)

Indeksowanie wyłącznie fragmentów podrzędnych

Tylko fragmenty podrzędne są osadzane i przechowywane w bazie wektorowej. Fragmenty nadrzędne są przechowywane w osobnym magazynie klucz–wartość (słowniku w pamięci, Redisie lub bazie dokumentowej). Dzięki temu indeks wektorowy pozostaje gęsty i precyzyjny, a bogaty kontekst znajduje się poza nim.

# Store parents in a docstore
parent_store = {i: chunk.page_content for i, chunk in enumerate(parent_chunks)}

# Embed and index only children
vectorstore = Chroma.from_documents(
    child_chunks,
    embedding=OpenAIEmbeddings()
)

Wyszukiwanie: fragment podrzędny na wejściu, nadrzędny na wyjściu

Podczas wyszukiwania zapytanie użytkownika jest osadzane i porównywane z fragmentami podrzędnymi. Znajdowane są k najlepszych fragmentów podrzędnych, a zawarte w nich odwołania parent_id są rozwiązywane przez wyszukanie danych w magazynie fragmentów nadrzędnych. Następnie do promptu LLM-a wstawiane są fragmenty nadrzędne, a nie podrzędne. LLM otrzymuje szeroki kontekst, a wyszukiwanie zachowuje precyzję.

def retrieve_with_parents(query, vectorstore, parent_store, k=5):
    child_results = vectorstore.similarity_search(query, k=k)
    seen_parent_ids = set()
    parent_contexts = []
    for child in child_results:
        pid = child.metadata['parent_id']
        if pid not in seen_parent_ids:
            parent_contexts.append(parent_store[pid])
            seen_parent_ids.add(pid)
    return parent_contexts

LangChain ParentDocumentRetriever

LangChain udostępnia klasę ParentDocumentRetriever, która implementuje ten wzorzec od razu po wyjęciu z pudełka. Należy podać splitter dokumentów nadrzędnych, splitter dokumentów podrzędnych, bazę wektorową dla embeddingów dokumentów podrzędnych oraz magazyn dokumentów dla dokumentów nadrzędnych. Klasa konfiguruje hierarchię i w przejrzysty sposób obsługuje pobieranie danych.

from langchain.retrievers import ParentDocumentRetriever
from langchain.storage import InMemoryStore

store = InMemoryStore()
retriever = ParentDocumentRetriever(
    vectorstore=vectorstore,
    docstore=store,
    child_splitter=child_splitter,
    parent_splitter=parent_splitter
)
retriever.add_documents(docs)
results = retriever.invoke('What is the refund policy?')

Wyjaśnienie pobierania od małych do dużych fragmentów

Pobieranie od małych do dużych fragmentów to inna nazwa tej samej koncepcji: pobierane są małe, precyzyjne fragmenty, a następnie przed wysłaniem ich do LLM rozszerza się je o otaczający kontekst. Niektóre implementacje rozszerzają fragment nie do ustalonego dokumentu nadrzędnego, lecz do okna sąsiednich zdań — przekazując modelowi zdania znajdujące się przed dopasowanym fragmentem i po nim, aby zachować ciągłość kontekstu.

def retrieve_with_window(query, vectorstore, sentences, window=2, k=5):
    results = vectorstore.similarity_search(query, k=k)
    expanded = []
    for r in results:
        idx = r.metadata['sentence_index']
        start = max(0, idx - window)
        end = min(len(sentences), idx + window + 1)
        expanded.append(' '.join(sentences[start:end]))
    return expanded

Usuwanie duplikatów fragmentów nadrzędnych

W odpowiedzi na jedno zapytanie może zostać pobranych wiele fragmentów podrzędnych należących do tego samego dokumentu nadrzędnego. Bez usuwania duplikatów ten sam fragment dokumentu nadrzędnego pojawiłby się w promptcie wielokrotnie, niepotrzebnie zużywając tokeny. Przed złożeniem kontekstu zawsze usuwaj duplikaty na podstawie identyfikatora dokumentu nadrzędnego. Przykład kodu w przedstawionej wyżej funkcji retrieve obsługuje to za pomocą zbioru seen_parent_ids.

Kiedy stosować dzielenie na fragmenty nadrzędne i podrzędne

Pobieranie w układzie nadrzędny–podrzędny sprawdza się najlepiej, gdy dokumenty mają wyraźną strukturę hierarchiczną: rozdziały z sekcjami, artykuły z akapitami lub wiki z podsekcjami. Jest szczególnie skuteczne w przypadku długiej dokumentacji technicznej, w której precyzyjne pytania wymagają odpowiedzi dotyczących konkretnego miejsca, ale odpowiedzi te mają sens dopiero w szerszym kontekście sekcji.

Dobór rozmiarów fragmentów podrzędnych i nadrzędnych

Typowa konfiguracja obejmuje: fragmenty podrzędne o rozmiarze 200–400 tokenów (skupione na pojedynczych zagadnieniach) oraz fragmenty nadrzędne o rozmiarze 1000–2000 tokenów (pełne sekcje). Jeśli fragmenty podrzędne są zbyt małe, stają się pojedynczymi zdaniami, które same w sobie nie mają wystarczającego znaczenia. Jeśli fragmenty nadrzędne są zbyt duże, ponownie pojawia się problem rozmycia kontekstu, którego próbowano uniknąć.

Porównanie podejść: podsumowanie

Podsumowując dotychczasowe strategie dzielenia: stały rozmiar jest szybki, ale rozbija kontekst; dzielenie semantyczne zachowuje spójność tematyczną; układ nadrzędny–podrzędny optymalizuje zarówno precyzję pobierania, jak i bogactwo kontekstu LLM. W większości produkcyjnych systemów RAG przetwarzających długie dokumenty dzielenie na fragmenty nadrzędne i podrzędne zapewnia najlepszą jakość pobierania przy akceptowalnej złożoności.

Szybki sprawdzian

Sprawdź swoją wiedzę na temat dzielenia na fragmenty nadrzędne i podrzędne z tego modułu.

Podsumowanie modułu

W tym module nauczysz się, że: fragmenty podrzędne zapewniają precyzyjne pobieranie, a fragmenty nadrzędne — bogaty kontekst, ParentDocumentRetriever w LangChain automatycznie realizuje ten proces, a usuwanie duplikatów na podstawie identyfikatora dokumentu nadrzędnego zapobiega powtarzaniu kontekstu. Następnie omówimy strategie dzielenia zależne od rodzaju dokumentu, stosowane w plikach z kodem i dokumentach HTML.

Bezpłatny start

Ucz się Python dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
30
Lekcje
120

Często zadawane pytania

Czy lekcja „Wyszukiwanie nadrzędny–podrzędny i od małego do dużego” jest bezpłatna?

Tak — pełny tekst „Wyszukiwanie nadrzędny–podrzędny i od małego do dużego” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Engineering Academy, przejdź na CoddyKit PRO. Kurs AI Engineering Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Wyszukiwanie nadrzędny–podrzędny i od małego do dużego”?

Przechowuj małe fragmenty podrzędne na potrzeby precyzyjnego wyszukiwania, ale zwracaj ich większe fragmenty nadrzędne do LLM, aby zapewnić bogatszy kontekst i równoważyć precyzję wyszukiwania z jako… Ćwiczysz AI Engineering Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć AI Engineering Academy?

Nie wymagamy żadnego doświadczenia. AI Engineering Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „Wyszukiwanie nadrzędny–podrzędny i od małego do dużego”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji AI Engineering Academy?

Tak. Każda lekcja AI Engineering Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Dlaczego naiwne dzielenie na fragmenty pogarsza wyszukiwanie
  2. Dzielenie semantyczne na podstawie podobieństwa embeddingów
  3. Wyszukiwanie nadrzędny–podrzędny i od małego do dużego
  4. Strategie dopasowane do dokumentów: kod i HTML
← Powrót do AI Engineering Academy