Splitting de documentos

Intermedio
LangChain
LangChain
Actualizado: 09/07/2025

¡Desbloquea el curso completo!

IA
Ejercicios
Certificado
Entrar

RecursiveCharacterTextSplitter

El RecursiveCharacterTextSplitter es la herramienta principal de LangChain para dividir documentos largos en fragmentos más pequeños y manejables. A diferencia de otros métodos de división más básicos, este splitter utiliza una estrategia jerárquica que respeta la estructura natural del texto, intentando mantener párrafos, oraciones y palabras completas siempre que sea posible.

Funcionamiento interno del splitter

El RecursiveCharacterTextSplitter funciona mediante un algoritmo recursivo que intenta dividir el texto utilizando una lista ordenada de separadores. Primero intenta dividir por párrafos (dobles saltos de línea), luego por oraciones (puntos seguidos de espacio), después por palabras (espacios) y finalmente por caracteres individuales si es necesario.

from langchain_text_splitters import RecursiveCharacterTextSplitter

# Configuración básica del splitter
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200,
    length_function=len,
    is_separator_regex=False,
)

Esta jerarquía de separadores garantiza que el texto se divida de la manera más natural posible. Si un párrafo completo cabe dentro del tamaño de chunk especificado, se mantendrá intacto. Solo cuando el párrafo es demasiado largo, el algoritmo intentará dividirlo por oraciones, y así sucesivamente.

Separadores por defecto

El splitter utiliza una lista predefinida de separadores que está optimizada para texto en inglés, pero funciona eficazmente también con español:

# Los separadores por defecto (en orden de prioridad)
default_separators = [
    "\n\n",    # Párrafos
    "\n",      # Líneas
    " ",       # Palabras
    "",        # Caracteres individuales
]

Puedes personalizar estos separadores según el tipo de documento que estés procesando:

# Splitter personalizado para código Python
code_splitter = RecursiveCharacterTextSplitter(
    chunk_size=800,
    chunk_overlap=100,
    separators=[
        "\n\nclass ",
        "\n\ndef ",
        "\n\n",
        "\n",
        " ",
        ""
    ]
)

Ejemplo práctico con texto real

Veamos cómo funciona el splitter con un documento de ejemplo:

from langchain_text_splitters import RecursiveCharacterTextSplitter

# Texto de ejemplo que simula un documento técnico
documento = """
La inteligencia artificial ha revolucionado múltiples sectores en las últimas décadas. 
Sus aplicaciones van desde el reconocimiento de voz hasta la conducción autónoma.

En el ámbito del procesamiento de lenguaje natural, los modelos de transformers han 
marcado un antes y un después. Estos modelos utilizan mecanismos de atención que 
permiten procesar secuencias de texto de manera más eficiente.

Los sistemas RAG (Retrieval-Augmented Generation) combinan la recuperación de 
información con la generación de texto. Esta aproximación permite a los modelos 
acceder a conocimiento actualizado sin necesidad de reentrenamiento.

Para implementar un sistema RAG efectivo, es crucial dividir los documentos en 
fragmentos apropiados. El tamaño de estos fragmentos afecta directamente la 
calidad de la recuperación de información.
"""

# Configurar el splitter
splitter = RecursiveCharacterTextSplitter(
    chunk_size=300,
    chunk_overlap=50
)

# Dividir el documento
chunks = splitter.split_text(documento)

# Mostrar los resultados
for i, chunk in enumerate(chunks):
    print(f"Chunk {i + 1}:")
    print(chunk)
    print(f"Longitud: {len(chunk)} caracteres")
    print("-" * 50)

Trabajando con objetos Document

En aplicaciones RAG reales, normalmente trabajarás con objetos Document que incluyen metadatos además del contenido textual:

from langchain_core.documents import Document

# Crear documentos con metadatos
documentos = [
    Document(
        page_content="Contenido del primer documento sobre IA...",
        metadata={"fuente": "articulo_ia.pdf", "pagina": 1}
    ),
    Document(
        page_content="Contenido del segundo documento sobre ML...",
        metadata={"fuente": "libro_ml.pdf", "pagina": 15}
    )
]

# El splitter preserva los metadatos en cada chunk
chunks_con_metadatos = splitter.split_documents(documentos)

# Verificar que los metadatos se mantienen
for chunk in chunks_con_metadatos:
    print(f"Contenido: {chunk.page_content[:100]}...")
    print(f"Metadatos: {chunk.metadata}")

Ejemplo de uso con documentos leídos de PDF, primero cargo el pdf:

Segundo hago el split:

Consideraciones para diferentes tipos de contenido

El tipo de contenido que estés procesando influye en cómo debes configurar el splitter:

Para documentos académicos o técnicos:

academic_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1200,  # Chunks más grandes para mantener contexto
    chunk_overlap=200,
    separators=["\n\n", "\n", ". ", " ", ""]
)

Para código fuente:

code_splitter = RecursiveCharacterTextSplitter(
    chunk_size=800,
    chunk_overlap=100,
    separators=["\n\nclass ", "\n\ndef ", "\n\n", "\n", " ", ""]
)

Para contenido conversacional o chat:

chat_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,   # Chunks más pequeños para respuestas rápidas
    chunk_overlap=50,
    separators=["\n\n", "\n", ". ", "! ", "? ", " ", ""]
)

El RecursiveCharacterTextSplitter es especialmente eficaz para mantener la coherencia semántica del texto, ya que su enfoque jerárquico evita cortes abruptos en medio de ideas importantes. Esta característica lo convierte en la opción preferida para la mayoría de aplicaciones RAG donde la calidad del contexto es fundamental para obtener respuestas precisas.

chunk_size y chunk_overlap

Guarda tu progreso

Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.

Progreso guardado
Asistente IA
Ejercicios
Iniciar sesión gratis

Más de 25.000 desarrolladores ya confían en CertiDevs

Los parámetros chunk_size y chunk_overlap son fundamentales para controlar cómo se divide el texto y determinar la calidad del retrieval en sistemas RAG. Una configuración inadecuada de estos valores puede resultar en pérdida de contexto importante o en chunks demasiado fragmentados que dificulten la comprensión.

Entendiendo chunk_size

El chunk_size define el tamaño máximo en caracteres que puede tener cada fragmento de texto. Este parámetro actúa como un límite superior, pero el splitter intentará crear chunks más pequeños si encuentra separadores naturales antes de alcanzar este límite.

from langchain_text_splitters import RecursiveCharacterTextSplitter

# Ejemplo con diferentes tamaños de chunk
texto_ejemplo = """
Los sistemas de recomendación utilizan algoritmos de machine learning para predecir 
las preferencias de los usuarios. Estos sistemas analizan patrones de comportamiento 
histórico para sugerir productos, contenido o servicios relevantes.

Existen principalmente tres tipos de sistemas de recomendación: colaborativos, 
basados en contenido e híbridos. Los sistemas colaborativos se basan en las 
similitudes entre usuarios, mientras que los basados en contenido analizan 
las características de los elementos.

La implementación de un sistema de recomendación requiere considerar factores 
como la escalabilidad, la precisión y la diversidad de las recomendaciones.
"""

# Chunk pequeño (200 caracteres)
splitter_pequeño = RecursiveCharacterTextSplitter(
    chunk_size=200,
    chunk_overlap=0
)

chunks_pequeños = splitter_pequeño.split_text(texto_ejemplo)
print(f"Chunks pequeños generados: {len(chunks_pequeños)}")
for i, chunk in enumerate(chunks_pequeños):
    print(f"Chunk {i+1} ({len(chunk)} chars): {chunk[:100]}...")

El impacto del tamaño en la recuperación

Un chunk_size demasiado pequeño puede fragmentar información relacionada, mientras que uno demasiado grande puede incluir información irrelevante que diluya la relevancia del contenido recuperado.

# Comparación práctica de diferentes tamaños
tamaños = [300, 600, 1200]

for tamaño in tamaños:
    splitter = RecursiveCharacterTextSplitter(
        chunk_size=tamaño,
        chunk_overlap=50
    )
    
    chunks = splitter.split_text(texto_ejemplo)
    
    print(f"\nTamaño {tamaño}:")
    print(f"Número de chunks: {len(chunks)}")
    print(f"Tamaño promedio: {sum(len(c) for c in chunks) / len(chunks):.0f} chars")
    
    # Mostrar el primer chunk como ejemplo
    print(f"Primer chunk: {chunks[0][:150]}...")

Comprendiendo chunk_overlap

El chunk_overlap especifica cuántos caracteres se solapan entre chunks consecutivos. Este solapamiento es crucial para mantener la continuidad del contexto y evitar que información importante se pierda en los límites entre fragmentos.

# Ejemplo sin solapamiento
sin_overlap = RecursiveCharacterTextSplitter(
    chunk_size=400,
    chunk_overlap=0
)

# Ejemplo con solapamiento
con_overlap = RecursiveCharacterTextSplitter(
    chunk_size=400,
    chunk_overlap=100
)

texto_continuidad = """
La arquitectura de transformers revolucionó el procesamiento de lenguaje natural. 
El mecanismo de atención permite al modelo enfocarse en diferentes partes del texto 
de entrada simultáneamente. Esta capacidad de atención paralela es lo que hace 
a los transformers tan eficientes para tareas de comprensión de texto.

Los modelos como BERT y GPT utilizan esta arquitectura para lograr resultados 
excepcionales en múltiples tareas de NLP.
"""

chunks_sin = sin_overlap.split_text(texto_continuidad)
chunks_con = con_overlap.split_text(texto_continuidad)

print("Sin solapamiento:")
for i, chunk in enumerate(chunks_sin):
    print(f"Chunk {i+1}: ...{chunk[-50:]}")

print("\nCon solapamiento:")
for i, chunk in enumerate(chunks_con):
    print(f"Chunk {i+1}: ...{chunk[-50:]}")

Calculando el overlap óptimo

Una regla práctica es establecer el overlap entre el 10% y 20% del chunk_size. Esto proporciona suficiente contexto sin crear redundancia excesiva:

def calcular_overlap_recomendado(chunk_size):
    """Calcula el overlap recomendado basado en el tamaño del chunk"""
    return int(chunk_size * 0.15)  # 15% del tamaño del chunk

# Ejemplos de configuraciones balanceadas
configuraciones = [
    {"chunk_size": 500, "chunk_overlap": calcular_overlap_recomendado(500)},
    {"chunk_size": 1000, "chunk_overlap": calcular_overlap_recomendado(1000)},
    {"chunk_size": 1500, "chunk_overlap": calcular_overlap_recomendado(1500)}
]

for config in configuraciones:
    splitter = RecursiveCharacterTextSplitter(**config)
    print(f"Chunk size: {config['chunk_size']}, Overlap: {config['chunk_overlap']}")
    
    chunks = splitter.split_text(texto_continuidad)
    print(f"Chunks generados: {len(chunks)}")
    print(f"Eficiencia: {(sum(len(c) for c in chunks) / len(texto_continuidad)):.2f}x")
    print("-" * 40)

Configuraciones según el caso de uso

La elección de parámetros debe adaptarse al tipo de aplicación RAG que estés desarrollando:

Para chatbots de atención al cliente:

# Respuestas rápidas y precisas
customer_service_splitter = RecursiveCharacterTextSplitter(
    chunk_size=600,    # Suficiente para procedimientos completos
    chunk_overlap=120  # 20% de overlap para mantener contexto
)

Para análisis de documentos legales:

# Precisión máxima, contexto extenso
legal_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1500,   # Chunks grandes para cláusulas completas
    chunk_overlap=300  # Overlap generoso para referencias cruzadas
)

Para búsqueda en bases de conocimiento técnico:

# Balance entre precisión y cobertura
technical_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,   # Tamaño medio para explicaciones técnicas
    chunk_overlap=150  # Overlap moderado para conceptos relacionados
)

Midiendo la efectividad de la configuración

Para evaluar si tu configuración es óptima, puedes analizar métricas como la distribución de tamaños y la redundancia:

def analizar_chunks(chunks):
    """Analiza las características de los chunks generados"""
    tamaños = [len(chunk) for chunk in chunks]
    
    estadisticas = {
        "total_chunks": len(chunks),
        "tamaño_promedio": sum(tamaños) / len(tamaños),
        "tamaño_mínimo": min(tamaños),
        "tamaño_máximo": max(tamaños),
        "desviación_estándar": (sum((t - sum(tamaños)/len(tamaños))**2 for t in tamaños) / len(tamaños))**0.5
    }
    
    return estadisticas

# Analizar diferentes configuraciones
documento_prueba = "Tu documento de prueba aquí..." * 100  # Documento largo

for chunk_size in [500, 1000, 1500]:
    overlap = int(chunk_size * 0.15)
    splitter = RecursiveCharacterTextSplitter(
        chunk_size=chunk_size,
        chunk_overlap=overlap
    )
    
    chunks = splitter.split_text(documento_prueba)
    stats = analizar_chunks(chunks)
    
    print(f"\nConfiguración: chunk_size={chunk_size}, overlap={overlap}")
    for key, value in stats.items():
        print(f"{key}: {value:.2f}")

La configuración óptima de chunk_size y chunk_overlap depende del equilibrio entre mantener suficiente contexto para respuestas coherentes y evitar la dilución de información relevante. Experimentar con diferentes valores y medir el rendimiento en tu caso de uso específico es la mejor estrategia para encontrar la configuración ideal.

Aprendizajes de esta lección

  • Comprender el funcionamiento jerárquico y recursivo del RecursiveCharacterTextSplitter.
  • Aprender a configurar los parámetros chunk_size y chunk_overlap para dividir textos de forma eficiente.
  • Saber personalizar separadores según el tipo de contenido para mantener la coherencia semántica.
  • Entender la importancia del solapamiento entre fragmentos para preservar contexto en aplicaciones RAG.
  • Evaluar y ajustar configuraciones según el caso de uso específico para optimizar la calidad de la recuperación de información.

Completa LangChain y certifícate

Únete a nuestra plataforma y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.

Asistente IA

Resuelve dudas al instante

Ejercicios

Practica con proyectos reales

Certificados

Valida tus conocimientos

Más de 25.000 desarrolladores ya se han certificado con CertiDevs

⭐⭐⭐⭐⭐
4.9/5 valoración