Semantic-aware chunking with provenance tracking for production RAG and LLM data pipelines
Project description
chunkops
Semantic-aware chunking with provenance tracking for production RAG and LLM data pipelines.
pip install llm-chunk-optimizer
The problem
Every RAG system reinvents chunking from scratch. Existing tools (LangChain splitters, LlamaIndex nodes) are buried inside their frameworks, don't interop, and return plain strings with no provenance. When your pipeline gives a wrong answer three weeks after deploy, you have no way to trace which chunk caused it.
chunkops solves three things:
- Standalone chunking — works with any vector DB, any LLM, any framework
- Provenance — every
ChunkResultcarries a stable ID, character span, and lineage so you can trace any LLM output back to its exact source passage - Benchmarking — run 3–4 strategies on your actual corpus with one function call before committing
Installation
# Core — fixed, recursive, structural strategies + provenance + benchmark
pip install llm-chunk-optimizer
# Add semantic chunking (embedding-based topic boundaries)
pip install "llm-chunk-optimizer[semantic]"
# Everything + dev/test tools
pip install "llm-chunk-optimizer[dev]"
Import name vs install name
- Install name:
llm-chunk-optimizer - Import name:
chunkops
Dependencies
| Package | When required | Why |
|---|---|---|
tiktoken |
always | accurate token counting |
sentence-transformers |
chunkops[semantic] only |
semantic boundary detection |
numpy |
chunkops[semantic] only |
vector operations |
scikit-learn |
chunkops[semantic] only |
cosine similarity |
pytest |
chunkops[dev] only |
running tests |
Quick start
from chunkops import Chunker
chunker = Chunker(strategy="recursive", min_tokens=100, max_tokens=400)
chunks = chunker.chunk(text, doc_id="my_doc.txt")
for c in chunks:
print(c.id, c.token_count, c.span, c.text[:60])
Strategies
| Strategy | Best for | Speed | Quality |
|---|---|---|---|
fixed |
quick prototyping | fastest | poor — breaks sentences |
recursive |
most documents | fast | good — respects paragraphs |
structural |
markdown, wikis, docs | fast | great — uses headings |
semantic |
dense unstructured prose | slow | best — topic boundaries |
adaptive |
mixed corpora | fast | good — auto-selects |
# Semantic chunking (requires pip install chunkops[semantic])
chunker = Chunker(
strategy="semantic",
min_tokens=150, # prevents micro-fragments
max_tokens=512,
semantic_threshold=0.25,
embedding_model="all-MiniLM-L6-v2",
)
chunks = chunker.chunk(text, doc_id="paper.txt")
ChunkResult — provenance fields
chunk = chunks[0]
chunk.id # "3f8a1c9b2d41" — stable 12-char hash
chunk.doc_id # "my_doc.txt"
chunk.chunk_index # 0
chunk.span # (0, 712) — char offsets in original text
chunk.token_count # 142
chunk.strategy # ChunkStrategy.RECURSIVE
chunk.merged_from # [0, 1, 2] — sentence indices merged here
chunk.metadata # {"source": "arxiv", "year": 2017}
chunk.text # "The transformer architecture..."
ProvenanceStore
Trace any LLM output back to its exact source passage. Uses SQLite — zero infrastructure required.
from chunkops import ProvenanceStore
store = ProvenanceStore() # in-memory
store = ProvenanceStore("./prov.db") # persistent on disk
store.register(chunks)
# Later — your RAG pipeline cites a chunk_id
origin = store.trace("3f8a1c9b2d41")
print(origin.doc_id) # "my_doc.txt"
print(origin.span) # (0, 712)
print(origin.merged_from) # [0, 1, 2]
print(origin.text) # exact source passage
# All chunks from a document
doc_chunks = store.trace_doc("my_doc.txt")
# Stats
print(store.count()) # 487
print(store.docs()) # ["my_doc.txt", "paper2.txt", ...]
Benchmark
Find the best strategy for your corpus before committing.
from chunkops import benchmark
result = benchmark(
docs=[doc1, doc2, doc3],
strategies=["fixed", "recursive", "structural"],
metric="coherence", # or "chunk_count", "avg_tokens"
)
result.report()
# ── chunkops benchmark ──────────────────────────────────────────────────────
# docs: 3 metric: coherence best: recursive
# ────────────────────────────────────────────────────────────────────────────
# strategy chunks avg tok min max coherence breaks ms
# ────────────────────────────────────────────────────────────────────────────
# fixed 18 47.2 12 112 0.142 4 2.1
# * recursive 9 91.4 63 147 0.381 0 1.3
# structural 9 91.4 63 147 0.374 0 1.2
# ────────────────────────────────────────────────────────────────────────────
print(result.best_strategy) # "recursive"
print(result.best().avg_tokens)
BatchChunker
Process large corpora with concurrency and checkpoint/resume.
from chunkops import BatchChunker
bc = BatchChunker(
strategy="adaptive",
workers=8,
checkpoint="./ckpt/run_001", # crash at doc 80k → resume from 80k
min_tokens=150,
max_tokens=512,
)
results = bc.run(
docs_iterator, # iterable of (doc_id, text) tuples, or plain strings
on_progress=lambda n, t: print(f"{n}/{t} docs"),
)
# 10000/100000 docs
# 50000/100000 docs [checkpoint saved]
# KeyboardInterrupt → resume → 100000/100000 docs
# Total: 487,302 chunks
CLI
# Chunk a file
chunkops chunk my_doc.txt --strategy recursive --max-tokens 400
# Benchmark strategies on a file
chunkops bench my_doc.txt --strategies fixed,recursive,structural --metric coherence
RAG pipeline integration
from chunkops import Chunker, ProvenanceStore
# 1. Ingest
chunker = Chunker(strategy="recursive")
store = ProvenanceStore("./prov.db")
for doc_id, text in your_documents:
chunks = chunker.chunk(text, doc_id=doc_id)
store.register(chunks)
your_vector_db.upsert([
{"id": c.id, "vector": embed(c.text), "text": c.text}
for c in chunks
])
# 2. Query
results = your_vector_db.search(query, k=5)
# 3. Trace
for r in results:
origin = store.trace(r["id"])
print(f"Source: {origin.doc_id} span: {origin.span}")
Development
git clone https://github.com/yourusername/chunkops
cd chunkops
pip install -e ".[dev]"
pytest
Roadmap
-
LATEchunking strategy (late chunking / contextual retrieval) - LangChain
TextSplitteradapter - LlamaIndex
NodeParseradapter - Async
BatchChunker - Export provenance to Parquet / Arrow
- OpenTelemetry tracing integration
License
MIT
Project details
Release history Release notifications | RSS feed
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 llm_chunk_optimizer-0.1.2.tar.gz.
File metadata
- Download URL: llm_chunk_optimizer-0.1.2.tar.gz
- Upload date:
- Size: 22.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
767bcc9299229b5358dc3f3b3b8d0c13100dbbfd1e745ce9cc6d5704ff95b2a9
|
|
| MD5 |
ffdbbd2eeecc5003e807f8c57d20a86f
|
|
| BLAKE2b-256 |
2a02cabf2058ff80c50b98d5750de6544b5ec250a9148b423a034b67ff17fd31
|
File details
Details for the file llm_chunk_optimizer-0.1.2-py3-none-any.whl.
File metadata
- Download URL: llm_chunk_optimizer-0.1.2-py3-none-any.whl
- Upload date:
- Size: 20.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cf14c659a58a74b066cd51f874a68b5abdfd87dd5b00452382fcaace6a824d7e
|
|
| MD5 |
566dc4d108c9a238b4b8ea10d03aea0c
|
|
| BLAKE2b-256 |
4c0ea6cb95b79c62185ebf27ba366996ba76d151b9497338b1b00399e838cea8
|