0Pricing
AI Engineering Academy · Aula

Estratégias específicas para código e HTML

Aplique uma divisão especializada ao código Python usando separadores de funções baseados em AST, ao HTML usando analisadores conscientes de tags e ao Markdown usando a hierarquia de cabeçalhos.

Estratégias específicas para código e HTML é uma aula grátis de AI Engineering Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Engineering Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Engineering Academy inclui 4 aulas no total.

Por que a Divisão Genérica Falha em Documentos Especializados

A divisão baseada em texto foi projetada para prosa, mas os dados do mundo real incluem código-fonte, páginas HTML e documentação Markdown. Dividir o código em um limite fixo de caracteres pode cortar uma função no meio do seu corpo, tornando a parte inútil para a recuperação. Documentos especializados precisam de divisores que compreendam sua estrutura interna, não apenas seu tamanho.

Divisão de Código Python Baseada em AST

A árvore sintática abstrata (AST) de um arquivo Python captura cada função, classe e módulo como um nó estruturado. Percorrendo a AST, o senhor pode extrair cada função ou método como sua própria parte, mantendo juntos a assinatura, a docstring e o corpo. O PythonCodeTextSplitter do LangChain utiliza essa abordagem 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

Divisão pelos Limites das Classes

Para bases de código orientadas a objetos, dividir no nível da classe costuma ser melhor do que dividir no nível da função. Uma parte de classe mantém a relação entre os métodos e o estado compartilhado sobre o qual eles operam. O senhor pode incluir a docstring da classe e todos os corpos dos métodos em uma única parte e, depois, criar partes separadas e mais detalhadas apenas para métodos extensos.

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')

Adicionando Metadados de Código às Partes

As partes de código brutas são tão úteis quanto seus metadados. Ao armazenar partes de código em um banco de dados vetorial, inclua o caminho do arquivo, o nome da função, a linguagem de programação e o intervalo de linhas. Esses metadados permitem que o recuperador filtre por linguagem ou arquivo e que o LLM cite a localização exata da fonte em sua resposta.

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: Estrutura Acima dos Caracteres

Os documentos HTML têm uma estrutura hierárquica composta por títulos, seções, parágrafos e listas. Dividir HTML por quantidade de caracteres frequentemente corta as tags, produzindo fragmentos malformados. A abordagem correta é analisar o HTML com um analisador apropriado, como BeautifulSoup, e extrair elementos semanticamente significativos, como as tags <article>, <section> e <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

Divisão Hierárquica de HTML por Títulos

Uma estratégia de HTML mais sofisticada agrupa o conteúdo sob o título mais próximo. Cada parágrafo e lista que aparece depois de um título <h2> pertence àquela seção. Ao agrupar o texto com seu título pai, o senhor preserva o contexto do tópico que um parágrafo isolado perderia. O HTMLHeaderTextSplitter do LangChain implementa isso automaticamente.

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: Respeitando a Hierarquia dos Títulos

A documentação Markdown é organizada com títulos #, ## e ###. O MarkdownHeaderTextSplitter divide o conteúdo nos limites dos títulos e armazena a hierarquia dos títulos nos metadados. Isso significa que cada parte conhece seu caminho completo de títulos, o que melhora muito a relevância do contexto recuperado quando os usuários perguntam sobre seções específicas da documentação.

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()

Divisão Secundária Após a Divisão por Títulos

Depois da divisão por título, algumas seções ainda podem ser longas demais para o limite de tokens do seu modelo de incorporação. O padrão recomendado é uma divisão em duas etapas: primeiro, divida pela hierarquia de títulos para preservar o contexto semântico; em seguida, aplique um divisor baseado em caracteres a qualquer seção que exceda o limite de tamanho da parte. Isso garante que nenhuma parte seja grande demais, preservando os metadados dos títulos.

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')

Divisão de PDFs com Reconhecimento de Tabelas

PDFs extraídos com ferramentas como PyMuPDF ou pdfplumber frequentemente perdem a estrutura das tabelas, produzindo linhas de texto desordenadas. Para lidar com isso, use analisadores de PDF que reconheçam o layout, detectem os limites das tabelas e as convertam para o formato Markdown ou CSV antes da divisão. Trate cada tabela como uma única parte, com metadados estruturados que a identifiquem como tabela, e não 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

Detecção de Linguagem para Corpora Mistos

As bases de conhecimento empresariais frequentemente combinam diferentes tipos de arquivo: scripts Python, documentação de API em HTML, notas de arquitetura em Markdown e exportações de dados em CSV. Um pipeline robusto de divisão deve detectar o tipo de arquivo pela extensão ou pelo tipo MIME e encaminhar cada documento ao divisor especializado apropriado. Isso evita aplicar a lógica de divisão de código à prosa ou vice-versa.

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)

Preservando o Contexto com Linhas Circundantes

Ao dividir código por função, costuma ser útil incluir algumas linhas de contexto circundante, como instruções de importação no início do arquivo ou a definição da classe que contém um método. Esse contexto ajuda o LLM a entender quais bibliotecas estão disponíveis e qual é o papel da função dentro da classe mais ampla, melhorando a qualidade das respostas geradas.

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

Verificação Rápida

Teste sua compreensão sobre as estratégias de divisão específicas para documentos apresentadas nesta lição.

Recapitulação da Lição

Nesta lição, o senhor aprendeu que: a divisão baseada em AST preserva os limites de funções e classes Python; HTMLHeaderTextSplitter e MarkdownHeaderTextSplitter respeitam a hierarquia dos títulos para manter o contexto junto à sua seção; e uma abordagem em duas etapas (divisão por títulos seguida de divisão por caracteres) lida com seções grandes demais sem perder os metadados estruturais. Em seguida, exploraremos a busca híbrida, combinando recuperação densa e esparsa.

Perguntas Frequentes

A aula “Estratégias específicas para código e HTML” é grátis?

Sim — o texto completo de “Estratégias específicas para código e HTML” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Engineering Academy, atualize para CoddyKit PRO. O curso de AI Engineering Academy inclui 4 aulas no total.

O que vou aprender em “Estratégias específicas para código e HTML”?

Aplique uma divisão especializada ao código Python usando separadores de funções baseados em AST, ao HTML usando analisadores conscientes de tags e ao Markdown usando a hierarquia de cabeçalhos. Você pratica AI Engineering Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar AI Engineering Academy?

Nenhuma experiência prévia é necessária. AI Engineering Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Estratégias específicas para código e HTML”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de AI Engineering Academy?

Sim. Cada aula de AI Engineering Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Por que a divisão ingênua prejudica a recuperação
  2. Divisão semântica com similaridade de embeddings
  3. Recuperação pai-filho e do pequeno para o grande
  4. Estratégias específicas para código e HTML
← Voltar para AI Engineering Academy