Chunking

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

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

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

Коротко

Коротко. Chunking — это разбиение длинных документов на фрагменты для индексации в RAG. Векторная база хранит каждый chunk отдельно и при запросе ищет близкие. Маленькие фрагменты точнее указывают место, но легче теряют контекст; большие сохраняют связность, но могут смешивать несколько тем. Размер и overlap выбирают по документам и тестовым вопросам.

Что это такое

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

Без chunking: загнать все 5000 страниц в context window LLM. Плюс это очень дорого.

С chunking:

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

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

  • 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 — максимальный объём фрагмента. Меньше — точнее место совпадения, но меньше соседнего контекста. Больше — наоборот.
  • chunk_overlap — пересечение соседних chunk'ов. Оно помогает сохранить мысль на границе, но увеличивает индекс и число почти одинаковых результатов.
  • 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", ". ", " "]
)

Для смешанных документов семантическое разбиение может быть полезно, но требует больше вычислений и отдельной проверки границ.

В 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.
  • «Overlap — только лишнее дублирование». Пересечение действительно увеличивает индекс, но иногда сохраняет ответ, оказавшийся на границе. Его пользу измеряют, а не предполагают заранее.
  • «Markdown-headers сохраняют сами себя в chunk'е». В большинстве библиотек headers нужно явно сохранять в metadata. Без этого теряется навигация.
  • «Один chunk_size подходит всем документам». FAQ, договор, исходный код и расшифровка разговора устроены по-разному, поэтому им могут понадобиться разные правила разбиения.
  • «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@k: для тестовых запросов проверяют, попадает ли нужный chunk в первые k результатов. Целевой уровень задают по риску задачи и сравнивают с простой базовой стратегией.

Зачем нужен overlap? Чтобы важная информация не потерялась на границе двух chunk'ов. Overlap позволяет связать.

Что такое late chunking? Один из подходов сначала кодирует документ с более широким контекстом, а затем получает представления отдельных фрагментов. Это может сохранить связь с соседними разделами, но требует совместимой модели и проверки retrieval на своём корпусе.

Можно ли вообще без chunking? Если документ помещается в окно модели, его можно передать целиком. Это не всегда лучший маршрут: большой вход дороже, медленнее и может размывать внимание. Chunking с retrieval полезен, когда нужны точные фрагменты, цитаты и частые обновления; для короткого связного документа полный контекст иногда проще.

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

Главное

Chunking разбивает длинные документы на фрагменты для поиска в RAG. Качество зависит от границ, размера, метаданных и того, как найденные куски собираются обратно в контекст. Для структурированного текста удобно сохранять заголовки и разделы, для смешанного корпуса может помочь семантическое разбиение. Универсального preset нет: варианты сравнивают по реальным вопросам, полноте поиска и качеству итоговых цитат.