LangGraph Tutorial (Python): chunking large documents for beginners
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-dotenvif you want to load env vars from a.envfile - •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
- •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,
}
- •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,
}
- •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
- •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,
}
- •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()inprocess_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
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
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