Expérimenter différentes stratégies de découpage via LangChain pour les applications LLM
Le chunking fait partie des problèmes les plus difficiles dans la création d’applications de retrieval-augmented generation (RAG). Le chunking est le processus de découpage des phrases en morceaux plus petits et gérables pour un traitement en aval. Bien que cela paraisse simple, le diable se cache dans les détails. Une stratégie de chunking mal choisie peut entraîner des résultats non pertinents ou incomplets, rendant plus difficile pour un système d’IA de fournir des réponses précises. Par exemple, des chunks trop petits peuvent manquer de contexte, tandis que des chunks trop grands peuvent renvoyer des informations non pertinentes.
Dans ce tutoriel, nous explorons comment différentes stratégies de chunking affectent les performances de récupération pour le même jeu de données ; en particulier, nous nous concentrerons sur un cas d’utilisation avec le chunking Langchain. À la fin de ce guide, vous comprendrez comment la taille des chunks et le chevauchement influencent la qualité de la récupération et obtiendrez des informations pratiques pour choisir les bons paramètres pour votre cas d’utilisation spécifique. Le code de cet article est disponible dans ce GitHub Repo on LLM Experimentation.
Présentation de LangChain et pourquoi le chunking est important
LangChain est un framework d’orchestration de Large Language Model avec des outils intégrés pour le chargement de documents et le découpage de texte. Sa flexibilité en fait un choix populaire pour créer des applications RAG, où le chunking joue un rôle essentiel dans la détermination de la pertinence et de l’exhaustivité des informations récupérées.
Le chunking implique de sélectionner deux paramètres principaux : un chunk donné, sa taille et son chevauchement.
Les tailles de chunk définissent le nombre de caractères ou de tokens dans chaque chunk. Les chunks plus grands capturent davantage de contexte mais risquent de renvoyer des informations non pertinentes, tandis que les chunks plus petits assurent la précision mais peuvent perdre le contexte nécessaire. Le chevauchement détermine la quantité de texte partagée entre des chunks consécutifs. Il aide à préserver la continuité, en particulier pour les idées liées entre paragraphes, mais un chevauchement excessif augmente la surcharge de traitement. L’optimisation de ces paramètres garantit un équilibre entre la capture du contexte et le maintien de la focalisation lorsque vous découpez le texte, deux éléments essentiels pour une récupération précise.
Les stratégies de chunking ont de nombreuses applications au-delà des workflows RAG. Elles sont cruciales dans les chatbots contextuels, qui s’appuient sur du texte chunké pour fournir des réponses concises mais complètes aux requêtes des utilisateurs. Par exemple, un bot de support peut utiliser le chunking pour diviser des guides de dépannage en étapes actionnables sans submerger l’utilisateur. De même, dans la construction de graphes de connaissances, le chunking extrait les entités et les relations du texte brut, aidant à transformer des documents non structurés en données structurées. Ces exemples montrent comment la bonne stratégie de chunking peut améliorer les tâches d’IA en aval.
Comprendre les défis d’un mauvais chunking
Une stratégie de chunking mal optimisée peut créer des problèmes importants dans la récupération. Des tailles de chunk vraiment petites manquent souvent de contexte suffisant, produisant des résultats fragmentés ou incomplets. Par exemple, une requête dans un manuel produit pourrait renvoyer des fragments isolés comme « Étape 1 : Allumez l’alimentation », sans information accompagnante sur les étapes suivantes. À l’inverse, lorsque votre application découpe le texte en chunks trop grands, cela peut diluer la spécificité des informations récupérées. Une requête de similarité sémantique qui attend des instructions de dépannage concises pourrait renvoyer une section entière, rendant plus difficile pour les utilisateurs d’identifier les détails pertinents.
Le chevauchement ajoute une autre couche de complexité. Sans chevauchement, les systèmes peuvent perdre la continuité de la pensée entre des chunks consécutifs, ce qui est essentiel pour des récits ou des processus liés. Cependant, un chevauchement excessif peut introduire de la redondance, augmentant les coûts de stockage et de traitement. Équilibrer ces compromis est essentiel pour garantir que les systèmes de récupération fournissent des réponses précises et exploitables.
Imports et configuration du code LangChain
Cette première section se concentre sur les imports et autres outils de configuration. La première chose que vous remarquez peut-être dans le code ci-dessous est qu’il y a BEAUCOUP d’imports. Les plus utilisés sont : os et dotenv, donc je ne les aborderai pas. Ils sont simplement utilisés pour vos variables d’environnement. Passons en revue le découpage de texte dans LangChain avec python et le client pymilvus.
En haut, vous verrez nos trois imports pour récupérer le doc. D’abord, il y a NotionDirectoryLoader, qui charge un répertoire contenant des docs markdown/Notion. Ensuite, nous avons les splitters de texte Markdown Header et Recursive Character. Ils découpent le texte dans le doc markdown en fonction des en-têtes (le header splitter), ou d’un ensemble de coupures de caractères présélectionnées (le recursive splitter).
Ensuite, nous avons les imports du retriever. Milvus est notre base de données vectorielle, OpenAIEmbeddings est notre modèle d’embedding, et OpenAI est notre LLM. Le SelfQueryRetriever est le retriever natif de LangChain qui permet à une base de données vectorielle de “s’interroger elle-même”. J’ai écrit davantage sur l’utilisation de LangChain pour interroger une base de données vectorielle dans cet article.
Notre dernier import LangChain est AttributeInfo, qui transmet un attribut avec des informations au self-query retriever, comme on peut le deviner. Enfin, je veux aborder les imports pymilvus. Ils sont strictement utilisés à des fins utilitaires ; nous n’en avons pas besoin pour travailler avec une base de données vectorielle dans LangChain. J’utilise ces imports pour nettoyer la base de données à la fin.
La dernière chose que nous faisons avant d’écrire la fonction est de charger nos variables d’environnement et de déclarer quelques constantes. La variable headers_to_split_on est essentielle - elle liste tous les en-têtes que nous nous attendons à voir et sur lesquels nous voulons effectuer le découpage dans le markdown. path indique simplement à LangChain où trouver les docs Notion.
import os
from langchain.document_loaders import NotionDirectoryLoader
from langchain.text_splitter import MarkdownHeaderTextSplitter, RecursiveCharacterTextSplitter
from langchain.vectorstores import Milvus
from langchain.embeddings import OpenAIEmbeddings
from langchain.llms import OpenAI
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain.chains.query_constructor.base import AttributeInfo
from pymilvus import connections, utility
from dotenv import load_dotenv
load_dotenv()
zilliz_uri = os.getenv("ZILLIZ_CLUSTER_01_URI")
zilliz_token = os.getenv("ZILLIZ_CLUSTER_01_TOKEN")
headers_to_split_on = [
("##", "Section"),
]
path='./notion_docs'
Créer une fonction d’expérimentation de chunking
Créer la fonction d’expérimentation est la partie la plus critique du tutoriel. Comme mentionné, cette fonction prend certains paramètres pour l’ingestion de documents et l’expérimentation. Nous devons fournir le chemin vers les docs, les en-têtes sur lesquels découper (splitters), la taille des chunks, le chevauchement maximal de taille des chunks, et indiquer si nous voulons ou non nettoyer en supprimant les collections à la fin. La suppression de collection est définie sur true par défaut
Si nous pouvons l’éviter, nous voulons créer et supprimer des collections aussi rarement que possible, car elles entraînent des surcoûts que nous pouvons éviter. Vous verrez peut-être le script évoluer à mesure que je chercherai de bonnes solutions de contournement.
Cette fonction est très similaire à celle que nous avons liée ci-dessus concernant l’utilisation de Notion avec LangChain. La première section charge le document depuis le chemin à l’aide du Notion Directory Loader. Notez que nous ne récupérons que le contenu html de la première page web (et n’avons qu’une seule page).
Ensuite, nous récupérons nos splitters. D’abord, nous utilisons le splitter markdown pour découper selon les en-têtes que nous avons indiqués ci-dessus. Ensuite, nous utilisons notre méthode de splitter récursif et découpons en fonction de la taille des chunks et du chevauchement.
C’est tout le découpage dont nous avons besoin. Une fois le découpage terminé, nous donnons un nom de collection et initialisons une instance LangChain Milvus en utilisant les variables d’environnement par défaut, les embeddings OpenAI, les splits et le nom de la collection. Nous créons également une liste de champs de métadonnées via l’objet AttributeInfo pour indiquer au retriever self-query que nous avons des « sections ».
Avec toute cette configuration, nous récupérons notre LLM, puis nous le passons à un retriever self-query Python. À partir de là, le retriever opère sa magie lorsque nous lui posons une question sur nos docs. Je l’ai également configuré pour nous indiquer quelle stratégie de chunking nous testons. Enfin, nous pouvons supprimer la collection si nous le souhaitons.
def test_langchain_chunking(docs_path, splitters, chunk_size, chunk_overlap, drop_collection=True):
path=docs_path
loader = NotionDirectoryLoader(path)
docs = loader.load()
md_file=docs[0].page_content
# Let's create groups based on the section headers in our page
markdown_splitter = MarkdownHeaderTextSplitter(headers_to_split_on=splitters)
md_header_splits = markdown_splitter.split_text(md_file)
# Define our text splitter
text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)
all_splits = text_splitter.split_documents(md_header_splits)
test_collection_name = f"EngineeringNotionDoc_{chunk_size}_{chunk_overlap}"
vectordb = Milvus.from_documents(documents=all_splits,
embedding=OpenAIEmbeddings(),
connection_args={"uri": zilliz_uri,
"token": zilliz_token},
collection_name=test_collection_name)
metadata_fields_info = [
AttributeInfo(
name="Section",
description="Part of the document that the text comes from",
type="string or list[string]"
),
]
document_content_description = "Major sections of the document"
llm = OpenAI(temperature=0)
retriever = SelfQueryRetriever.from_llm(llm, vectordb, document_content_description, metadata_fields_info, verbose=True)
res = retriever.get_relevant_documents("What makes a distinguished engineer?")
print(f"""Responses from chunking strategy:
{chunk_size}, {chunk_overlap}""")
for doc in res:
print(doc)
# this is just for rough cleanup, we can improve this
# lots of user considerations to understand for real experimentation use cases though
if drop_collection:
connections.connect(uri=zilliz_uri, token=zilliz_token)
utility.drop_collection(test_collection_name)
Tests et résultats LangChain
Très bien, voici maintenant la partie passionnante ! Regardons les tests et les résultats.
Code pour tester les chunks LangChain
Ce bref bloc de code ci-dessous montre comment nous pouvons exécuter notre fonction pour l’expérimentation. J’ai ajouté cinq expériences. Ce tutoriel teste des stratégies de chunking de 32 à 512 de longueur par puissances de 2, avec des chevauchements allant de 4 à 64 également par puissances de 2. Pour tester, nous parcourons la liste de tuples et appelons la fonction que nous avons écrite ci-dessus.
chunking_tests = [(32, 4), (64, 8), (128, 16), (256, 32), (512, 64)]
for test in chunking_tests:
test_langchain_chunking(path, headers_to_split_on, test[0], test[1])
Voici à quoi ressemble la sortie complète. Jetons maintenant un coup d’œil aux sorties individuelles. Souvenez-vous que notre question d’exemple choisie est : "What makes a distinguished engineer?"
Longueur 32, chevauchement 4
Bon, à partir de cela, nous pouvons clairement voir que 32 est trop court. Cette phrase est totalement inutile. « Est un Distinguished Engineer » est le raisonnement circulaire le plus évident possible.
Longueur 64, chevauchement 8
64 et 8 ne sont pas beaucoup mieux au départ. Cela nous donne toutefois un exemple de Distinguished Engineer. Werner Vogels, CTO d’Amazon.
Longueur 128, chevauchement 16
À 128, nous commençons à voir des phrases plus complètes. Moins de mots et de réponses du type « ingénieur. ». Ce n’est pas mauvais, cela parvient à extraire le passage sur Werner Vogel et « A accompli des réalisations techniques et professionnelles remarquables en travaillant comme ingénieur. » La dernière entrée provient en fait de la section principal engineer.
Un inconvénient ici est que nous voyons déjà apparaître des exemples de ces caractères spéciaux comme \xa0 et \n. Cela nous indique que nous allons peut-être trop loin dans la longueur des chunks.
Longueur 256, chevauchement 32
Je pense que cette longueur de chunking est clairement trop longue. Elle extrait les entrées requises, mais extrait aussi des entrées de « Fellow », « Principal Engineer » et « Senior Staff Engineer ». La première entrée vient toutefois de Distinguished Engineer, et elle couvre trois points à ce sujet.
Longueur de chunk 512, chevauchement 64
Nous avons déjà établi que 256 est probablement trop long. Cependant, la première extraction de ce 512 est en fait toute la section sur les distinguished engineers. Nous avons maintenant un dilemme : voulons-nous des « lignes » ou des « notes » individuelles, ou extraire une section entière ? Cela dépend de votre cas d’utilisation.
Résumé de l’expérimentation avec différentes stratégies de chunking
Super, donc, nous avons vu cinq stratégies différentes de text splitter avec une approche paramétrée qui met en évidence les stratégies de taille de chunks et de chevauchement de chunks dans ce tutoriel utilisant langchain chunking python. L’un des dilemmes que nous avons observés en appliquant simplement ces 5 stratégies de chunks est le choix entre récupérer des informations individuelles et récupérer une section entière, selon la taille du chunk. Nous avons vu que 128 était plutôt bon pour obtenir des « lignes » ou des « notes » individuelles sur les distinguished engineers, mais que 512 pouvait récupérer toute notre section.
Cependant, 256 n’était pas si bon.
Ces trois points de données nous apprennent quelque chose sur le text splitter. Ce n’est pas seulement qu’il est difficile de trouver une taille de chunks idéale. C’est aussi le signe que vous devez réfléchir à ce que vous attendez de vos réponses lorsque vous définissez vos tailles de chunks.
Notez que nous n’avons même pas encore commencé à tester différents chevauchements. Après avoir appris et mis au point une bonne stratégie de chunks, vérifier les chevauchements est l’étape logique suivante. Peut-être que nous l’aborderons dans un futur tutoriel, peut-être avec une autre bibliothèque. Restez connectés !
Enseignements tirés de l’expérimentation
Ces expériences mettent en évidence la relation nuancée entre la taille des chunks et le chevauchement. Les chunks plus petits excellent dans les tâches nécessitant une précision très ciblée, tandis que les chunks plus grands conviennent mieux aux questions exigeant un contexte étendu. Le chevauchement, quant à lui, joue un rôle essentiel dans l’équilibre entre ces objectifs.
Il convient de souligner que les compromis observés ici ne sont pas universels. Les paramètres de chunking idéaux dépendent fortement de votre cas d’utilisation spécifique. Les applications comme les agents conversationnels ou les outils de recherche rapide peuvent bénéficier de chunks plus petits pour des réponses précises. En revanche, les flux de travail axés sur la recherche, comme la synthèse de documents juridiques complexes, nécessitent des chunks plus grands afin de garantir un contexte complet.
Dans des scénarios réels, une approche hybride peut souvent fournir les meilleurs résultats. En ajustant dynamiquement la taille des chunks en fonction de la requête et de l’intention de l’utilisateur, les développeurs peuvent trouver un équilibre entre efficacité et qualité de récupération. De telles approches peuvent impliquer l’ajout de couches de routage intelligent des requêtes ou de pipelines de découpage adaptatifs adaptés aux besoins des utilisateurs.
Considérations futures
Les expériences menées dans ce tutoriel ne sont qu’un début. De futures explorations pourraient examiner des stratégies de découpage hiérarchique qui combinent différentes tailles de chunks pour une segmentation à plusieurs niveaux. De plus, l’extension à la récupération de données multimodales, comme la combinaison d’embeddings de texte et d’image, ouvre des possibilités pour des cas d’utilisation plus complexes.
Il existe également un potentiel dans l’expérimentation systématique des chevauchements afin de mieux comprendre comment ils influencent la récupération sur divers jeux de données. L’intégration d’autres frameworks aux côtés de LangChain pourrait affiner davantage les approches de découpage et révéler de nouvelles techniques d’optimisation. Par exemple, des frameworks comme Haystack offrent des capacités de récupération supplémentaires qui peuvent compléter le flux de travail de LangChain.
Enfin, l’intégration des retours utilisateurs dans le processus de récupération pourrait conduire à des systèmes adaptatifs qui apprennent et optimisent les stratégies de découpage au fil du temps. Avec des expérimentations plus finement ajustées, il est possible d’établir des pipelines RAG robustes et centrés sur l’utilisateur.
Conclusion
Le découpage est un composant indispensable des flux de travail de récupération dans les applications RAG. Ce tutoriel a démontré l’importance d’ajuster soigneusement la taille des chunks et le chevauchement, en montrant comment différentes stratégies influencent les résultats de récupération.
En équilibrant les compromis entre contexte et précision, les développeurs peuvent optimiser leurs systèmes pour une variété de cas d’utilisation. Bien que ce tutoriel ait couvert des expériences fondamentales, les possibilités d’exploration ultérieure sont vastes. Restez à l’écoute pour découvrir des tutoriels plus avancés et des analyses sur l’optimisation des systèmes de récupération alimentés par l’IA.
Références sur le découpage
Le découpage, ou les stratégies de text splitter, continuent d’évoluer, c’est pourquoi nous avons commencé à constituer une collection de ces différentes stratégies afin de les examiner et de les implémenter potentiellement dans votre application. Bonne lecture !
Un guide des stratégies de découpage pour la génération augmentée par récupération (RAG). Dans ce guide, nous avons exploré diverses facettes des stratégies de découpage au sein des systèmes de génération augmentée par récupération (RAG).
Guide du débutant sur le découpage et l’embedding de sites Web pour vos applications RAG. Dans cet article, nous expliquerons comment extraire du contenu d’un site Web et l’utiliser comme contexte pour les LLM dans une application RAG. Cependant, avant cela, nous devons comprendre les fondamentaux des sites Web.
Exploration de trois stratégies clés pour construire une génération augmentée par récupération (RAG) efficace. La génération augmentée par récupération (RAG) est une technique utile pour utiliser vos propres données dans un Chatbot alimenté par l’IA. Cet article de blog vous guidera à travers trois stratégies clés pour tirer le meilleur parti de RAG.
Pandas DataFrame : découpage et vectorisation avec Milvus. Si nous stockons toutes les données, y compris le texte du chunk et l’embedding, dans Pandas DataFrame, nous pouvons facilement les intégrer et les importer dans la base de données vectorielle Milvus.
Continuer à lire

Build Multimodal Search for 3D Assets with Tripo and Zilliz Cloud
Generate 3D assets with Tripo, then search them by text, image, and metadata with multimodal embeddings and Zilliz Cloud.

How Zilliz Ended Up at the Center of NVIDIA’s Unstructured Data Story at GTC 2026
If unstructured data is the context of AI, then the ceiling of AI applications will be set not just by models, but by how mature the infrastructure for unstructured data becomes.

Vector Databases vs. Hierarchical Databases
Use a vector database for AI-powered similarity search; use a hierarchical database for organizing data in parent-child relationships with efficient top-down access patterns.



