Сначала задача выглядела просто: собрать PDF, CVE и статьи по кибербезопасности в одну базу и отдавать LLM-агенту нужные фрагменты через HTTP API. На практике быстро выяснилось, что для Threat Intelligence мало искать похожий абзац по смыслу. Важны источник, дата, индикаторы компрометации и то, не устарела ли запись.

История инцидента

Авторы проекта начали с локального прототипа и быстро получили рабочую цепочку: загрузка, извлечение текста, разбиение на части, построение векторов и поиск. Но первая же полная загрузка показала проблему: TI-материалы живут по другим правилам, чем обычные документы. Статья о новой атаке, вышедшая вчера, может быть важнее длинного обзора, а строка с точным CVE и доменом иногда полезнее большого текста про уязвимости.

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

Что пошло не так в защите

Главная ошибка первого варианта — слишком много работы оказалось внутри API. Он не только принимал запрос, но и тянул RSS, разбирал статью, резал текст на фрагменты и считал векторы. На нескольких документах это выглядело нормально, но большой сбор из 48 лент закончился падением контейнера по нехватке памяти.

Система ещё и зависала логически: задание уже погибло, а в Postgres оно продолжало числиться как running. Отдельный обработчик не мог забрать его себе, потому что статус говорил об обратном. Проблему усиливали тяжёлые ответы источников, длинные статьи и редкое обновление прогресса.

Команда исправила архитектуру без лишнего усложнения. API стал только ставить задачу в очередь, а всю тяжёлую обработку вынесли в фоновый процесс. Векторы начали считать группами по восемь фрагментов, а объём ответа и размер одной статьи ограничили. Ещё важнее другое: повторный запуск теперь сначала проверяет дубликат по внешнему идентификатору, каноническому URL и хэшу, а уже потом тянет контент.

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

Уроки для читателя

Из этой истории хорошо видно, почему «просто подключить поиск» почти всегда заканчивается переделкой. Если база работает с документами об угрозах, ей нужны метаданные, контроль дублей, понятные статусы задач и аккуратная обработка источников. Без этого даже хороший векторный поиск выдаёт красивый, но бесполезный ответ.

Вторая важная мысль — свежесть данных нельзя считать одинаково для всего подряд. Новость об атаке стареет быстро, а запись о CVE может оставаться актуальной долго. Аналитику нужен не просто похожий текст, а контекст, в котором этот текст появился.

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

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

Практические выводы и чек-лист

Ниже — короткий список того, что стоит проверить в своей инфраструктуре, если вы храните документы, отчёты или внутренние базы знаний.

  • Разделяйте приём запроса и тяжёлую обработку: загрузку, разбор, индексацию и поиск.
  • Храните исходный файл отдельно от очищенного текста и промежуточных результатов.
  • Для повторных загрузок проверяйте дубликаты по нескольким признакам, а не по одному URL.
  • Учитывайте свежесть данных по-разному для новостей, справочников и технических записей.
  • Сохраняйте метаданные: источник, дату, ссылку, тип документа и признаки доверия.
  • Ограничивайте размер входных файлов и сетевых ответов, чтобы один источник не положил весь сервис.
  • Делите длинные тексты по смысловым границам, а не по фиксированному числу символов.
  • Проверяйте, можно ли восстановить обработку после сбоя без ручной уборки мусора.
  • Для аналитических систем используйте комбинированный поиск: смысловой, по сущностям и по метаданным.
  • Если сервис работает с внешними источниками, заранее продумайте, как он поведёт себя при битом RSS, пустом PDF и обрыве соединения.

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

Поделиться: