Все статьи

Проблема повторного сканирования: как поддерживать актуальность RAG-конвейеров

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

Проблема

Все стартапы в области вертикального ИИ сталкиваются с одной и той же стеной примерно на второй месяц. Они выпускают copilot для поддержки, помощника по юридическим исследованиям или бота для комплаенса. Первая демо-версия привлекает клиентов. Затем данные устаревают, а ответы начинают расходиться с реальностью.

Мы наблюдали, как команды чисто создают ИИ-часть, а работу с данными оставляют на потом. Конвейер приема данных, это один скрипт на Python, запущенный на чьем-то ноутбуке. Он один раз собирает данные с 200 исходных URL-адресов, сбрасывает чистый Markdown в векторное хранилище, и все празднуют. Спустя шесть недель половина ответов ссылается на удаленные страницы, устаревшие API или функции продукта, которые были выпущены в марте, а затем снова в мае.

Решение звучит просто: еженедельно сканировать каждый источник заново. В реальности все сложнее. К 2026 году около 60% авторитетных сайтов блокируют сканеры ИИ (по сравнению с 23% в конце 2023 года), и защита больше не сводится к глупым проверкам User-Agent. Они смотрят на поведение сеанса, ритм запросов и сигналы на уровне рукопожатия. Простой скрипт, работавший в январе, в марте молча возвращает пустые страницы.

Хуже того, некоторые сайты теперь подают tarpit-контент (сгенерированную Марковым бессмыслицу, которая читается как настоящая проза), пока она не отравит ваши embeddings. В итоге ваши разработчики тратят половину недели на латание парсера вместо выпуска продукта. Качество извлечения падает, клиенты это замечают, и команда, нанятая вами для создания ИИ, превращается в цех по обслуживанию парсера.

Подход

Проблема повторного сканирования разбивается на три конкретных решения, которые должны приниматься при каждом запросе:

  1. Рендерить или нет? Большинство порталов документации отдают чистый HTML. Растущая доля (все, что построено на Next.js, все с рендерингом на стороне клиента) нуждается в полном браузерном рендеринге для возврата полезного контента.
  2. Какой прокси? Резидентный, дата-центр, мобильный, с гео-привязкой, специфичный для интернет-провайдера. Правильный выбор меняется в зависимости от цели.
  3. Сработало ли это на самом деле? 200 с пустым телом или HTML-страница с CAPTCHA, это успешный HTTP-запрос и неудачное сканирование.

Платформа, такая как FourA, обрабатывает каждую из этих проблем как первостепенную задачу.

Для решения о рендеринге вы вызываете Single для дешевого, быстрого случая и Browser для тяжелых JS-целей. Тело вызова имеет ту же форму, поэтому ваш код приема данных ветвится один раз по флагу на источник вместо того, чтобы тащить за собой сотню специфичных для сайта причуд.

Для выбора прокси Proxy Finder работает как часть каждого вызова Single, Browser и Auto. Платформа выбирает рабочий выход для каждого запроса, возвращает его непрозрачный id в ответе (на r.proxy верхнем уровне в Single/Browser или r.session.proxy в Auto), и вы повторно используете этот id в последующих вызовах, когда вам нужно придерживаться того же выхода. Ваш сканер не имеет собственного алгоритма ранжирования прокси. (Мы писали о том, почему размер пула перестал быть отличительным фактором в статье Почему размер пула прокси-серверов перестал иметь значение в 2026 году.)

А что касается вопроса "сработало ли это на самом деле", каждый запрос поддерживает блок validate. Вы объявляете, что считается успехом: допустимые коды состояния, требуемые значения заголовков, строки тела, которые должны или не должны появляться. FourA возвращает один из семи результатов, и только success подлежит оплате. 200, который не соответствует вашим правилам для контента, помечается как application_fail и никогда не попадает в ваш набор данных.

Вот как выглядит вызов повторного сканирования для портала документации, которому требуется рендеринг JS. Мы позволяем Auto осуществлять оркестровку, он выбирает нужный продукт (Single, Proxy или Browser), справляется с защитой от ботов и возвращает тройку сеанса, чтобы следующее повторное сканирование могло придерживаться того же выхода:

import requests

r = requests.post(
    "https://api.foura.ai/api/auto",
    headers={"Authorization": "Bearer pk_live_..."},
    json={
        "url": "https://docs.example.com/changelog",
        "validate": {
            "status": {"accept": [200]},
            "data":   {"accept": ["<article"], "fail": ["captcha", "Just a moment"]},
        },
    },
).json()

# r["data"] or r["body"]   — rendered content (Auto runs the right sub-product per host;
#                            Single populates "data", Browser populates "body")
# r["session"]              — { "proxy": "<base36 id>", "cookies": [...], "userAgent": "..." }
# On the next recrawl, pass r["session"]["proxy"] back as `ignoreProxies: [<id>]` to avoid
# the same exit, or via /api/single with `proxy: <id>` to stick to it.

Если цель выдает промежуточную страницу Cloudflare, правило validate.data.fail перехватывает ее. Результат, отмеченный в вашем использовании,, application_fail. Вы не платите за это, и ваш код приема данных знает, что нужно повторить попытку с другим прокси, вместо того, чтобы скармливать страницу "Just a moment..." в embeddings.

Для более широкого корпуса вы оборачиваете тот же паттерн в существующую очередь заданий. Команды, с которыми мы общались, запускают ночные diffs по сравнению с предыдущим сканированием, повторно встраивают только те документы, которые действительно изменились, и обновляют корпуса из 500 источников за пару часов реального времени. Очередь заданий остается вашей. Управление прокси, решение о рендеринге, вердикт об успехе, наши.

Результаты

Как выглядит цикл обновления, когда инфраструктура перестает быть узким местом (иллюстративный сценарий на основе паттернов, которые мы наблюдаем в командах вертикального ИИ):

  • Еженедельно повторно сканируется 500 исходных URL-адресов вместо одноразового запуска 200 URL-адресов при старте.
  • Время инженеров на парсер: менее 2 часов в неделю, по сравнению с 1-2 днями.
  • Окно устаревания извлечения: 5-7 дней вместо неограниченного.
  • Уровень мусора в векторном хранилище близок к нулю, поскольку промежуточные страницы Cloudflare и tarpit-страницы отклоняются на уровне validate до того, как они достигнут вашей модели встраивания.
  • Затраты предсказуемы для каждого источника, поскольку неудачные сканирования не отображаются в счетах.

Суть не в том, что что-то из этого, магия. Суть в том, что это скучно. А скука, это то, что нужно ИИ в продакшене. (Подробнее о том, где математика перестает работать с извлечением LLM на хостинге, см. Когда извлечение LLM перестает окупаться.)

Ключевой вывод

Большинство команд, создающих вертикальный ИИ, думают, что их конкурентное преимущество, это промпт, выбор модели или алгоритм извлечения. Это не так. Преимущество, это цикл обновления: неприглядная инфраструктура, которая неделя за неделей поддерживает актуальность базы знаний.

Команды, которые выиграют в вертикальном ИИ вплоть до 2026 года, не будут теми, у кого самые умные промпты. Они будут теми, чьи пользователи никогда не заметят, что данные актуальны, потому что они всегда такие.