Гайд · TNWS AI
Как очистить текст для RAG через Haystack DocumentCleaner
Удаляем артефакты извлечения из документов, сохраняя значимые пробелы, страницы и исходную разметку.
Применимость и задача
Поисковый запрос: «как очистить текст для RAG Haystack DocumentCleaner». Материал сверён с официальной документацией Haystack 3.1 19 сентября 2026 года. Примеры рассчитаны на Python и пакет haystack-ai; для векторного примера дополнительно нужен пакет sentence-transformers-haystack. Демонстрационное InMemoryDocumentStore не рекомендовано разработчиком для production. Интерфейс командной строки ниже — Python API, а не названия пунктов графического меню.
Компонент DocumentCleaner получает список Document и возвращает список Document. Официальное руководство фиксирует порядок операций: нормализация Unicode, ASCII-преобразование, пробелы, пустые строки, заданные подстроки, regex и повторяющиеся колонтитулы. Последняя операция распознаёт страницы, разделённые символом form feed; обычные переводы строк не являются границей страницы.
Нумерованный порядок работы
- Сохраните исходный текст и документальный ID отдельно, чтобы сравнение до и после было воспроизводимым.
- Определите, является ли вход обычным текстом или Markdown с таблицами и списками: для Markdown выключите автоматическое удаление лишних пробелов и пустых строк.
- Выпишите только заведомо лишнюю строку колонтитула; не подставляйте регулярное выражение, которое может захватить деловые факты.
- Запустите компонент на маленьком образце и сравните весь результат, не только длину текста.
- Примените очищение к полному набору лишь после проверки примеров с переносом страницы и значимым форматированием.
Готовый шаблон
from haystack import Document
from haystack.components.preprocessors import DocumentCleaner
source = Document(content="Правило: 14 дней.\n\n\nКонтакт: support@example.org")
cleaner = DocumentCleaner(remove_empty_lines=True,
remove_extra_whitespaces=True)
cleaned = cleaner.run(documents=[source])["documents"][0]
print(repr(cleaned.content))
Пример предназначен для контролируемого теста на своих данных. Установите зависимости в отдельном окружении и зафиксируйте версии; при использовании локальной embedding-модели отдельно проверьте её доступность и разрешённость для вашего проекта. Код был проверен на синтаксис Python, но его вызовы Haystack в данном материале не выдаются за выполненный runtime-тест.
Вход и ожидаемый результат
На входе строка с двумя пробелами внутри «14 дней» и тремя переводами строк перед адресом. В ожидаемом результате факт «14 дней» и адрес сохраняются, лишние пробелы и пустые строки сокращаются. Если удалить сам адрес, это провал проверки, даже если текст выглядит визуально чище. Для Markdown-таблицы ожидаемый результат иной: сохранение границ ячеек важнее одинаковой плотности пробелов.
Помимо положительного кейса записывайте отрицательный: отсутствие факта, чужой документ, пустой файл или несовместимая редакция правила в зависимости от задачи. Храните ожидаемые ID и смысл результата отдельно от вывода программы. Если пример не прошёл, выясните, на каком шаге данные впервые разошлись: загрузка, обработка, извлечение или построение ответа. Нельзя исправлять результат одной только формулировкой ответа, если нужный факт никогда не поступил в контекст.
Разбор ограничений и ошибок
Очистка влияет не на косметику, а на доступность фрагментов при последующем поиске. Если исключить текст с юридически значимым исключением, генератор не сможет его восстановить. Постройте регрессионный тест из пары исходных документов: простой текст с колонтитулом и Markdown с таблицей тарифных условий. В первом можно проверять удаление заведомой повторной строки на нескольких страницах, но remove_repeated_substrings требует настоящих границ form feed; во втором сохраните строки таблицы и заголовок. Не включайте ascii_only для русского: кириллица может быть испорчена, а это изменит смысл и ухудшит поиск. unicode_normalization тоже требует осознанного выбора, особенно когда по очищенному тексту затем сопоставляют исходные смещения или юридические цитаты. Сохраните контрольные фразы и запустите тест после смены конвертера, потому что текст PDF и Markdown могут иметь разные структуры. В логах фиксируйте версию компонента и настройку удаления, не копируйте персональные документы в публичный стенд.
Проверочный сценарий на реальном корпусе
Отдельно протестируйте пустой текст и документ только из пробелов: downstream-разбиение не должно превратить их в ложный ответ. Измеряйте долю удалённых символов по каждому файлу, а не только среднюю: резкий всплеск у одного договора указывает на ошибочный regex. Если файл содержит оглавление и повторный заголовок раздела, не называйте всякое повторение колонтитулом: повтор может быть частью нормы. Для сложного PDF с колонками сначала проверьте качество извлечения конвертером; очистка не способна восстановить утраченный порядок чтения. При проверке человек должен видеть diff на нескольких критических строках. После очистки повторите один поисковый вопрос, где ожидаемая фраза находится рядом с удалённым шумом: релевантность должна сохраниться. Так вы отделите видимость чистого текста от реального эффекта для RAG.
Критерии приёмки
- Сохранены числа, отрицания и контакты.
- Контрольная Markdown-таблица не разрушена.
- Отсутствует неожиданное удаление на нескольких файлах.
Не принимайте демонстрационный вывод за статистику качества. Для рабочего приложения повторите эти проверки на обезличенном наборе документов, измерьте результат после изменения версии корпуса и запретите доступ к источникам вне полномочий пользователя. Корректный ответ HTTP вашего сервиса не означает корректный ответ RAG-системы; последнее устанавливается сопоставлением факта с разрешённым источником.
Типичные ошибки: чего не делать
- Не включать ascii_only для русского текста без специальной причины.
- Не удалять заголовки агрессивным regex на всём корпусе.
- Не путать перевод строки с символом form feed.
Если после обновления пакета поведение разошлось с примером, сначала проверьте официальную документацию именно установленной версии, а затем обновите тест и собственный код. Не пытайтесь обходить ограничения сервиса, подменять чужие документы или использовать промпт как замену серверной проверки доступа.
FAQ
Нужна ли модель LLM?
Нет, это детерминированная предобработка.
Можно ли подать Markdown?
Да, но пробелы и пустые строки лучше сохранять, если они кодируют структуру.
Когда удалятся колонтитулы?
Когда страницы разделены form feed и настроено удаление повторяющихся подстрок.
Официальные источники
Частые вопросы
Нужна ли модель LLM?
Нет, это детерминированная предобработка.
Можно ли подать Markdown?
Да, но пробелы и пустые строки лучше сохранять, если они кодируют структуру.
Когда удалятся колонтитулы?
Когда страницы разделены form feed и настроено удаление повторяющихся подстрок.
Читайте также
Как ограничить поиск документами одного клиента в Haystack
Фильтр meta.tenant в retriever, тест на утечку чужого документа и границы серверной авторизации.
Как настроить смысловой поиск в Haystack InMemoryEmbeddingRetriever
Индексируем документы и запрос одной embedding-моделью, проверяем размерность, top_k и качество на перефразировках.
Как избежать дублей документов в Haystack через DocumentWriter и DuplicatePolicy
Повторная индексация без случайных дублей: стабильные ID, режимы OVERWRITE, SKIP и FAIL и проверка числа записей.
Комментарии
Пока тихо. Скажите первое слово