Загрузка и парсинг документов

Откуда RAG берёт знания и почему «мусор на входе — мусор на выходе».

Загрузка (loading) и парсинг — этап, на котором сырые файлы превращаются в чистый текст, пригодный для нарезки на чанки и эмбеддинга.

Источники бывают разные

Документы для RAG приходят отовсюду: PDF-инструкции, страницы сайта, Markdown-вики, таблицы, тикеты поддержки, базы данных. У каждого формата своя «упаковка», из которой нужно достать собственно текст.

ФорматСложность парсинга
TXT / Markdownлёгкий, текст почти готов
HTMLнадо убрать теги, меню, рекламу
PDFсложный: колонки, таблицы, сканы
DOCX / таблицысредний, важна структура

Почему этот шаг критичен

Если в текст просочились навигация сайта, номера страниц, колонтитулы или «склеенные» из PDF слова — этот мусор попадёт в чанки, испортит эмбеддинги и всплывёт в ответах. Качество RAG начинается здесь, на самом скучном шаге.

Простая чистка текста

Базовая нормализация: убрать лишние пробелы и переносы, выкинуть совсем короткие «строки-обрывки». Покажем идею на stdlib.

import re

raw = """  Раздел 1.   Возврат  товара\n\n\nВозврат возможен\nв течение 14 дней.\n\n12"""

def clean(text):
    # схлопываем пробелы
    text = re.sub(r"[ \t]+", " ", text)
    lines = []
    for ln in text.splitlines():
        ln = ln.strip()
        # выкидываем пустые строки и «строки» из одних цифр (номера страниц)
        if ln and not ln.isdigit():
            lines.append(ln)
    return "\n".join(lines)

print(clean(raw))

Вывод:

Раздел 1. Возврат товара
Возврат возможен
в течение 14 дней.

Реальные инструменты (для чтения)

На практике парсинг берут на себя библиотеки. Это не запускается в браузере:

# LangChain: загрузчики под разные форматы
from langchain_community.document_loaders import PyPDFLoader, WebBaseLoader

docs = PyPDFLoader("manual.pdf").load()
web = WebBaseLoader("https://example.com/faq").load()
# каждый docs[i] — .page_content (текст) + .metadata (источник, страница)

Особый случай: PDF и таблицы

PDF — самый коварный формат. Текст в нём расположен по координатам, а не по смыслу, поэтому наивный экстрактор легко склеивает колонки, путает порядок абзацев и рвёт слова переносами. Таблицы вообще превращаются в кашу из чисел без структуры. На практике для PDF берут специализированные парсеры (а для сканов — OCR), а таблицы по возможности сохраняют отдельно, например в виде «ключ: значение» построчно, чтобы каждая строка оставалась осмысленной после чанкинга. Помните: всё, что вы потеряете или испортите здесь, retrieval уже не восстановит.

Сохраняйте источник

Уже на этом шаге к тексту прикрепляют метаданные: имя файла, URL, номер страницы. Позже это позволит RAG цитировать источник и фильтровать выдачу. О метаданных — отдельный урок.

Итог

  • Парсинг превращает PDF/HTML/прочее в чистый текст.
  • Мусор на входе (меню, колонтитулы) портит весь RAG.
  • Сразу сохраняйте источник в метаданные — пригодится для цитат.
Проверьте себя
1. Зачем нужен этап парсинга документов в RAG?
AЧтобы сжать файлы
BЧтобы вытащить из разных форматов чистый текст для чанкинга и эмбеддинга
CЧтобы зашифровать данные
DЧтобы перевести их на английский
2. Почему важно убирать из текста меню, колонтитулы и номера страниц?
AТак файл весит меньше
BЭтот мусор попадёт в чанки, исказит эмбеддинги и всплывёт в ответах
CИначе не запустится Python
DЭто требование GDPR
3. Что полезно сохранить вместе с текстом уже на этапе загрузки?
AРазмер шрифта
BМетаданные источника (файл, URL, страница) для будущего цитирования
CЦвет фона страницы
DВремя загрузки в миллисекундах
Поддержать проект