chunkwise
Token-aware, boundary-respecting text and document chunking for RAG ingestion.
Part of the ragkit suite. Install with
pip install ragkit-chunkwise, thenimport chunkwise.
Naive character slicing shreds sentences and paragraphs and ignores model token
limits. chunkwise splits text along real structural boundaries (paragraphs →
lines → sentences → words → characters), packs the pieces up to a token budget,
and carries a configurable overlap between chunks — so your retrieval index gets
clean, self-contained passages instead of arbitrary fragments.
- Pure Python standard library at runtime. No required third-party dependencies.
- Python 3.8+.
- Pluggable token counting — plug in
tiktoken, a HuggingFace tokenizer, or anycallable(str) -> int. - Accurate character offsets back into the original text.
Install
pip install ragkit-chunkwise
Optional tokenizer extra (pulls in tiktoken):
pip install "ragkit-chunkwise[tokenizers]"
Local development (from chunkwise/):
pip install -e .
Quick Start
from chunkwise import chunk_text
paragraph = (
"Retrieval-augmented generation grounds a language model in your own data. "
"You first split documents into chunks, embed them, and store the vectors. "
"At query time you retrieve the most relevant chunks and feed them to the model."
)
for c in chunk_text(paragraph, chunk_size=15, chunk_overlap=4):
print(c.index, c.token_count, repr(c.text))
Each result is a Chunk with the text, its position, character offsets, and a
token count.
The effect of chunk_size and chunk_overlap
chunk_size is the maximum length of a chunk, measured by your
length_function (words by default). chunk_overlap is how much of the tail of
one chunk is repeated at the head of the next — overlap preserves context that
would otherwise be cut off at a boundary, which improves retrieval recall.
from chunkwise import RecursiveChunker
text = " ".join(f"word{i}" for i in range(60))
# Bigger chunks, no overlap → fewer, disjoint chunks.
print(len(RecursiveChunker(chunk_size=30, chunk_overlap=0).split_text(text))) # ~2
# Smaller chunks with overlap → more chunks that share context.
print(len(RecursiveChunker(chunk_size=15, chunk_overlap=5).split_text(text))) # more
chunk_overlap must be strictly less than chunk_size or a ValueError is
raised.
API Reference
RecursiveChunker
RecursiveChunker(
chunk_size=512,
chunk_overlap=64,
separators=None, # default: ["\n\n", "\n", ". ", " ", ""]
length_function=word_token_counter,
keep_separator=True,
)
Recursively splits text using an ordered list of separators, trying the largest
structural boundary first. If a piece still exceeds chunk_size, it recurses
with the next separator; the final "" separator splits by characters as a last
resort. Adjacent small pieces are greedily merged up to chunk_size, and
chunk_overlap tokens from the previous chunk's tail are carried forward.
Methods:
.split_text(text) -> List[str]— return chunk strings..chunk(text, metadata=None) -> List[Chunk]— returnChunkobjects with accurate character offsets, token counts, sequential indexes, andmetadatamerged into each chunk.
chunk_text(text, chunk_size=512, chunk_overlap=64, **kwargs) -> List[Chunk]
Convenience wrapper around RecursiveChunker. Extra keyword arguments
(separators, length_function, keep_separator) are forwarded to the
chunker. An optional metadata= keyword is attached to every chunk.
SentenceChunker
SentenceChunker(chunk_size=512, chunk_overlap=64, length_function=word_token_counter)
Splits text into sentences with a lightweight regex (handles ., !, ?
followed by whitespace or end-of-string), then packs whole sentences into chunks
up to chunk_size with sentence-level overlap. Sentences are never cut mid-way.
Exposes .split_text(text) and .chunk(text, metadata=None).
chunk_markdown(text, chunk_size=512, chunk_overlap=64, length_function=word_token_counter) -> List[Chunk]
Splits markdown into sections at headings (lines starting with #). The trail of
active headings (outermost → innermost) is attached to each chunk's metadata
under the "headings" key, and oversized sections are further split with
RecursiveChunker.
from chunkwise import chunk_markdown
md = "# Guide\nIntro.\n\n## Setup\nInstall the package and configure it."
for c in chunk_markdown(md, chunk_size=50):
print(c.metadata["headings"], "->", repr(c.text))
# ['Guide'] -> '# Guide\nIntro.\n'
# ['Guide', 'Setup'] -> '## Setup\nInstall the package and configure it.'
Custom length_function
Any callable(str) -> int works. Built-ins:
word_token_counter(text)— whitespace-split word count (default).char_token_counter(text)—len(text).
To chunk by real model tokens, plug in a tokenizer:
import tiktoken
enc = tiktoken.get_encoding("cl100k_base")
from chunkwise import RecursiveChunker
chunker = RecursiveChunker(
chunk_size=256,
chunk_overlap=32,
length_function=lambda t: len(enc.encode(t)),
)
chunks = chunker.chunk(my_document)
The Chunk dataclass
| Field | Type | Meaning |
|---|---|---|
text |
str |
The chunk text. |
index |
int |
Position in the output sequence (0-based). |
start |
int |
Character offset of the chunk's primary span in the original. |
end |
int |
End character offset (exclusive). |
token_count |
int |
Length of text per the length_function. |
metadata |
dict |
User metadata (defaults to {}). |
len(chunk) returns token_count.
Offsets and overlap: for RecursiveChunker (and the sentence/markdown
chunkers built on the same logic), original_text[chunk.start:chunk.end] == chunk.text holds even when overlap is used — successive chunks simply share an
overlapping character range. start/end always describe the contiguous
primary span a chunk covers.
Design notes / correctness
- No chunk exceeds
chunk_sizeby more than a single indivisible unit (e.g. one very long word or a single sentence longer than the budget). - Empty or whitespace-only input returns
[]. - Overlap never produces an infinite loop; an indivisible piece larger than the budget is isolated rather than re-seeding subsequent chunks.
Running the tests
python -m unittest discover -s tests -v
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ragkit_chunkwise-0.1.0.tar.gz.
File metadata
- Download URL: ragkit_chunkwise-0.1.0.tar.gz
- Upload date:
- Size: 13.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b67abeeadf0b9a3a2880358e6df9f1687f3a18ae50018e1689686671d6f991d9
|
|
| MD5 |
fef68a820c9e582ee2cd65f364b4a4ea
|
|
| BLAKE2b-256 |
5e82964af041014d38ccc403d92a183f3a05c9e391e2f72c7fa4c92e396f0df8
|
Provenance
The following attestation bundles were made for ragkit_chunkwise-0.1.0.tar.gz:
Publisher:
publish.yml on Meet2147/pythonLibraries
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ragkit_chunkwise-0.1.0.tar.gz -
Subject digest:
b67abeeadf0b9a3a2880358e6df9f1687f3a18ae50018e1689686671d6f991d9 - Sigstore transparency entry: 2244313045
- Sigstore integration time:
-
Permalink:
Meet2147/pythonLibraries@6fde7a37ee929e2e8cfd85031d173ee2d3bb73a2 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Meet2147
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6fde7a37ee929e2e8cfd85031d173ee2d3bb73a2 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file ragkit_chunkwise-0.1.0-py3-none-any.whl.
File metadata
- Download URL: ragkit_chunkwise-0.1.0-py3-none-any.whl
- Upload date:
- Size: 9.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a125f8ab63091006de739bee68ac9e8ea899e33d016bc64df5aa1d4b32764201
|
|
| MD5 |
35684dbb2d62a943f5bed93f3fd0d1a6
|
|
| BLAKE2b-256 |
438dd4d0beb76861cfffce9f80f193d642deac347374ae325aca4f116bad73c0
|
Provenance
The following attestation bundles were made for ragkit_chunkwise-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on Meet2147/pythonLibraries
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ragkit_chunkwise-0.1.0-py3-none-any.whl -
Subject digest:
a125f8ab63091006de739bee68ac9e8ea899e33d016bc64df5aa1d4b32764201 - Sigstore transparency entry: 2244313842
- Sigstore integration time:
-
Permalink:
Meet2147/pythonLibraries@6fde7a37ee929e2e8cfd85031d173ee2d3bb73a2 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Meet2147
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6fde7a37ee929e2e8cfd85031d173ee2d3bb73a2 -
Trigger Event:
workflow_dispatch
-
Statement type: