Quick answer: Chunkers are tools that split long documents into smaller pieces ("chunks") so they can be embedded, indexed, and retrieved by AI systems. They exist because embedding models and retrieval work poorly on whole documents: a 50-page PDF embedded as one vector blurs everything it contains, while 200 well-chosen chunks each capture one idea that can be found precisely. The standard strategies are fixed-size splitting with overlap, recursive splitting on natural boundaries (paragraphs, then sentences), and structure-aware splitting on headings; recursive is the sensible default.
If you're building RAG, chunking is one of those unglamorous decisions that moves answer quality more than the choice of LLM. Here's how it works and how to not get it wrong.
Why Chunking Exists at All
Retrieval-augmented generation runs in two phases: embed your documents into vectors, then at question time find the most similar pieces and hand them to the model. Both phases force the size question.
Embed too big, and each vector is an average of many topics; the section about refunds and the section about shipping share one blurry vector, and neither is findable. Embed too small (single sentences), and each piece lacks the context to be understood ("It increased by 40%": what did?). Chunking is the art of cutting documents so each piece is one coherent, self-contained idea, big enough to mean something, small enough to be specific.
The Main Strategies
Fixed-size with overlap. Cut every N characters or tokens, with 10 to 20 percent overlap so sentences straddling a boundary survive in at least one chunk. Dumb, fast, and surprisingly serviceable. The failure mode is mid-sentence, mid-thought cuts.
Recursive splitting. The default in LangChain and most frameworks. Try to split on paragraph breaks first; if a piece is still too big, split on sentences; then words as a last resort. Same size targets as fixed, but the cuts land on natural seams:
from langchain_text_splitters import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, chunk_overlap=150,
separators=["\n\n", "\n", ". ", " "],
)
chunks = splitter.split_text(document)
Structure-aware splitting. Use the document's own organization: Markdown headings, HTML sections, PDF layout. A chunk becomes "everything under one H2," which tends to be exactly one topic, and the heading travels with the chunk as free context. When your source has real structure, this beats everything else.
Semantic chunking. Embed sentences, walk the document, and cut where the topic measurably shifts. Elegant, costs an embedding pass, and in practice the gains over structure-aware splitting are modest. Worth testing, not worth assuming.
The Settings That Actually Matter
Chunk size: 500 to 1,500 tokens is the working range for most retrieval; start around 1,000. Overlap: 10 to 20 percent. But two less-discussed choices matter as much:
Attach metadata to every chunk. Source URL, document title, section heading, date. The chunk "returns are accepted within 30 days" is dangerous without knowing which product and which year it describes. Metadata is also what makes citations possible later.
Never chunk raw HTML. If your documents come from the web, extract content before chunking. Raw HTML wastes most of your chunk budget on markup, and nav-bar fragments become retrievable "knowledge." Convert pages to Markdown first; this is precisely the pipeline link.sc's Fetch API feeds, and the token math is dramatic, as we showed in HTML to Markdown for LLMs. Markdown's structure (headings, lists) is also exactly what structure-aware chunkers key on, so clean input upgrades your chunking strategy for free.
A Web-to-RAG Pipeline, End to End
The standard 2026 shape, with the chunker in context:
import requests
from langchain_text_splitters import RecursiveCharacterTextSplitter
page = requests.post(
"https://api.link.sc/v1/fetch",
headers={"x-api-key": "YOUR_API_KEY"},
json={"url": "https://example.com/docs/guide", "format": "markdown"},
).json()
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=150)
chunks = [
{"text": c, "source": page["url"]}
for c in splitter.split_text(page["content"])
]
# embed chunks, store in your vector DB
Fetch clean, chunk on structure, embed with metadata. We walk the full architecture, retrieval included, in building RAG pipelines with real-time web data.
How to Know Your Chunking Is Bad
Skip the theory; look at the symptoms. Retrieval returns fragments that are true but unusable: chunking is too small. Answers cite the right document but miss the specific fact: too big. Retrieved chunks start mid-sentence: fixed-size without overlap. The model confidently describes your website's footer: you chunked raw HTML. Each symptom maps to exactly one fix above, which is what makes chunking such a satisfying thing to debug.
The Bottom Line
Chunkers turn documents into retrievable ideas. Default to recursive splitting around 1,000 tokens with 15 percent overlap, upgrade to structure-aware when your sources have headings, attach metadata always, and feed the chunker clean Markdown rather than raw HTML. Get those four right and you're ahead of most production RAG systems.
Clean, chunk-ready Markdown from any URL: start free with link.sc, 500 requests a month included.