0Pricing
AI Engineering Academy · Lección

Estrategias específicas para código y HTML

Aplique una división especializada al código Python mediante separadores de funciones basados en AST, al HTML mediante analizadores conscientes de las etiquetas y a Markdown mediante la jerarquía de encabezados.

Estrategias específicas para código y HTML es una lección gratuita de AI Engineering Academy en CoddyKit. Esta es la lección 4 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.

Por qué falla la fragmentación genérica en documentos especializados

La fragmentación basada en texto se diseñó para la prosa, pero los datos del mundo real incluyen código fuente, páginas HTML y documentación Markdown. Dividir el código en un límite fijo de caracteres puede cortar una función por la mitad de su cuerpo, lo que inutiliza el fragmento para la recuperación. Los documentos especializados necesitan fragmentadores que comprendan su estructura interna, no solo su longitud.

Fragmentación de código Python basada en AST

El árbol de sintaxis abstracta (AST) de un archivo Python representa cada función, clase y módulo como un nodo estructurado. Al recorrer el AST, puede extraer cada función o método como su propio fragmento, manteniendo unidos la firma, el docstring y el cuerpo. PythonCodeTextSplitter de LangChain utiliza este enfoque internamente.

import ast
import textwrap

def extract_functions(source_code: str) -> list[dict]:
    tree = ast.parse(source_code)
    chunks = []
    for node in ast.walk(tree):
        if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
            start = node.lineno - 1
            end = node.end_lineno
            lines = source_code.splitlines()[start:end]
            chunks.append({
                'name': node.name,
                'code': '\n'.join(lines),
                'start_line': node.lineno,
            })
    return chunks

Fragmentación por límites de clase

En las bases de código orientadas a objetos, fragmentar en el nivel de clase suele ser mejor que hacerlo en el nivel de función. Un fragmento de clase conserva la relación entre los métodos y el estado compartido sobre el que operan. Puede incluir el docstring de la clase y todos los cuerpos de sus métodos en un único fragmento, y después crear fragmentos independientes más detallados solo para los métodos largos.

from langchain_text_splitters import Language, RecursiveCharacterTextSplitter

python_splitter = RecursiveCharacterTextSplitter.from_language(
    language=Language.PYTHON,
    chunk_size=1000,
    chunk_overlap=100,
)

with open('my_module.py', 'r') as f:
    source = f.read()

chunks = python_splitter.create_documents([source])
print(f'Created {len(chunks)} code chunks')

Adición de metadatos de código a los fragmentos

Los fragmentos de código sin procesar solo son tan útiles como sus metadatos. Al almacenar fragmentos de código en una base de datos vectorial, incluya la ruta del archivo, el nombre de la función, el lenguaje de programación y el intervalo de líneas. Estos metadatos permiten al recuperador filtrar por lenguaje o archivo, y al LLM citar la ubicación exacta del código fuente en su respuesta.

from langchain_core.documents import Document

def chunk_python_file(filepath: str) -> list[Document]:
    with open(filepath) as f:
        source = f.read()

    functions = extract_functions(source)  # from previous example
    docs = []
    for fn in functions:
        docs.append(Document(
            page_content=fn['code'],
            metadata={
                'source': filepath,
                'function': fn['name'],
                'language': 'python',
                'start_line': fn['start_line'],
            }
        ))
    return docs

HTML: la estructura por encima de los caracteres

Los documentos HTML tienen una estructura jerárquica formada por encabezados, secciones, párrafos y listas. Dividir HTML por cantidad de caracteres suele cortar las etiquetas y producir fragmentos malformados. El enfoque adecuado consiste en analizar el HTML con un analizador apropiado, como BeautifulSoup, y extraer elementos con significado semántico, como las etiquetas <article>, <section> y <p>.

from bs4 import BeautifulSoup

def chunk_html_by_section(html: str) -> list[dict]:
    soup = BeautifulSoup(html, 'html.parser')
    chunks = []
    for tag in soup.find_all(['h1', 'h2', 'h3', 'p', 'li']):
        text = tag.get_text(separator=' ', strip=True)
        if len(text) > 40:  # skip trivial fragments
            chunks.append({
                'tag': tag.name,
                'text': text,
            })
    return chunks

Fragmentación jerárquica de HTML por encabezados

Una estrategia de HTML más sofisticada agrupa el contenido bajo su encabezado más cercano. Cada párrafo y lista que aparece después de un encabezado <h2> pertenece a esa sección. Al agrupar el texto con su encabezado principal, se conserva el contexto temático que un párrafo independiente perdería. HTMLHeaderTextSplitter de LangChain implementa este proceso automáticamente.

from langchain_text_splitters import HTMLHeaderTextSplitter

headers_to_split_on = [
    ('h1', 'Header 1'),
    ('h2', 'Header 2'),
    ('h3', 'Header 3'),
]

splitter = HTMLHeaderTextSplitter(headers_to_split_on=headers_to_split_on)

with open('page.html') as f:
    html = f.read()

sections = splitter.split_text(html)
for sec in sections[:3]:
    print(sec.metadata)
    print(sec.page_content[:200])
    print('---')

Markdown: respeto de la jerarquía de encabezados

La documentación Markdown se organiza mediante encabezados #, ## y ###. MarkdownHeaderTextSplitter divide el contenido en los límites de los encabezados y almacena la jerarquía de estos en los metadatos. Esto significa que cada fragmento conoce su ruta completa de encabezados, lo que mejora considerablemente la relevancia del contexto recuperado cuando los usuarios preguntan por secciones específicas de la documentación.

from langchain_text_splitters import MarkdownHeaderTextSplitter

headers_to_split_on = [
    ('#', 'H1'),
    ('##', 'H2'),
    ('###', 'H3'),
]

md_splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on)

with open('README.md') as f:
    markdown = f.read()

docs = md_splitter.split_text(markdown)
for doc in docs[:2]:
    print('Metadata:', doc.metadata)
    print('Content:', doc.page_content[:300])
    print()

División secundaria después de dividir por encabezados

Después de dividir por encabezados, algunas secciones individuales todavía pueden ser demasiado largas para el límite de tokens del modelo de incrustación. El patrón recomendado consta de dos pasos: primero, dividir según la jerarquía de encabezados para conservar el contexto semántico; después, aplicar un divisor basado en caracteres a cualquier sección que supere el límite de tamaño de los fragmentos. Así se garantiza que ningún fragmento sea demasiado grande sin perder los metadatos de los encabezados.

from langchain_text_splitters import MarkdownHeaderTextSplitter, RecursiveCharacterTextSplitter

header_splitter = MarkdownHeaderTextSplitter(
    headers_to_split_on=[('#', 'H1'), ('##', 'H2')]
)
char_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=50,
)

with open('docs.md') as f:
    md = f.read()

header_chunks = header_splitter.split_text(md)
final_chunks = char_splitter.split_documents(header_chunks)
print(f'{len(final_chunks)} final chunks produced')

Fragmentación de PDF con reconocimiento de tablas

Los PDF extraídos con herramientas como PyMuPDF o pdfplumber suelen perder la estructura de las tablas y producir filas de texto desordenadas. Para resolverlo, utilice analizadores de PDF que tengan en cuenta el diseño, detecten los límites de las tablas y las conviertan a formato Markdown o CSV antes de fragmentarlas. Trate cada tabla como un único fragmento con metadatos estructurados que la identifiquen como tabla y no como prosa.

import pdfplumber

def extract_pdf_chunks(pdf_path: str) -> list[dict]:
    chunks = []
    with pdfplumber.open(pdf_path) as pdf:
        for page_num, page in enumerate(pdf.pages):
            # Extract tables separately
            for table in page.extract_tables():
                rows = ['|'.join(str(c) for c in row) for row in table]
                chunks.append({
                    'type': 'table',
                    'content': '\n'.join(rows),
                    'page': page_num + 1,
                })
            # Extract prose text
            text = page.extract_text()
            if text:
                chunks.append({'type': 'text', 'content': text, 'page': page_num + 1})
    return chunks

Detección de idioma para corpus mixtos

Las bases de conocimiento empresariales suelen combinar distintos tipos de archivo: scripts de Python, documentación de API en HTML, notas de arquitectura en Markdown y exportaciones de datos en CSV. Una canalización de fragmentación sólida debe detectar el tipo de archivo a partir de la extensión o del tipo MIME y dirigir cada documento al fragmentador especializado adecuado. Así se evita aplicar la lógica de división de código a la prosa, o viceversa.

from pathlib import Path

def route_document(filepath: str) -> list[dict]:
    ext = Path(filepath).suffix.lower()
    if ext == '.py':
        return chunk_python_file(filepath)
    elif ext in ('.html', '.htm'):
        with open(filepath) as f:
            return chunk_html_by_section(f.read())
    elif ext == '.md':
        # use MarkdownHeaderTextSplitter
        return chunk_markdown(filepath)
    elif ext == '.pdf':
        return extract_pdf_chunks(filepath)
    else:
        # fallback: plain text recursive splitter
        return chunk_plain_text(filepath)

Conservación del contexto mediante líneas circundantes

Al fragmentar código por función, suele ser útil incluir algunas líneas de contexto circundante, como las instrucciones de importación situadas al principio del archivo o la definición de la clase que contiene un método. Este contexto ayuda al LLM a comprender qué bibliotecas están disponibles y cuál es la función del método dentro de la clase general, lo que mejora la calidad de las respuestas generadas.

def chunk_with_imports(source_code: str, fn_node, lines: list[str]) -> str:
    # Gather top-of-file imports (first block before first non-import)
    import_lines = []
    for line in lines:
        stripped = line.strip()
        if stripped.startswith('import ') or stripped.startswith('from '):
            import_lines.append(line)
        elif stripped and not stripped.startswith('#'):
            break

    fn_body = '\n'.join(lines[fn_node.lineno - 1:fn_node.end_lineno])
    return '\n'.join(import_lines) + '\n\n' + fn_body

Comprobación rápida

Compruebe su comprensión de las estrategias de fragmentación específicas para documentos explicadas en esta lección.

Resumen de la lección

En esta lección ha aprendido que la fragmentación basada en AST conserva los límites de las funciones y clases de Python; HTMLHeaderTextSplitter y MarkdownHeaderTextSplitter respetan la jerarquía de encabezados para mantener el contexto junto a su sección; y un enfoque de dos pasos (división por encabezados seguida de división por caracteres) permite procesar secciones demasiado grandes sin perder los metadatos estructurales. A continuación exploraremos la búsqueda híbrida, que combina la recuperación densa y dispersa.

Preguntas frecuentes

¿La lección «Estrategias específicas para código y HTML» es gratis?

Sí — el texto completo de «Estrategias específicas para código y HTML» 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 «Estrategias específicas para código y HTML»?

Aplique una división especializada al código Python mediante separadores de funciones basados en AST, al HTML mediante analizadores conscientes de las etiquetas y a Markdown mediante la jerarquía de… 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 4 de 4.

¿Cuánto tiempo toma la lección «Estrategias específicas para código y HTML»?

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

  1. Por qué la división ingenua perjudica la recuperación
  2. División semántica con similitud de embeddings
  3. Recuperación padre-hijo y de pequeño a grande
  4. Estrategias específicas para código y HTML
← Volver a AI Engineering Academy