Chunking

chunking — разбиение документов на фрагменты для RAG

Раздел
Языковые модели
Обновлено
18.05.26

Chunking — разбиение длинных документов на маленькие фрагменты (chunks) для индексации в RAG. От выбора размера и стратегии разбиения зависит качество поиска. Слишком маленькие chunks теряют контекст, слишком большие — теряют точность векторного поиска. Стратегии: фиксированные токены, по разделителям (абзац, заголовок), recursive, semantic. Главное правило — overlap 10–20% между chunk'ами.

Коротко

Коротко. Chunking — это разбиение длинных документов на маленькие фрагменты для индексации в RAG. Векторная база хранит каждый chunk отдельно; при запросе ищет похожие. Главные параметрыchunk_size (обычно 200–800 токенов) и chunk_overlap (10–20%). Маленькие chunks дают точный поиск, но теряют контекст. Большие — наоборот. Стратегии: fixed-size, recursive, semantic, по разделителям (заголовки, абзацы).

Что это такое

Команда строит RAG-ассистента поверх корпоративной wiki: 5000 страниц документации, 3 миллиона слов. Хочет, чтобы AI отвечал на вопросы пользователей со ссылками на конкретные страницы.

Без chunking: загнать все 5000 страниц в context window LLM. Невозможно — 3 миллиона слов = ~4 миллиона токенов, окно даже Gemini 2.0 Pro (2M токенов) не выдерживает. Плюс это очень дорого.

С chunking:

  1. Каждая страница режется на chunks по 500 токенов с overlap 50.
  2. Каждый chunk → вектор через embedding-модель.
  3. Векторы хранятся в БД.
  4. При запросе пользователя: его вопрос → вектор → поиск похожих → топ-5 chunks подгружаются как контекст в LLM.
  5. LLM отвечает по этим 5 chunk'ам (~2500 токенов вместо 4 миллионов).

Это и есть chunking — главный шаг подготовки данных для RAG. Качество всего pipeline сильно зависит от того, как документы разбиты.

К 2026-му стандартные стратегии:

  • Fixed-size token splitting — самый простой, по N токенов.
  • Recursive splitting — пробует разные разделители (абзацы → предложения → слова).
  • Markdown-aware — режет по заголовкам, оставляет иерархию.
  • Semantic chunking — определяет «смысловые границы» через embedding-similarity.
  • Late chunking — индексирует длинные документы целиком, потом ретриверит фрагменты на лету.

Как это работает

Базовый алгоритм fixed-size splitting:

def chunk_text(text, chunk_size=500, overlap=50):
    tokens = tokenize(text)
    chunks = []
    start = 0
    while start < len(tokens):
        end = start + chunk_size
        chunks.append(tokens[start:end])
        start = end - overlap  # overlap для контекста
    return chunks

Параметры:

  • chunk_size — главный. Обычно 200–800 токенов. Меньше — точнее поиск, но теряется контекст. Больше — наоборот.
  • chunk_overlap — пересечение между соседними chunk'ами. Обычно 10–20% от размера. Позволяет не потерять контекст на границе.
  • separators — список разделителей (для recursive splitting): ["\n\n", "\n", ". ", " ", ""]. Пробует по очереди.

Особый случай — markdown / code splitting. Для технической документации:

  • Markdown — режут по ## заголовкам, сохраняя heading-цепочку в metadata каждого chunk'а.
  • Code — режут по функциям/классам через AST-парсер.

Это значительно улучшает качество поиска — chunk «помнит», в каком разделе он находится.

Пример на практике

Разработчик строит ChatGPT-style ассистента для документации Stripe API. 200 000 слов в Markdown.

Попытка 1: fixed-size, chunk_size=500, overlap=0.

from langchain.text_splitter import TokenTextSplitter
splitter = TokenTextSplitter(chunk_size=500, chunk_overlap=0)
chunks = splitter.split_documents(docs)
# 487 chunks

Тест: «Как принимать платежи в евро?». Топ-1 chunk — середина какого-то абзаца, теряется контекст «в каком разделе мы». Качество ответа среднее.

Попытка 2: Markdown-splitting.

from langchain.text_splitter import MarkdownHeaderTextSplitter
splitter = MarkdownHeaderTextSplitter(headers_to_split_on=[
    ("#", "h1"), ("##", "h2"), ("###", "h3")
])
chunks = splitter.split_text(md)
# 312 chunks с metadata.h1/h2/h3

Тот же тест. Топ-1 chunk — секция «Currency Support → EUR». Metadata показывает breadcrumb «Payments → Currency → EUR». LLM знает, в каком контексте отвечает. Качество резко лучше.

Попытка 3: recursive + semantic enhancement.

from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
    chunk_size=500, chunk_overlap=80,
    separators=["\n## ", "\n### ", "\n\n", "\n", ". ", " "]
)

Лучшее качество для смешанных документов (markdown + код + plain).

В ComfyUI с RAG-нодами тоже есть chunking-параметры. Стандартные настройки обычно работают для большинства случаев, но для специфичных корпусов стоит подбирать.

С чем часто путают

  • Chunking и Tokenization — Tokenization режет на минимальные единицы (subwords). Chunking — на смысловые блоки (десятки-сотни токенов).
  • Chunk Size и Context Window — Chunk Size — размер одного индексируемого фрагмента. Context Window — общий бюджет LLM на всё (включая retrieved chunks).
  • Fixed-size и Recursive — Fixed-size режет каждые N токенов слепо. Recursive пробует естественные разделители.
  • Semantic Chunking и Semantic Search — Semantic Chunking определяет границы chunk'ов по смыслу. Semantic Search ищет в готовых chunk'ах.
  • Chunking и Reranking — Chunking — подготовка. Reranking — улучшение результатов после первого retrieval.

Частые ошибки и заблуждения

  • «Большие chunks всегда лучше — больше контекста». Не всегда. Embedding-модели лучше работают на коротких текстах (200–500 токенов). Большие chunks смешивают много тем — поиск становится менее точным.
  • «Overlap = дублирование данных, лишняя нагрузка». Дублирование минимальное (10–20%), но без overlap критичные ответы могут быть «разрезаны» границей chunk'а.
  • «Markdown-headers сохраняют сами себя в chunk'е». В большинстве библиотек headers нужно явно сохранять в metadata. Без этого теряется навигация.
  • «Один chunk_size подходит всем документам». Часто разные типы документов требуют разного chunking. FAQ — мелко (300), технические manuals — крупно (800).
  • «Semantic chunking всегда лучше». Не всегда. На структурированных markdown/code recursive может быть качественнее (быстрее и точнее).

Связанные термины

  • RAG — главный сценарий применения chunking.
  • Embedding — что делается с каждым chunk'ом.
  • Vector Database — где хранятся векторы chunk'ов.
  • Semantic Search — что использует chunked-данные.
  • Reranking — улучшение результатов после первого retrieval.
  • Context Window — общий бюджет LLM, ограничивающий, сколько chunks можно подгрузить.
  • LangChain / LlamaIndex — главные библиотеки с chunking-функциями.

Частые вопросы

Какой chunk_size оптимальный? Стартовая точка: 500 токенов, overlap 50. Для коротких текстов — 200/30. Для длинных technical docs — 800/100. Тестируйте на ваших данных.

Как измерять качество chunking? Через retrieval recall@5: для тестовых запросов проверяете, попадает ли «правильный» chunk в топ-5 по similarity. Цель — recall ≥ 90%.

Зачем нужен overlap? Чтобы важная информация не потерялась на границе двух chunk'ов. Пример: предложение «Цена $50» может оказаться в chunk N, контекст «для plan Pro» — в chunk N+1. Overlap позволяет связать.

Что такое late chunking? Новый подход (Jina AI 2024): сначала вычисляется длинный embedding для всего документа, потом «нарезается» на векторные фрагменты. Сохраняет глобальный контекст лучше.

Можно ли вообще без chunking? Если документ помещается в context window LLM (до 200K токенов) — можно подавать целиком. Но это дорого и медленно. Chunking + RAG почти всегда экономнее.

Какая библиотека для chunking? LangChain (text_splitter), LlamaIndex (NodeParser), Haystack (PreProcessor). Все имеют богатый набор стратегий.

Главное

Chunking — это разбиение длинных документов на фрагменты для индексации в RAG. Качество всего pipeline сильно зависит от стратегии разбиения. Главные параметры: chunk_size (200–800 токенов) и overlap (10–20%). Лучшие стратегии — recursive (с natural separators) и markdown-aware (сохраняет иерархию заголовков). Семантический chunking лучше для смешанных текстов, но медленнее. Универсального размера нет — для FAQ 200/30, для технических manuals 800/100. Проверяйте через retrieval recall@5 на ваших реальных запросах. Chunking — основа RAG: плохой chunking = плохой retrieval = плохой ответ.