Skip to main content

chunkwise

PyPI Python versions License: MIT

chunkwise

Token-aware, boundary-respecting text and document chunking for RAG ingestion.

Part of the ragkit suite. Install with pip install ragkit-chunkwise, then import 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 any callable(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] — return Chunk objects with accurate character offsets, token counts, sequential indexes, and metadata merged 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_size by 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

ragkit_chunkwise-0.1.0.tar.gz (13.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ragkit_chunkwise-0.1.0-py3-none-any.whl (9.9 kB view details)

Uploaded Python 3

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

Hashes for ragkit_chunkwise-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b67abeeadf0b9a3a2880358e6df9f1687f3a18ae50018e1689686671d6f991d9
MD5 fef68a820c9e582ee2cd65f364b4a4ea
BLAKE2b-256 5e82964af041014d38ccc403d92a183f3a05c9e391e2f72c7fa4c92e396f0df8

See more details on using hashes here.

Provenance

The following attestation bundles were made for ragkit_chunkwise-0.1.0.tar.gz:

Publisher: publish.yml on Meet2147/pythonLibraries

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ragkit_chunkwise-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for ragkit_chunkwise-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a125f8ab63091006de739bee68ac9e8ea899e33d016bc64df5aa1d4b32764201
MD5 35684dbb2d62a943f5bed93f3fd0d1a6
BLAKE2b-256 438dd4d0beb76861cfffce9f80f193d642deac347374ae325aca4f116bad73c0

See more details on using hashes here.

Provenance

The following attestation bundles were made for ragkit_chunkwise-0.1.0-py3-none-any.whl:

Publisher: publish.yml on Meet2147/pythonLibraries

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page