Stratégies propres aux documents pour le code et HTML
Appliquez un découpage spécialisé au code Python à l’aide de séparateurs de fonctions fondés sur AST, à HTML à l’aide d’analyseurs tenant compte des balises et à Markdown à l’aide de la hiérarchie des en-têtes.
Stratégies propres aux documents pour le code et HTML est une leçon AI Engineering Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage AI Engineering Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours AI Engineering Academy comprend 4 leçons au total.
Pourquoi le découpage générique échoue avec les documents spécialisés
Le découpage fondé sur le texte a été conçu pour la prose, mais les données réelles comprennent du code source, des pages HTML et de la documentation Markdown. Découper du code à une limite fixe de caractères peut couper une fonction au milieu de son corps, rendant le segment inutile pour la récupération. Les documents spécialisés nécessitent des séparateurs qui comprennent leur structure interne, et pas seulement leur longueur.
Découpage du code Python fondé sur AST
L'arbre syntaxique abstrait (AST) d'un fichier Python représente chaque fonction, classe et module sous la forme d'un nœud structuré. En parcourant l'AST, vous pouvez extraire chaque fonction ou méthode dans son propre segment, en conservant ensemble sa signature, sa chaîne de documentation et son corps. Le PythonCodeTextSplitter de LangChain utilise cette approche en interne.
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 chunksDécoupage aux limites des classes
Pour les bases de code orientées objet, le découpage au niveau de la classe est souvent préférable au découpage au niveau de la fonction. Un segment de classe conserve la relation entre les méthodes et l'état partagé sur lequel elles agissent. Vous pouvez inclure la chaîne de documentation de la classe et tous les corps de méthode dans un seul segment, puis créer des segments plus fins pour les seules méthodes longues.
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')Ajouter les métadonnées du code aux segments
Les segments de code bruts ne sont utiles qu'à la mesure de leurs métadonnées. Lorsque vous stockez des segments de code dans une base de données vectorielle, incluez le chemin du fichier, le nom de la fonction, le langage de programmation et la plage de lignes. Ces métadonnées permettent au récupérateur de filtrer par langage ou par fichier, et au LLM de citer l'emplacement exact de la source dans sa réponse.
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 docsHTML : privilégier la structure aux caractères
Les documents HTML sont structurés hiérarchiquement avec des en-têtes, des sections, des paragraphes et des listes. Découper le HTML selon le nombre de caractères coupe souvent les balises, ce qui produit des fragments mal formés. La bonne approche consiste à analyser le HTML avec un analyseur adapté comme BeautifulSoup et à extraire des éléments sémantiquement significatifs tels que les balises <article>, <section> et <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 chunksDécoupage HTML hiérarchique par en-têtes
Une stratégie HTML plus sophistiquée regroupe le contenu sous son en-tête le plus proche. Chaque paragraphe et chaque liste qui suivent un en-tête <h2> appartiennent à cette section. En regroupant le texte avec son en-tête parent, vous préservez le contexte du sujet qu'un paragraphe isolé perdrait autrement. Le HTMLHeaderTextSplitter de LangChain implémente cela automatiquement.
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 : respecter la hiérarchie des en-têtes
La documentation Markdown est organisée à l'aide des en-têtes #, ## et ###. Le MarkdownHeaderTextSplitter découpe le contenu aux limites des en-têtes et stocke la hiérarchie des en-têtes dans les métadonnées. Ainsi, chaque segment connaît son chemin complet d'en-têtes, ce qui améliore considérablement la pertinence du contexte récupéré lorsque les utilisateurs posent des questions sur des sections précises de la documentation.
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()Découpage secondaire après le découpage par en-têtes
Après un découpage par en-têtes, certaines sections peuvent encore être trop longues pour la limite de jetons de votre modèle de représentation vectorielle. Le modèle recommandé se déroule en deux étapes : commencez par découper selon la hiérarchie des en-têtes afin de préserver le contexte sémantique, puis appliquez un séparateur fondé sur les caractères à toute section qui dépasse la limite de taille de vos segments. Vous vous assurez ainsi qu'aucun segment n'est trop grand, tout en préservant les métadonnées des en-têtes.
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')Découper les PDF en tenant compte des tableaux
Les PDF extraits avec des outils comme PyMuPDF ou pdfplumber perdent souvent la structure des tableaux, ce qui produit des lignes de texte incohérentes. Pour gérer ce problème, utilisez des analyseurs PDF tenant compte de la mise en page, capables de détecter les cadres des tableaux et de les convertir au format Markdown ou CSV avant le découpage. Traitez chaque tableau comme un seul segment, avec des métadonnées structurées indiquant qu'il s'agit d'un tableau et non de prose.
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 chunksDétection du langage pour les corpus mixtes
Les bases de connaissances d'entreprise mélangent souvent différents types de fichiers : scripts Python, documentation d'API en HTML, notes d'architecture en Markdown et exportations de données en CSV. Une chaîne de traitement de découpage robuste doit détecter le type de fichier à partir de son extension ou de son type MIME, puis orienter chaque document vers le séparateur spécialisé approprié. Cela évite d'appliquer une logique de découpage du code à de la prose, ou inversement.
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)Préserver le contexte avec les lignes environnantes
Lorsque vous découpez du code par fonction, il est souvent utile d'inclure quelques lignes de contexte environnant, comme les instructions d'importation en haut du fichier ou la définition de la classe qui contient une méthode. Ce contexte aide le LLM à comprendre quelles bibliothèques sont disponibles et quel est le rôle de la fonction au sein de la classe élargie, ce qui améliore la qualité des réponses générées.
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_bodyVérification rapide
Vérifiez votre compréhension des stratégies de découpage propres aux documents présentées dans cette leçon.
Récapitulatif de la leçon
Dans cette leçon, vous avez appris que le découpage fondé sur l'AST préserve les limites des fonctions et des classes Python, que HTMLHeaderTextSplitter et MarkdownHeaderTextSplitter respectent la hiérarchie des en-têtes afin de conserver le contexte avec sa section, et qu'une approche en deux étapes (découpage par en-têtes suivi d'un découpage par caractères) gère les sections trop volumineuses sans perdre les métadonnées structurelles. Nous allons maintenant étudier la recherche hybride combinant récupération dense et récupération creuse.
Questions Fréquemment Posées
La leçon « Stratégies propres aux documents pour le code et HTML » est-elle gratuite ?
Oui — le texte complet de « Stratégies propres aux documents pour le code et HTML » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours AI Engineering Academy, passe à CoddyKit PRO. Le cours AI Engineering Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Stratégies propres aux documents pour le code et HTML » ?
Appliquez un découpage spécialisé au code Python à l’aide de séparateurs de fonctions fondés sur AST, à HTML à l’aide d’analyseurs tenant compte des balises et à Markdown à l’aide de la hiérarchie de… Tu pratiques AI Engineering Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer AI Engineering Academy ?
Aucune expérience préalable n'est requise. AI Engineering Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.
Combien de temps prend la leçon « Stratégies propres aux documents pour le code et HTML » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon AI Engineering Academy ?
Oui. Chaque leçon AI Engineering Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Pourquoi le découpage naïf nuit à la recherche
- Découpage sémantique avec la similarité des plongements
- Recherche parent-enfant et du petit vers le grand
- Stratégies propres aux documents pour le code et HTML