Report

A Russian RAG splitter that cuts documents by indices, not by rewriting the text

The story behind agmind-rag-splitter-ru: why a chunker that rewrites text is dangerous for RAG, how a LoRA fine-tune learned to return boundary indices as JSON, the training corpus published alongside it — and the honest gap between teacher agreement and retrieval quality.

lab_single_run internal research August 21, 2026 · Funding: Self-funded internal research

agmind-rag-splitter-ru is the lab’s document chunker for Russian RAG: a LoRA fine-tune of t-tech/T-lite-it-2.1 (a Qwen3-8B derivative) that reads a document pre-split into numbered units and answers with boundary indices plus a topic, as one small JSON object — never with rewritten text. It ships under Apache-2.0 with GGUF weights and, much rarer, with its training corpus published next to it. The full story is a Russian long-read on Habr, and that article is the primary source for every figure quoted here. This is the English companion: the same story, condensed, with the numbers marked as quotes from the article rather than registry claims.

Why is a splitter that rewrites text dangerous for RAG?

The obvious way to use an LLM as a chunker is to ask it to emit the chunks. The article’s case against that is simple: generation quietly “improves” the text. Cyrillic ё comes back as е, «guillemets» become straight quotes, whitespace normalizes — and occasionally a sentence comes back that the source never contained. For RAG these are not cosmetic defects. Chunks stop matching the document byte for byte, character offsets and citations break, and the retrieval index slowly fills with text nobody wrote. The second argument is cost: re-generating a whole document spends on the order of ten times the output tokens of naming its cut points — the splitter’s complete answer for a test document was 35 generated tokens of JSON .

How does cutting by indices work?

The host does the deterministic part. Prose is split into sentences with razdel.sentenize; tables and code blocks stay whole as single atomic units; markdown headers become units of their own. The model sees the numbered units and returns {"splits": [...], "topic": "..."}, where the indices mark chunk boundaries. The host then slices the original document at those indices, so every assembled chunk is a substring of the source by construction — the document’s text never passes through the model’s decoder. This is also how tables survive: a table is cut as one atomic unit as long as the upstream parser identified it correctly, where embedding-similarity splitters break tables mid-row because adjacent rows look alike and no topic-shift signal ever appears.

How was it trained?

The base model had to pass four filters: it runs under llama.cpp/Vulkan on AMD hardware without CUDA, tokenizes Cyrillic efficiently — the article cites 1.74 tokens per Russian word where Llama-2 spends 3.17 — carries an Apache-2.0 license, and has official GGUF builds. Training was bf16 LoRA with Unsloth on a single RTX 5090: rank 32, alpha 32, dropout 0.05, learning rate 2e-4 on a cosine schedule with 5% warmup, effective batch 16, two epochs — 2122 steps, about 3.5 hours, 25.4 GB peak VRAM . Loss was computed on the JSON response only, with the instruction and the document masked out.

What is in the open training corpus, and why publish it?

Nobody publishes the training data behind chunking models, which means nobody can check what a model learned to treat as a boundary. This one is inspectable. Labels were distilled from a self-hosted DeepSeek-V4-Flash constrained by a guided_json grammar, then filtered through hard gates: valid JSON, sane boundary counts, minimum chunk lengths, topic-string sanity, index validity, exact deduplication. After filtering the corpus held about 17 thousand examples — 47% web and educational prose from cultura_ru_edu, 34% technical text with code from Habr, 19% synthetic tables and code — plus a 12-thousand-example synthetic top-up . The article also documents its own discrepancy rather than hiding it: the README claimed labeling ran at temperature 0 while the labeling code actually used 0.2 , acknowledged as-is, without a retroactive justification. The dataset carries license: other because of the Habr-sourced portion, and the article notes that as a limitation too.

What do the numbers honestly say?

On the N=300 holdout snapshot the bf16 model returned valid JSON on 100% of requests, with boundary-F1 of 0.656 at exact match and 0.821 within ±1 unit, and exact-set-match of 29% . The GGUF Q5_K_M build read 0.639 exact and 0.817 within ±1 . A full recheck on the 1500-document holdout put the two builds at 0.665/0.825 and 0.661/0.826 — a negligible quantization gap . On a Strix Halo box the Q5_K_M build split a nine-unit test document in about 1.2 seconds end to end, 317 prompt tokens in and 35 generated tokens out . The article’s own caveat is kept intact here, because it is the honest core of the piece: boundary-F1 against the teacher’s labels is teacher agreement, not proven RAG quality. No downstream hit-rate or faithfulness evaluation was run for v1, and the article says so in as many words.

Where does it still fail?

Four limitations, straight from the source. The metrics ceiling is the teacher: agreeing with DeepSeek’s labels is not the same as cutting well. The model over-segments slightly, likely inheriting the tendency from its distillation target. Very large tables are out of scope by design — no boundary decision fixes a table that exceeds the embedding budget, and the article routes those to table summaries with parent-document retrieval instead. And the whole scheme trusts the upstream parser: if a table arrives shredded, the splitter cannot un-shred it.

What changed in v2?

Since the article was published, the model’s v2 release raised the training set to 28 thousand examples across six source types and added a held-out reference set of 140 out-of-domain legal documents, labeled by consensus of two independent models with arbitration . The Habr long-read remains the story of v1 — the idea, the format and the first honest numbers; the identity of the current release lives on the artifacts page.

Where everything lives, and what this page is not

The primary source is the Habr long-read (Russian), with the full labeling pipeline, prompt format and evaluation code. The model, its GGUF builds and the training corpus are on Hugging Face. What this page is not: none of the numbers above are lab registry claims. They are quotes from the article — single-lab work, evaluated by its own author against its own teacher’s labels — and they keep the article’s caveats. What our registry-grade protocol would demand of them is a separate report.

Cite this report

AGmind Systems Lab (2026-08-21). A Russian RAG splitter that cuts documents by indices, not by rewriting the text. Evidence level: lab_single_run. https://agmind.ai/reports/russian-rag-splitter/
← Reports