Recuperación padre-hijo y de pequeño a grande
Almacene fragmentos hijo pequeños para lograr una recuperación precisa, pero devuelva sus fragmentos padre más grandes al LLM para ofrecer un contexto más rico y equilibrar la precisión de recuperación con la calidad de generación.
Recuperación padre-hijo y de pequeño a grande es una lección gratuita de AI Engineering Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de AI Engineering Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de AI Engineering Academy incluye 4 lecciones en total.
El dilema entre precisión y contexto
Los sistemas RAG se enfrentan a una tensión: los fragmentos pequeños se recuperan con gran precisión porque cada uno se centra en una idea, pero carecen del contexto circundante que el LLM necesita para generar una respuesta completa. Los fragmentos grandes proporcionan un contexto abundante, pero reducen la precisión de recuperación porque coinciden débilmente con muchas consultas en lugar de hacerlo fuertemente con una sola. La división padre-hijo resuelve este dilema.
La arquitectura padre-hijo
En la división padre-hijo, se crean dos capas de fragmentos a partir del mismo documento. Los fragmentos hijo son pequeños (por ejemplo, de 1 a 3 frases) y se transforman en embeddings y se indexan para la recuperación. Los fragmentos padre son secciones más grandes (por ejemplo, párrafos o páginas completos) que se almacenan por separado. Cuando se recupera un hijo, se devuelve su padre al LLM.
Construcción de la jerarquía de fragmentos
El primer paso consiste en dividir el documento en fragmentos padre grandes y, después, dividir cada padre en fragmentos hijo más pequeños. Cada fragmento hijo conserva una referencia —normalmente un campo de metadatos parent_id— que apunta a su padre. Esta correspondencia permite buscar el pasaje padre completo a partir de cualquier hijo recuperado.
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)Indexación únicamente de los fragmentos hijo
Solo los fragmentos hijo se transforman en embeddings y se almacenan en la base de datos vectorial. Los fragmentos padre se almacenan en un almacén de clave-valor independiente (un diccionario en memoria, Redis o una base de datos de documentos). Así, el índice vectorial se mantiene denso y preciso, mientras que el contexto enriquecido permanece fuera de él.
# 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()
)Recuperación: entra el hijo, sale el padre
Durante la recuperación, se genera el embedding de la consulta del usuario y se compara con los fragmentos hijo. Se encuentran los fragmentos hijo del top-k y sus referencias parent_id se resuelven buscando en el almacén de padres. A continuación, se inyectan en el prompt del LLM los pasajes padre, no los hijos. El LLM recibe un contexto amplio; la recuperación fue precisa.
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_contextsParentDocumentRetriever de LangChain
LangChain proporciona la clase ParentDocumentRetriever, que implementa este patrón de forma integrada. Debe proporcionar un divisor para los documentos principales, un divisor para los documentos secundarios, un almacén vectorial para las incrustaciones de los documentos secundarios y un almacén de documentos para los documentos principales. La clase configura la jerarquía y gestiona la recuperación de forma transparente.
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?')Explicación de la recuperación de pequeño a grande
La recuperación de pequeño a grande es otro nombre para el mismo concepto: se recuperan fragmentos pequeños y precisos, pero después se amplían para incluir el contexto circundante antes de enviarlos al LLM. Algunas implementaciones no amplían el fragmento hasta un documento principal fijo, sino hasta una ventana de oraciones adyacentes, proporcionando al modelo las oraciones anteriores y posteriores al fragmento coincidente para mantener la continuidad contextual.
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 expandedEliminación de duplicados en los fragmentos principales
Es posible que se recuperen varios fragmentos secundarios del mismo documento principal para una consulta. Sin eliminación de duplicados, el mismo pasaje principal aparecería varias veces en el prompt y desperdiciaría tokens. Siempre debe eliminar los duplicados mediante el ID del documento principal antes de ensamblar el contexto. El ejemplo de código de la función de recuperación anterior lo hace con un conjunto seen_parent_ids.
Cuándo usar la fragmentación principal-secundaria
La recuperación principal-secundaria funciona mejor cuando los documentos tienen una estructura jerárquica clara: capítulos con secciones, artículos con párrafos o wikis con subsecciones. Es especialmente eficaz para documentación técnica extensa en la que las preguntas precisas requieren respuestas localizadas, pero esas respuestas solo tienen sentido dentro de un contexto más amplio de la sección.
Elección del tamaño de los fragmentos secundarios y principales
Una configuración habitual es la siguiente: fragmentos secundarios de 200 a 400 tokens (ideas individuales y concretas) y fragmentos principales de 1000 a 2000 tokens (secciones completas). Si los fragmentos secundarios son demasiado pequeños, se convierten en oraciones individuales que carecen de significado por sí solas. Si los fragmentos principales son demasiado grandes, comienza a reaparecer el problema de dilución del contexto que se intentaba evitar.
Comparación de enfoques: resumen
En resumen, las estrategias de fragmentación vistas hasta ahora son las siguientes: el tamaño fijo es rápido, pero rompe el contexto; la fragmentación semántica conserva la coherencia temática; y la fragmentación principal-secundaria optimiza tanto la precisión de la recuperación como la riqueza del contexto del LLM. En la mayoría de los sistemas RAG de producción que procesan documentos extensos, la fragmentación principal-secundaria ofrece la mejor calidad de recuperación con una complejidad manejable.
Comprobación rápida
Compruebe su comprensión de la fragmentación principal-secundaria explicada en esta lección.
Resumen de la lección
En esta lección ha aprendido que: los fragmentos secundarios permiten una recuperación precisa, mientras que los fragmentos principales proporcionan un contexto enriquecido; ParentDocumentRetriever de LangChain implementa este proceso automáticamente; y la eliminación de duplicados mediante el ID del documento principal evita repetir el contexto. A continuación exploraremos estrategias de fragmentación específicas para documentos de código y documentos HTML.
Aprende Python con un tutor de IA — gratis
Escribe y ejecuta código real en tu navegador, obtén ayuda instantánea de un tutor de IA disponible 24/7 y continúa donde lo dejaste en la web o en la aplicación.
- Cursos
- 30
- Lecciones
- 120
Preguntas frecuentes
¿La lección «Recuperación padre-hijo y de pequeño a grande» es gratis?
Sí — el texto completo de «Recuperación padre-hijo y de pequeño a grande» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de AI Engineering Academy, actualiza a CoddyKit PRO. El curso de AI Engineering Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Recuperación padre-hijo y de pequeño a grande»?
Almacene fragmentos hijo pequeños para lograr una recuperación precisa, pero devuelva sus fragmentos padre más grandes al LLM para ofrecer un contexto más rico y equilibrar la precisión de recuperaci… Practicas AI Engineering Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar AI Engineering Academy?
No se requiere experiencia previa. AI Engineering Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.
¿Cuánto tiempo toma la lección «Recuperación padre-hijo y de pequeño a grande»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de AI Engineering Academy?
Sí. Cada lección de AI Engineering Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Por qué la división ingenua perjudica la recuperación
- División semántica con similitud de embeddings
- Recuperación padre-hijo y de pequeño a grande
- Estrategias específicas para código y HTML