Суть
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"]})
Связано с
- RAG — чанкинг = первый этап конвейера ingestion
- Embeddings — каждый чанк превращается в вектор
- Reranking — что делать с найденными чанками дальше
- RAG Metrics — как измерить, что чанкинг улучшил поиск
Открытые вопросы
- оптимальный размер чанка и overlap под русскоязычные документы
- когда Late Chunking достаточно, а когда нужен дорогой Contextual Retrieval