TL;DR
- Для веб-краулеров RAG границы фрагментов должны следовать значению и структуре документа, прежде чем учитывать предел токенов.
- Заголовки Markdown хорошо подходят для документов; рекурсивное деление — практическое решение для длинных секций; семантические и родительско-дочерние подходы требуют отдельной оценки.
- Сохраняйте исходный URL, путь заголовка, версию и стабильные идентификаторы с каждым фрагментом, защищая кодовые блоки, таблицы и контекст конечных точек/параметров.
- Сравнивайте стратегии на одних и тех же страницах и наборах вопросов; этот проект предоставляет метод оценки, а не поддельные результаты бенчмаркинга.
Введение: Деление — часть дизайна поиска
Nstdata Crawl — это слой сбора в этом рабочем процессе; его обзор продукта описывает получение страниц и сайтов для последующих потоков данных.
Деление разделяет исходные документы на единицы, которые могут быть встроены и извлечены. Цель не в том, чтобы создать текстовые блоки одинакового размера. Цель состоит в том, чтобы сделать так, чтобы отрывок содержал достаточный контекст для ответа на вопрос, не включая не относящийся материал. Веб-страница с заголовком, таблицей API, образцом кода и подвалом не эквивалентна неструктурированному абзацу.
Хороший фрагмент RAG сохраняет информацию, необходимую для интерпретации отрывка: его заголовок, страницу, версию и часто предложение или блок кода рядом с ним. Плохой фрагмент может разделить конечную точку от ее параметров или повторять навигационный текст в каждом результате. Метод ниже сначала подготавливает чистый Markdown, затем сравнивает выборы фрагментов по одной и той же задаче поиска.
Что такое деление в RAG и почему это важно?
Извлекатель ищет фрагменты, а не весь исходный сайт. Если один фрагмент слишком широк, релевантное предложение конкурирует с не относящимся контентом и потребляет больше контекста. Если один фрагмент слишком узок, извлеченный термин может быть отделен от его определения, условия или примера. Это может снизить полезность извлечения, даже если исходная страница была захвачена правильно.
Деление не может восстановить отсутствующий контент. Если краулер не смог захватить таблицу, отрисованную клиентом, никакой разделитель не сможет ее восстановить. Используйте Crawl для получения и очистки страницы, затем проверьте структуру Markdown перед настройкой делителя. Руководство по Crawling от Nstdata документирует выходной Markdown для RAG и рабочих процессов агентов.
Почему контент, полученный через веб-краулер, требует учета структуры
Веб-контент включает в себя повторяющиеся заголовки и подвал, вложенные заголовки, образцы кода, таблицы, ссылки, уведомления и версии путей. Разделитель, работающий только с символами, не имеет понятия, что кодовый блок является лишь одним примером или что заголовок "Аутентификация" определяет область следующих абзацев. Нормализуйте общие элементы сначала, затем сохраните структуру страницы, несущую значение.
Шесть общих стратегий деления RAG
| Стратегия | Граница | Подходит | Стоимость или режим сбоя |
|---|---|---|---|
| Фиксированный размер | символы или токены | быстрое базовое решение | разделяет заголовки, примеры и списки |
| Рекурсивный | абзацы, строки, предложения | смешанная проза | порядок и перекрытие разделителей требуют настройки |
| Семантический | изменение значения между предложениями | проза с изменениями темы | дополнительная работа по встраиванию; чувствительный к порогам |
| Заголовок Markdown | секции H1/H2/H3 | технические документы и базы знаний | очень длинные секции требуют второго прохода |
| Родитель-дочерний | маленький дочерний, большой родитель | точное извлечение плюс более полный контекст | больше идентификаторов и логики извлечения |
| Контекстный/иерархический | секция плюс контекст документа | фрагментированные страницы или многоуровневые документы | добавленные токены и возможная инъекция контекста |
Это паттерны реализации, а не ранжирование. Правильный выбор зависит от вопросов, на которые ваша система должна ответить, и стоимости недостающего контекста.
Подготовьте Markdown перед его разбиением
Полезный порядок обработки: отклоните пустые или неудачные страницы, удалите дублирующую навигацию, которая выжила после извлечения, нормализуйте пробелы, сохраните иерархию заголовков/названий, затем разделите. Сохраните кодовые блоки, таблицы, ссылки, блоки предупреждений и пары методов/конечных точек в неповрежденном виде. Текущий выход Nstdata поддерживает Markdown и очищенный HTML; Markdown является практическим начальным форматом для извлечения текста, в то время как HTML может быть полезен, если требуется пользовательский разбор.
Избегайте отклонения секции просто потому, что она содержит короткий текст. Короткое предупреждение "Устарело" может быть более важным, чем длинный обзор. Добавьте валидацию для обнаружения пустых тел, повторяющихся хешей контента, не закрытых кодовых блоков и очень длинных секций, прежде чем они попадут в встраивание.
Шаг за шагом: реализуйте три стратегии на Python
Этот пример только со стандартной библиотекой предоставляет базовые решения фиксированного размера, рекурсивного и с учетом заголовков. Он предназначен для сравнения границ на образце Markdown; добавьте свой производственный токенизатор и тестовый набор перед индексацией реального контента.
import re def fixed_chunks(text: str, size: int = 1200, overlap: int = 150): if size <= 0 or not 0 <= overlap < size: raise ValueError("require 0 <= overlap < size") start = 0 while start < len(text): end = min(start + size, len(text)) yield text[start:end] if end == len(text): break start = end - overlap def recursive_chunks(text: str, size: int = 1200): parts = re.split(r"\n\n+|(?<=[.!?])\s+", text) chunks, current = [], "" for part in parts: candidate = f"{current}\n\n{part}" if current else part if len(candidate) > size and current: chunks.append(current) current = part else: current = candidate if current: chunks.append(current) return chunks def heading_chunks(markdown: str): path, lines, fenced = [], [], False for line in markdown.splitlines(): if line.strip().startswith("```"): fenced = not fenced if line.startswith("#") and not fenced and lines: body = "\n".join(lines).strip() if body: yield " / ".join(path), body level = len(line) - len(line.lstrip("#")) path = path[:level - 1] + [line[level:].strip()] lines = [line] else: lines.append(line) if lines: yield " / ".join(path), "\n".join(lines).strip()
Фиксированная версия измеряет количество символов, а не токенов модели. Рекурсивное разбиение использует границы параграфов и предложений, но все равно может разбить длинную таблицу. Разбиение заголовков сохраняет огражденные блоки, но может вывести раздел, который превышает лимит ввода вашей модели. Это базовые линии, которые вы можете запустить на образце, а не готовые гарантии для каждого диалекта Markdown.
Сравните границы частей в одном и том же документе
Используйте одну представительную страницу, содержащую прозу, многорядную таблицу, многострочный огражденный блок кода и как минимум три уровня заголовков. Для каждой стратегии запишите количество частей, приблизительное и фактическое распределение токенов, количество сохраненных огражденных блоков кода, количество частей с контекстом заголовка и коэффициент дубликатов. Исследуйте выбросы, а не сообщайте только о средних значениях.
Таблица сравнения может выглядеть следующим образом:
| Стратегия | Количество частей | Медианные / максимальные токены | Огражденные блоки нетронуты | Присутствует метаданные цитирования |
|---|---|---|---|---|
| Фиксированный размер | заполнить из запуска | заполнить из токенизатора | считать вручную | да/нет |
| Рекурсивный | заполнить из запуска | заполнить из токенизатора | считать вручную | да/нет |
| Сначала заголовок | заполнить из запуска | заполнить из токенизатора | считать вручную | да/нет |
Не заполняйте эту таблицу вымышленными контрольными числами. Запустите ее на вашем целевом корпусе и прикрепите версию скрипта и токенизатор к результату.
Как выбрать размер и перекрытие частей
Размер части взаимодействует с формой запроса, лимитом ввода модели встраивания, top-k, повторной ранговкой и контекстом генерации. Перекрытие может сохранить граничное предложение, но также создает повторяющийся текст, дублирующиеся результаты поиска, дополнительные затраты на встраивание и меньшую разнообразие результатов. Начните с частей, учитывающих заголовки; добавьте второе разбиение только для разделов, которые превышают лимит модели. Сравните небольшую сетку размеров и перекрытий, а не копируйте "лучшее" число из другого набора данных.
Полезные вопросы включают: "Какой заголовок аутентифицирует вызов?", "Какой параметр принимает список?", "Что означает ответ с ошибкой?", и вопрос, охватывающий два заголовка. Отслеживайте Recall@K или коэффициент попадания по маркированным доказательствам, MRR или ранг, корректность ответа, корректность цитирования и токены контекста. Держите сбои извлечения отдельно от сбоев генерации: модель не может цитировать относящийся фрагмент, который никогда не попал в top-k.
Обработка кода, таблиц, FAQ и иерархического контекста
Для кода сохраните огражденный блок и его метку языка. Если он слишком длинный, разделите на границах функции или примера и прикрепите ближайший заголовок плюс имя файла или языка. Для таблиц повторите строку заголовка в каждом разбиении и сохраняйте метку строки с ее значением. Записи FAQ часто могут быть одной парой вопрос-ответ на часть. Спецификации продуктов должны сохранять единицы и имена полей, прикрепленные к значениям.
Извлечение родительского-детского используется для сопоставления маленькой детской части и извлекает более крупный родительский раздел для генерации. Храните parent_id, child_id, source_url и heading_path. Контекстуальное разбиение может добавить заголовок документа или путь раздела к тексту перед встраиванием, но протестируйте, влияет ли этот дополнительный контекст на схожесть или дублирует общий заголовок на многих страницах.
Создание набора вопросов для оценки RAG
Создайте вопросы из фактических запросов в поддержку и задач для разработчиков, затем обозначьте точный исходный фрагмент, который отвечает на каждый из них. Включите прямые факты, таблицы, вопросы по коду, вопросы, специфичные для версии, вопросы по пересечению и вопросы, на которые невозможно ответить. Пусть рецензент проверит ответ и его доказательства, а не рассматривайте метку другой модели как истинную. Измеряйте качество извлечения и ответов отдельно. Для извлечения записывайте, появляется ли помеченный фрагмент в топ-k и на каком ранге. Для генерации записывайте правильность, правильность ссылок на источники, неподтвержденные утверждения и то, воздерживается ли система, когда страница не отвечает на вопрос. Повторите эксперимент после обновления документа, чтобы были видны регрессии свежести.
Общие ошибки разделения на фрагменты
- Слепые фиксированные окна: значимые заголовки и примеры разбиваются без метаданных.
- Слишком много перекрытий: близкие дубликаты доминируют в топ-k и стоят больше для встраивания.
- Потерянные пути заголовков: определение появляется без продукта или API, который он описывает.
- Обрезанный код или таблицы: результат извлечения больше не представляет действительных инструкций.
- Смешанные версии: руководство по API версий v1 и v2 встроено без фильтруемого поля версии.
- Отсутствие набора для оценки: фрагмент выбирается по внешнему виду, а не по производительности извлечения.
Выбор по случаю использования
Для документации разработчиков начните с заголовков Markdown и рекурсивно разделите несоразмерно длинные разделы. Для FAQ сохраняйте пары вопрос-ответ целиком. Для продуктовых знаний сохраняйте строки атрибут-значение и метаданные версии/статуса. Для длинных отчетов попробуйте извлечение родительских-детских или семантическую сегментацию, если набор вопросов пересекает разделы. Для новостей сохраняйте дату и издателя каждого элемента и учитывайте недолговечные записи. Сравните каждую с одним и тем же помеченным набором запросов. Для деталей реализации смотрите концепции разделителей LangChain, руководство по встраиванию OpenAI и руководство по семантическому поиску Pinecone. Эти источники документируют API и шаблоны; они не устанавливают, какая стратегия выигрывает в вашем корпусе.
Итоговый контрольный список
- Очистите и проверьте исходный контент перед разделением на фрагменты.
- Сохраняйте путь заголовка, URL источника, версию, язык и время обновления.
- Сохраняйте ограждения кода, таблицы и тесно связанные определения полей целыми.
- Используйте второй проход разделения только там, где это требуется лимитом ввода модели.
- Тестируйте качество извлечения и ответов на одних и тех же фиксированных вопросах.
- Записывайте фактические расходы на токены и векторы для выбранных параметров.
Для другой части рабочего процесса продолжайте с руководства по стеку веб-данных, руководства по автоматизации браузера и рабочего процесса от Краулинга до Pinecone.
Заключение
Не существует универсальной «лучшей стратегии разделения на фрагменты для RAG». Для документации, полученной с помощью веб-краулинга, разделение с учетом структуры является полезной отправной точкой, поскольку страница уже содержит заголовки и кодовые границы. Рекурсивные или семантические стратегии могут улучшить конкретные корпуса, но только набор для оценки может показать, помогут ли они в вопросах ваших пользователей. Сохраняйте сравнение воспроизводимым и записывайте как качество извлечения, так и операционные расходы.
Часто задаваемые вопросы
В: Какова лучшая стратегия разделения на фрагменты для RAG?
Лучшая стратегия — это та, которая извлекает полные доказательства для ваших реальных запросов с приемлемыми затратами на токены и хранение; разделение с учетом заголовков является практической отправной точкой для структурированных веб-документов.
В: Каков идеальный размер фрагмента?
Не существует универсального идеала; оцените размеры по лимиту ввода модели встраивания, контексту ответа и помеченным вопросам извлечения.
В: Улучшает ли перекрытие фрагментов извлечение?
Перекрытие может сохранить контекст рядом с границами, но слишком большое перекрытие создает дублирующие результаты и дополнительные затраты на индексацию, поэтому протестируйте небольшой диапазон.
В: Что такое семантическое разделение на фрагменты?
Семантическое разделение на фрагменты использует изменения в значении или сходстве между отрывками, чтобы предложить границы, что может помочь прозе, но вводит выбор модели и порога.
В: Как мне разделять Markdown для RAG?
Начните с разделов заголовков, переносите путь заголовка как метаданные, сохраняйте огражденный код и заголовки таблиц и рекурсивно разделяйте только длинные разделы.





