Exercices Projets guidés Decouper en chunks avec LangChain
🎉

Bravo!

Intermédiaire 🧠 Fondamentaux 20 XP 0 personnes ont réussi

Decouper en chunks avec LangChain

Tu as tes documents charges, mais certains font 50 pages. Si tu envoies un document entier au LLM comme contexte, deux problemes : ca coute cher en tokens, et le modele se noie dans trop de texte. Il va rater l'info pertinente, perdue au milieu d'un pave.

La solution : decouper les documents en petits morceaux (chunks). Chaque chunk fait quelques centaines de caracteres. Quand l'utilisateur pose une question, tu cherches les 3 ou 4 chunks les plus pertinents au lieu d'envoyer tout le document. C'est le coeur du RAG : Retrieval Augmented Generation.

LangChain fournit un outil parfait pour ca : le RecursiveCharacterTextSplitter. Il decoupe intelligemment en essayant de couper aux paragraphes d'abord, puis aux phrases, puis aux mots. Ca evite de couper un mot en deux.

Installe LangChain :

pip install langchain

Le splitter fonctionne comme ca :

from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
)
morceaux = splitter.split_text("Un tres long texte...")

Le chunk_overlap, c'est le chevauchement entre les morceaux. Si un chunk finit par "la procedure de conge" et le suivant commence par "de conge necessite un formulaire", le chevauchement garantit qu'on ne perd pas le contexte a la frontiere.

Ecris une fonction decouper_documents(documents, chunk_size=500, chunk_overlap=50) qui prend une liste de documents (au format de l'exercice precedent : dicts avec "contenu" et "source") et renvoie une liste de chunks. Chaque chunk est un dictionnaire avec les cles "texte" (le contenu du morceau), "source" (le nom du fichier d'origine) et "index" (le numero du chunk dans le document, en partant de 0).

Pour que les tests marchent dans le sandbox (sans LangChain), si LangChain n'est pas disponible, decoupe le texte toi-meme en morceaux de chunk_size caracteres avec un chevauchement de chunk_overlap.

Exemple :

documents = [
{"contenu": "A" * 1200, "source": "doc.txt", "nb_caracteres": 1200}
]
chunks = decouper_documents(documents, chunk_size=500, chunk_overlap=50)
# Devrait donner 3 chunks de tailles ~500, ~500, ~200+

chunks[0]["source"] # "doc.txt"
chunks[0]["index"] # 0
chunks[1]["index"] # 1

Tests (4/5)

Decoupe un document en chunks
docs = [{"contenu": "A" * 1200, "source": "test.txt", "nb_caracteres": 1200}]
chunks = decouper_documents(docs, chunk_size=500, chunk_overlap=0)
assert isinstance(chunks, list), "La fonction doit retourner une liste"
assert len(chunks) >= 2, f"1200 caracteres avec chunk_size=500 doit donner au moins 2 chunks, obtenu {len(chunks)}"
Chaque chunk a les bonnes cles
docs = [{"contenu": "Un texte assez long " * 50, "source": "doc.txt", "nb_caracteres": 950}]
chunks = decouper_documents(docs, chunk_size=200, chunk_overlap=0)
for chunk in chunks:
    assert "texte" in chunk, "Chaque chunk doit avoir une cle 'texte'"
    assert "source" in chunk, "Chaque chunk doit avoir une cle 'source'"
    assert "index" in chunk, "Chaque chunk doit avoir une cle 'index'"
La source est conservee
docs = [
    {"contenu": "Texte du premier document " * 30, "source": "premier.txt", "nb_caracteres": 780},
    {"contenu": "Texte du second document " * 30, "source": "second.md", "nb_caracteres": 750},
]
chunks = decouper_documents(docs, chunk_size=200, chunk_overlap=0)
sources = set(c["source"] for c in chunks)
assert "premier.txt" in sources, "La source premier.txt doit etre presente"
assert "second.md" in sources, "La source second.md doit etre presente"
Index commence a 0 pour chaque document
docs = [
    {"contenu": "A" * 600, "source": "a.txt", "nb_caracteres": 600},
    {"contenu": "B" * 600, "source": "b.txt", "nb_caracteres": 600},
]
chunks = decouper_documents(docs, chunk_size=500, chunk_overlap=0)
chunks_a = [c for c in chunks if c["source"] == "a.txt"]
chunks_b = [c for c in chunks if c["source"] == "b.txt"]
assert chunks_a[0]["index"] == 0, "L'index doit commencer a 0 pour chaque document"
assert chunks_b[0]["index"] == 0, "L'index doit recommencer a 0 pour le second document"

+ 0 tests cachés

Indices (3 disponibles)

solution.py