LangChain Hands-on · Module 2 · Lab 07

Text Splitters (Chunking)

⏱ 20 min + hands-on🎯 Beginner🖼 3 diagrams🧪 2 live demos🐍 Python code

A 200-page PDF cannot go into one prompt, and even if it could, searching it would be noisy. So we cut documents into small chunks first. The two numbers that matter are chunk_size (how big each piece is) and chunk_overlap (how much text repeats between pieces so a sentence is not cut in half). Play with both in the live playground below: it uses the same algorithm as LangChain.

In this session

  • Why split: limits, accuracy and cost
  • chunk_size and chunk_overlap
  • RecursiveCharacterTextSplitter: the default
  • Token, Markdown, HTML, code and JSON splitters
  • split_documents keeps metadata
  • Chunk size tips by data type

01The big idea: cutting a long train into coaches

🚆

Think of a long-distance train. You cannot lift the whole train, but each coach is easy to move, and each coach has a number (metadata) so you know where it belongs. Splitting cuts a document into coaches. The overlap is like the vestibule between coaches: a little shared space so nothing falls through the gap.

chunk 1chunk 2chunk 3overlapoverlap
Each chunk repeats a little of the previous one (amber), so a sentence on the boundary is still complete in at least one chunk.
Demo · Chunking playground (same algorithm as RecursiveCharacterTextSplitter)

Set chunk_overlap to 10, then try chunk_size 50, 100, 200 and 500: you get 12, 6, 4 and 1 chunks, exactly the numbers in the notebook. Paste your own text too.

02Which splitter?

RecursiveCharacterTextSplitter tries separators in order: paragraph \n\n → line \n → space → character. It only cuts smaller when a piece is still too big, so paragraphs and sentences stay together as much as possible.

"" (character)last resort" " (space)split words"\n" (line)split lines"\n\n" (paragraph)tried first
The recursive splitter’s ladder of separators, tried from the top.
DataSplitterTypical size
normal text / PDFRecursiveCharacterTextSplitter500–1000 chars, 10–20% overlap
strict token limitTokenTextSplitter (tiktoken)by tokens
Markdown docsMarkdownHeaderTextSplitter (+ recursive)by section
HTML pagesHTMLHeaderTextSplitterby heading
codeRecursiveCharacterTextSplitter.from_language(Language.PYTHON)by function / class
JSONRecursiveJsonSplitter(max_chunk_size=…)by key
Chunks too small• lose meaning (“3 days” of what?)• more chunks to search• answer spread over many piecesChunks too big• noisy search results• more tokens = more cost• useful line buried in junk
Start with 500–1000 characters and 10–20% overlap, then test with real questions.

03Hands-on: run it here

Same text and settings as the notebook, plus the NovaBank PDF from Lab 06. See how split_documents keeps the page metadata on every chunk, and how the code splitter keeps each function together.

lab07_splitters.py
from langchain_text_splitters import (CharacterTextSplitter, RecursiveCharacterTextSplitter, MarkdownHeaderTextSplitter, Language)
import warnings; warnings.filterwarnings("ignore")
from langchain_community.document_loaders import PyPDFLoader

text = """LangChain is a framework for building applications with large language models.
It provides tools for prompts, chains, memory, retrieval and agents.

RAG stands for Retrieval Augmented Generation. It lets the LLM answer from your own documents.
First we load documents, then split them into chunks, then create embeddings and store them in a vector database.

Agents use an LLM to decide which tool to call. Tools can be search engines, calculators or APIs."""

print("Character (\\n\\n, 200):", [len(c) for c in CharacterTextSplitter(separator="\n\n", chunk_size=200, chunk_overlap=20).split_text(text)])
chunks = RecursiveCharacterTextSplitter(chunk_size=120, chunk_overlap=20).split_text(text)
print(f"Recursive (120/20): {len(chunks)} chunks")
for i, c in enumerate(chunks[:4]): print(f"  {i} ({len(c)}) {c}")
for size in [50, 100, 200, 500]:
    print(f"  chunk_size={size:>3} -> {len(RecursiveCharacterTextSplitter(chunk_size=size, chunk_overlap=10).split_text(text))} chunks")


pages = PyPDFLoader("novabank_handbook.pdf").load()
docs = RecursiveCharacterTextSplitter(chunk_size=150, chunk_overlap=20).split_documents(pages)
print(f"\nPDF: {len(pages)} pages -> {len(docs)} chunks; chunk 4 keeps metadata page={docs[4].metadata['page']}:", docs[4].page_content[:70])

md = "# Python Course\n## Module 1: Basics\nVariables, data types and loops.\n## Module 2: OOP\nClasses, objects and inheritance.\n# GenAI Course\n## Module 1: LangChain\nPrompts, chains and agents."
for d in MarkdownHeaderTextSplitter(headers_to_split_on=[("#", "course"), ("##", "module")]).split_text(md):
    print("  md:", d.metadata, "->", d.page_content)

code = "class Calculator:\n    def add(self, a, b):\n        return a + b\n\n    def sub(self, a, b):\n        return a - b\n\ndef greet(name):\n    print(f\"Hello {name}\")\n"
for c in RecursiveCharacterTextSplitter.from_language(Language.PYTHON, chunk_size=80, chunk_overlap=0).split_text(code):
    print("  code chunk:", c.splitlines()[0], f"... ({len(c.splitlines())} lines)")
Character (\n\n, 200): [147, 208, 97] Recursive (120/20): 5 chunks 0 (78) LangChain is a framework for building applications with large language models. 1 (68) It provides tools for prompts, chains, memory, retrieval and agents. 2 (94) RAG stands for Retrieval Augmented Generation. It lets the LLM answer from your own documents. 3 (113) First we load documents, then split them into chunks, then create embeddings and store them in a vector database. chunk_size= 50 -> 12 chunks chunk_size=100 -> 6 chunks chunk_size=200 -> 4 chunks chunk_size=500 -> 1 chunks PDF: 3 pages -> 12 chunks; chunk 4 keeps metadata page=1: NovaBank Customer Handbook - UPI and payments The UPI limit for a new md: {'course': 'Python Course', 'module': 'Module 1: Basics'} -> Variables, data types and loops. md: {'course': 'Python Course', 'module': 'Module 2: OOP'} -> Classes, objects and inheritance. md: {'course': 'GenAI Course', 'module': 'Module 1: LangChain'} -> Prompts, chains and agents. code chunk: class Calculator: ... (3 lines) code chunk: def sub(self, a, b): ... (2 lines) code chunk: def greet(name): ... (2 lines)

TokenTextSplitter is in the notebook but not here: it downloads the tiktoken vocabulary the first time, which needs Colab’s internet.

04Hands-on: Ajeetkumar’s Colab notebook

Colab setup (same in every notebook): click 🔑 Secrets in the Colab sidebar, add groq_key with your free key from console.groq.com, switch on Notebook access, then run the cells from the top.
Demo · Notebook player · Lab 07

05Practice tasks

  1. Split the PDF with chunk_size 300 and 1500: compare the number of chunks.
  2. Split a markdown README by headers.
  3. Split a JavaScript file using Language.JS.

Try these in the same Colab notebook after you finish the lab. Change one thing at a time and look at the output again.

06Summary

07Quick quiz

1. Why use chunk_overlap?

2. Which separator does the recursive splitter try first?

3. Good starting size for PDF text?

4. Which splitter keeps Python functions together?

5. What does split_documents keep that split_text does not?

08References

Created by Ajeetkumar