Chunking avanzado

Intermedio
LangChain
LangChain
Actualizado: 02/12/2025

HTMLHeaderTextSplitter y MarkdownHeaderTextSplitter

Cuando trabajamos con documentos que tienen una estructura jerárquica bien definida, como páginas web HTML o documentación en Markdown, podemos aprovechar esta organización para crear chunks más inteligentes. Los splitters especializados HTMLHeaderTextSplitter y MarkdownHeaderTextSplitter preservan la información contextual de los encabezados.

Preservando la estructura con HTMLHeaderTextSplitter

El HTMLHeaderTextSplitter analiza documentos HTML y utiliza las etiquetas de encabezado (<h1>, <h2>, <h3>, etc.) como puntos de división natural:

from langchain_text_splitters import HTMLHeaderTextSplitter

# Definir qué encabezados usar como separadores
headers_to_split_on = [
    ("h1", "Header 1"),
    ("h2", "Header 2"),
    ("h3", "Header 3"),
]

html_splitter = HTMLHeaderTextSplitter(headers_to_split_on=headers_to_split_on)

html_content = """
<html>
<body>
    <h1>Introducción a Machine Learning</h1>
    <p>El machine learning es una rama de la inteligencia artificial...</p>
    
    <h2>Algoritmos Supervisados</h2>
    <p>Los algoritmos supervisados aprenden de datos etiquetados...</p>
    
    <h3>Regresión Lineal</h3>
    <p>La regresión lineal es uno de los algoritmos más básicos...</p>
    
    <h2>Algoritmos No Supervisados</h2>
    <p>Estos algoritmos trabajan con datos sin etiquetas...</p>
</body>
</html>
"""

html_chunks = html_splitter.split_text(html_content)

for i, chunk in enumerate(html_chunks):
    print(f"Chunk {i + 1}:")
    print(f"Contenido: {chunk.page_content}")
    print(f"Metadatos: {chunk.metadata}")
    print("-" * 50)

Cada chunk resultante incluye metadatos estructurados que indican su posición en la jerarquía del documento.

Trabajando con documentación Markdown

El MarkdownHeaderTextSplitter funciona de manera similar pero está optimizado para documentos Markdown, reconociendo la sintaxis de encabezados (#, ##, ###, etc.):

from langchain_text_splitters import MarkdownHeaderTextSplitter

markdown_headers = [
    ("#", "Header 1"),
    ("##", "Header 2"), 
    ("###", "Header 3"),
]

markdown_splitter = MarkdownHeaderTextSplitter(
    headers_to_split_on=markdown_headers,
    strip_headers=False
)

markdown_content = """
# API de Autenticación

Esta API proporciona endpoints para la autenticación de usuarios.

## Endpoints Disponibles

La API incluye los siguientes endpoints principales.

### POST /auth/login

Autentica un usuario con credenciales.

**Parámetros:**
- username: Nombre de usuario
- password: Contraseña

### POST /auth/refresh

Renueva un token de acceso existente.

## Códigos de Error

La API utiliza códigos de estado HTTP estándar.
"""

markdown_chunks = markdown_splitter.split_text(markdown_content)

for i, chunk in enumerate(markdown_chunks):
    print(f"Chunk {i + 1}:")
    print(f"Contenido: {chunk.page_content[:100]}...")
    print(f"Metadatos: {chunk.metadata}")

Combinando splitters para documentos complejos

En muchos casos reales, necesitamos combinar múltiples estrategias de splitting:

from langchain_text_splitters import (
    MarkdownHeaderTextSplitter, 
    RecursiveCharacterTextSplitter
)

# Primer paso: dividir por encabezados
markdown_splitter = MarkdownHeaderTextSplitter(
    headers_to_split_on=[
        ("#", "Header 1"),
        ("##", "Header 2"),
        ("###", "Header 3"),
    ]
)

# Segundo paso: controlar el tamaño de chunks
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=50
)

# Aplicar splitting en dos fases
header_chunks = markdown_splitter.split_text(markdown_content)
final_chunks = []

for chunk in header_chunks:
    if len(chunk.page_content) > 500:
        sub_chunks = text_splitter.split_documents([chunk])
        final_chunks.extend(sub_chunks)
    else:
        final_chunks.append(chunk)

print(f"Chunks finales generados: {len(final_chunks)}")

Configuración avanzada de separadores

Más allá de los separadores predeterminados, RecursiveCharacterTextSplitter ofrece configuraciones avanzadas que permiten adaptar el comportamiento de división a las características específicas de diferentes tipos de contenido.

Separadores personalizados por tipo de contenido

El comportamiento por defecto utiliza una jerarquía de separadores que funciona bien para texto general, pero podemos definir separadores específicos:

from langchain_text_splitters import RecursiveCharacterTextSplitter

# Separadores optimizados para documentación técnica
technical_separators = [
    "\n\n",
    "\n### ",
    "\n## ",
    "\n# ",
    "\n```\n",
    "\n---\n",
    "\n",
    ". ",
    " ",
    ""
]

tech_splitter = RecursiveCharacterTextSplitter(
    separators=technical_separators,
    chunk_size=800,
    chunk_overlap=100
)

Separadores para código fuente

Para código fuente, podemos definir separadores que respeten la estructura del lenguaje:

# Separadores para código Python
python_separators = [
    "\n\nclass ",
    "\n\ndef ",
    "\n\n```",
    "\n```\n",
    "\n\n",
    "\n",
    " ",
    ""
]

code_splitter = RecursiveCharacterTextSplitter(
    separators=python_separators,
    chunk_size=1000,
    chunk_overlap=100
)

Configuración adaptativa según el contenido

Para sistemas RAG que procesan múltiples tipos de documentos, podemos implementar una estrategia adaptativa:

def create_adaptive_splitter(content: str) -> RecursiveCharacterTextSplitter:
    """Crea un splitter adaptado al tipo de contenido"""
    
    has_code = '```' in content or 'def ' in content
    has_markdown = content.count('#') > 2
    
    if has_code:
        separators = ["\n\nclass ", "\n\ndef ", "\n\n", "\n", " ", ""]
        chunk_size = 1000
        overlap = 100
        
    elif has_markdown:
        separators = ["\n## ", "\n### ", "\n\n", "\n", ". ", " ", ""]
        chunk_size = 800
        overlap = 80
        
    else:
        separators = ["\n\n", "\n", ". ", " ", ""]
        chunk_size = 700
        overlap = 70
    
    return RecursiveCharacterTextSplitter(
        separators=separators,
        chunk_size=chunk_size,
        chunk_overlap=overlap
    )

# Uso del splitter adaptativo
adaptive_splitter = create_adaptive_splitter(markdown_content)
adaptive_chunks = adaptive_splitter.split_text(markdown_content)

Esta aproximación estructural al chunking es especialmente valiosa cuando trabajamos con documentación técnica, manuales de usuario, artículos académicos o cualquier contenido que siga una jerarquía clara.

En la siguiente lección aprenderemos sobre embeddings, que nos permitirán convertir estos chunks de texto en representaciones vectoriales para realizar búsquedas semánticas.

Fuentes y referencias

Documentación oficial y recursos externos para profundizar en LangChain

Documentación oficial de LangChain
Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, LangChain es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de LangChain

Explora más contenido relacionado con LangChain y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

Usar HTMLHeaderTextSplitter para documentos HTML preservando estructura de encabezados, trabajar con MarkdownHeaderTextSplitter para documentación Markdown, entender cómo preservar contexto jerárquico, y aplicar estrategias de chunking inteligentes según el tipo de documento.

Cursos que incluyen esta lección

Esta lección forma parte de los siguientes cursos estructurados con rutas de aprendizaje