Суть
LLM нельзя скормить весь корпус целиком — его режут на куски, каждый кусок → вектор (Embeddings) → индекс. Вопрос «как резать» нетривиален: граница чанка определяет, окажется ли нужный факт целиком в одном фрагменте или расколется пополам.
Зачем это нужно
Минимальный baseline («recursive chunking по знакам препинания») работает, но теряет смысл на сложных документах: чанк «Его цена 500 руб» не знает, что «его» = товар X из соседнего чанка (проблема анафор). Продвинутые техники чинят именно это.
Как работает (стратегии от простого к сложному)
- Fixed / Recursive — нарезка по фиксированному размеру или рекурсивно по разделителям (абзацы → предложения → знаки препинания). Baseline 2026.
- Semantic Chunking — границы по смысловым переходам (улучшает MRR, см. RAG Metrics).
- Adaptive Chunking — размер чанка подстраивается под структуру документа.
- Parent Document Retrieval (small-to-large): ищем по мелким чанкам (точность retrieval), а в LLM отдаём родительский крупный документ (полнота контекста). Context Precision +15-25%.
- Late Chunking (Jina AI, 2024): сначала прогоняем весь документ через embedding-модель (self-attention видит всё), потом режем на чанки со span pooling — каждый токен уже «знает» глобальный контекст. Без доп. LLM-вызовов, +10-12% retrieval accuracy.
- Contextual Retrieval (Anthropic, 2024): LLM дописывает к каждому чанку краткий контекст документа перед эмбеддингом. Решает анафоры, лучшая когерентность, но дорого (LLM-вызов на каждый чанк) — «для VIP-документов».
- Production-нюансы (общие, не RU-специфичные): «наивный» fixed 512/128 — не универсальный дефолт (рвёт предложения, отделяет вопрос от ответа). Practical: recursive (абзацы→предложения), semantic (граница там, где косинус между соседними предложениями падает ниже порога), structure-aware (AST для кода, пункты для юр.), parent-heading в каждый child-чанк. Оптимальный размер/overlap под русские документы — отдельный targeted research (см. fertility-прокси в Tokenization).
При сохранении чанков держим метаданные:
chunk_id,doc_id,title,url/путь(см. конвейер в RAG).
Пример
Parent Document Retrieval — два уровня чанкинга: поиск по мелким чанкам (точность), а в LLM отдаём крупный родительский документ (полный контекст). Метаданные (doc_id, title) держим на каждом child-чанке.
child_splitter = RecursiveCharacterTextSplitter(chunk_size=150, chunk_overlap=20)
parent_splitter = RecursiveCharacterTextSplitter(chunk_size=600, chunk_overlap=50)
parent_store = {} # doc_id -> полный текст (родитель)
for doc in DOCUMENTS:
parent_store[doc["id"]] = doc["content"]
for chunk in child_splitter.split_text(doc["content"]):
child_chunks.append(chunk) # child: точный поиск
child_metadatas.append({"doc_id": doc["id"], "title": doc["title"]})
chunk_size здесь считается в символах, а не в токенах — RecursiveCharacterTextSplitter по умолчанию меряет длину через len(). Поэтому 150 и 600 из примера нельзя сопоставлять с ориентирами таблицы ниже, которые даны в токенах: на русском 150 символов — это порядка сорока токенов, то есть в разы меньше, чем рекомендованные для child-чанка 200–400. Чтобы числа означали токены, сплиттер создают классметодом с явным энкодером — RecursiveCharacterTextSplitter.from_tiktoken_encoder(model_name="gpt-4", chunk_size=..., chunk_overlap=...); он рекурсивно дробит куски, пока каждый не уложится в лимит. Оговорка для русского корпуса: tiktoken считает по токенизатору OpenAI, а размер надо мерить по токенизатору своей embedding-модели — для неё берут from_huggingface_tokenizer. Расхождение молчаливое: код отработает и на символах, просто чанки окажутся мельче задуманного, а качество поиска просядет без единого сообщения об ошибке.
Ориентиры под русскоязычные документы
Отдельного «русского» правила нарезки нет — язык влияет на нарезку косвенно, через токенизацию: на русском один и тот же смысл занимает заметно больше токенов, чем на английском (Tokenization), поэтому чанк, отмеренный в символах, на русском окажется в токенах больше, чем ожидалось. Мерить размер надо в токенах целевой embedding-модели, а не в символах.
Практические ориентиры, встречающиеся в русскоязычных разборах (2026):
| Схема | Размер | Перекрытие |
|---|---|---|
| Плоская нарезка | 500-1500 токенов | около четверти от лимита при фиксированной нарезке |
| Семантическая | по границам смысла | 1-2 предложения в следующий чанк |
| Иерархическая (small-to-big) | child 200-400 токенов для поиска, parent 1500-2000 для передачи в модель | — |
Иерархическая схема здесь интереснее прочих именно на русском: искать удобно по коротким фрагментам, а в модель отдавать крупный кусок, потому что обрезанный по границе абзаца русский текст чаще теряет связность (согласование, отсылки местоимениями) сильнее, чем английский.
⚠️ Числа выше — ориентиры из практических разборов, а не измеренные оптимумы. Оптимальный размер зависит от embedding-модели, плотности знания в документе, его структуры и типа запросов, поэтому проверяется на своём корпусе тем же eval-набором, что и всё остальное (RAG Metrics).
Late Chunking или Contextual Retrieval
Оба приёма лечат одну болезнь — чанк, вырванный из контекста и потерявший смысл, — но платят за это по-разному.
Late Chunking дешёв: документ прогоняется через модель целиком, эмбеддинги чанков берутся из общего прохода, поэтому каждый несёт след соседей. Никакой дополнительной генерации не происходит. Ограничение прямое: документ должен помещаться в контекст embedding-модели, и приём не добавляет информации, которой в документе нет.
Contextual Retrieval дороже на порядок, потому что для каждого чанка модель пишет короткое пояснение о его месте в документе, — то есть на индексацию тратится генерация, умноженная на число чанков. Зато он добавляет то, чего в тексте чанка нет вовсе: к какому разделу относится, о каком объекте речь, когда местоимения и сокращения раскрываются только по документу.
Отсюда критерий: если потерянный контекст восстанавливается из соседних предложений — хватит Late Chunking; если он восстанавливается только из структуры документа — нужен Contextual Retrieval. Практический признак второго случая: таблицы, нумерованные разделы регламентов, документы, где половина чанков начинается с «в этом случае» и «он».
Связано с
- RAG — чанкинг = первый этап конвейера ingestion
- Embeddings — каждый чанк превращается в вектор
- Reranking — что делать с найденными чанками дальше
- RAG Metrics — как измерить, что чанкинг улучшил поиск