LangGraph Tutorial (Python): chunking large documents for beginners

By Cyprian AaronsUpdated 2026-04-22
langgraphchunking-large-documents-for-beginnerspython

This tutorial shows how to take a large document, split it into manageable chunks, and process those chunks with LangGraph in Python. You need this when a single document is too large for one model call, or when you want deterministic chunk-by-chunk processing for summarization, extraction, or classification.

What You'll Need

  • Python 3.10+
  • langgraph
  • langchain-core
  • langchain-text-splitters
  • python-dotenv if you want to load env vars from a .env file
  • An LLM API key if you plan to add model calls later, but this tutorial works without one
  • A large text file or any long string you want to chunk

Install the packages:

pip install langgraph langchain-core langchain-text-splitters python-dotenv

Step-by-Step

  1. Start by defining a simple graph state that holds the raw document, the generated chunks, and the current chunk index. For beginners, keep the state explicit so you can inspect every transition.
from typing import TypedDict, List
from langgraph.graph import StateGraph, START, END

class ChunkState(TypedDict):
    document: str
    chunks: List[str]
    current_index: int

def init_state(state: ChunkState) -> ChunkState:
    return {
        "document": state["document"],
        "chunks": [],
        "current_index": 0,
    }
  1. Next, split the document into overlapping chunks using LangChain’s text splitter. This is the part that makes large documents manageable without losing context between sections.
from langchain_text_splitters import RecursiveCharacterTextSplitter

def chunk_document(state: ChunkState) -> ChunkState:
    splitter = RecursiveCharacterTextSplitter(
        chunk_size=500,
        chunk_overlap=100,
    )
    chunks = splitter.split_text(state["document"])
    return {
        **state,
        "chunks": chunks,
        "current_index": 0,
    }
  1. Now add a node that processes each chunk one at a time. In real systems this is where you would summarize, extract entities, classify risk, or send the chunk to an LLM.
def process_chunk(state: ChunkState) -> ChunkState:
    idx = state["current_index"]
    chunk = state["chunks"][idx]
    print(f"\n--- Processing chunk {idx + 1}/{len(state['chunks'])} ---")
    print(chunk[:200].replace("\n", " "))
    return state
  1. Add a routing function so LangGraph knows whether to continue or stop. This is the core loop: move to the next chunk until you reach the end.
def route_next(state: ChunkState):
    next_index = state["current_index"] + 1
    if next_index < len(state["chunks"]):
        return "advance"
    return END

def advance_index(state: ChunkState) -> ChunkState:
    return {
        **state,
        "current_index": state["current_index"] + 1,
    }
  1. Wire everything into a LangGraph workflow and run it on a sample document. This gives you a reusable graph that can be dropped into a larger pipeline later.
builder = StateGraph(ChunkState)

builder.add_node("init_state", init_state)
builder.add_node("chunk_document", chunk_document)
builder.add_node("process_chunk", process_chunk)
builder.add_node("advance_index", advance_index)

builder.add_edge(START, "init_state")
builder.add_edge("init_state", "chunk_document")
builder.add_edge("chunk_document", "process_chunk")

builder.add_conditional_edges(
    "process_chunk",
    route_next,
    {
        "advance": "advance_index",
        END: END,
    },
)

builder.add_edge("advance_index", "process_chunk")

graph = builder.compile()

sample_doc = """
LangGraph is useful for building stateful applications.
When documents get large, you often need to split them into smaller parts.
Chunking helps control token usage and makes downstream processing more reliable.
""" * 20

result = graph.invoke({"document": sample_doc})
print("\nDone.")
print(f"Total chunks created: {len(result['chunks'])}")

Testing It

Run the script and confirm that it prints multiple chunk headers instead of trying to process the whole document at once. If your sample text is long enough, you should see Processing chunk 1/…, Processing chunk 2/…, and so on until completion.

A good sanity check is to change chunk_size and chunk_overlap and watch how the number of chunks changes. Smaller chunks should produce more iterations; larger overlap should make adjacent chunks share more text.

If you want to verify the graph behavior more deeply, print result["chunks"][0] and result["chunks"][-1] after execution. That tells you whether splitting worked as expected and whether your routing loop stopped correctly.

Next Steps

  • Replace print() in process_chunk() with an LLM call for summarization or extraction.
  • Add structured output per chunk using Pydantic models or JSON schema validation.
  • Persist chunk results in a database so you can resume processing after failures.

Keep learning

By Cyprian Aarons, AI Consultant at Topiax.

Want the complete 8-step roadmap?

Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.

Get the Starter Kit

Related Guides