În RAG există o contradicție fundamentală la împărțirea textelor în bucăți (chunking):
• Dacă faci fragmente mici (ex. 100 de tokeni), căutarea vectorială găsește exact propoziția căutată, dar când o trimiți la LLM, modelul nu înțelege contextul general și nu poate formula un răspuns complet.
• Dacă faci fragmente mari (ex. 1.000 de tokeni), contextul este bogat, dar embedding-ul devine ‘diluat’ și căutarea semantică ratează detalii specifice.
Parent-Child Chunking (numit și Small-to-Big Retrieval) rezolvă această dilemă prin separarea etapei de căutare de etapa de generare: documentul este împărțit în blocuri mari ‘părinte’ (secțiuni întregi sau pagini), iar fiecare părinte este subdivizat în fragmente mici ‘copil’ (propoziții sau paragrafe scurte).
În baza de date vectorială indexezi exclusiv fragmentele copil mici pentru a garanta o regăsire chirurgicală. Însă când un copil este găsit, sistemul îl folosește doar ca o ancoră: preia din baza de stocare întregul bloc părinte asociat și îl trimite către LLM, oferind modelului imaginea de ansamblu completă.
Concepte cheie și caracteristici
| Concept / Parametru | Descriere practică |
|---|---|
Child Chunks (Fragmente Copil) |
Fragmente scurte (tipic 50–150 tokeni) optimizate pentru acuratețea căutării semantice. |
Parent Chunks (Fragmente Părinte) |
Blocuri largi (tipic 500–1.500 tokeni) salvate într-un Document Store (Redis, SQLite, MongoDB). |
Parent ID Pointer |
Metadată unică atașată fiecărui vector copil ce indică direct cheia părintelui corespunzător. |
Deduplicare Părinți |
Dacă trei fragmente copil din același paragraf părinte sunt găsite, părintele este injectat o singură dată în prompt. |
Exemple practice și scenarii reale
Exemplul 1: Configurarea ParentDocumentRetriever în LangChain / Python
Indexăm propoziții mici, dar recuperăm paragrafe complete.
from langchain.retrievers import ParentDocumentRetriever
from langchain.storage import InMemoryStore
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
# 1. Splitter mare pentru părinți și mic pentru copii
parent_splitter = RecursiveCharacterTextSplitter(chunk_size=1000)
child_splitter = RecursiveCharacterTextSplitter(chunk_size=150)
# 2. Vectorstore pentru copii, Docstore pentru părinți
vectorstore = Chroma(collection_name="split_parents", embedding_function=embedder)
docstore = InMemoryStore()
retriever = ParentDocumentRetriever(
vectorstore=vectorstore,
docstore=docstore,
child_splitter=child_splitter,
parent_splitter=parent_splitter,
)
Rezultat & Impact
Regăsire de înaltă precizie cu livrare de context exhaustiv către LLM.
Greșeli frecvente și capcane
- Indexarea fragmentelor părinte direct în baza vectorială; acest lucru distruge avantajul granularității fine a căutării.
- Omiterea deduplicării id-urilor părinte atunci când se returnează multiple rezultate copil, irosind inutil fereastra de context.