
В SOC значительная часть нагрузки L1-аналитика — разбор однотипных инцидентов, которые в итоге оказываются ложными срабатываниями. При этом каждый алерт нужно проверить, обогатить контекстом и задокументировать. Результат — много ручной работы, которая отнимает время от более сложных задач и повышает риск ошибки из-за усталости.
Особенно остро эта проблема стоит в командах ИБ, которые одновременно занимаются инфраструктурой, клиентскими задачами и другими проектами. Можно ли автоматизировать первичный разбор, не отдавая данные во внешнюю LLM и не превращая внедрение в многомесячный проект по файнтюнингу?
Мы попробовали это сделать с помощью локальной LLM, RAG и второго прохода с валидатором. Привет! На связи Антон Дятлов, инженер по защите информации в Selectel. В статье покажу, как устроен этот процесс, почему мы выбрали RAG вместо файнтюнинга и какие проблемы обнаружили уже после внедрения.
Как мы жили до внедрения LLM
Представьте картину: L1-аналитик SOC получает инцидент, читает и анализирует события в SIEM, ищет CVE, проверяет во внутренней документации адреса и хосты, пишет разбор по шаблону. Далее ему нужно принять решение: закрыть инцидент как FP (False Positive) или эскалировать на L2.
У нас таких инцидентов приходило около 100 в месяц, примерно 80% из них оказывались ложными срабатываниями. Но даже очевидный FP нужно было проверить и задокументировать. На полный разбор инцидента уходило до двух рабочих дней. Такие затраты времени были особенно заметны на фоне остальной работы команды: помимо разбора инцидентов, мы занимались настройкой и администрированием оборудования, коммуникацией с клиентами и разработкой различных решений.
При подобном потоке рутины стоит учитывать и человеческий фактор: после двадцатого похожего алерта за час можно ошибиться с принятием решения, так как наступает усталость от разбора инцидентов.
Так и появилась цель — освободить аналитика от рутинного разбора. Не заменить его нейросетью, а делегировать ей первичный анализ, обогащение данных и подготовку решения, чтобы человек получил готовый разбор в Telegram, а не сырой JSON из SIEM.

Информационная безопасность как услуга
Предоставляем ИТ‑инфраструктуру для проектов с повышенными требованиями безопасности, а также сервисы для защиты сетей, ОС и приложений.
Из чего состоит наш SOC
Прежде чем переходить к автоматизации, расскажу о нашем SOC. Под ним подразумевается SIEM-система, в которую с части наших служебных и клиентских систем стекаются логи:
сетевого оборудования;
серверов и контроллеров доменов;
антивирусов и межсетевых экранов;
средств защиты информации (СЗИ), в том числе при несанкционированном доступе и событиях криптографии.
SIEM коррелирует события по заданным правилам и создает инциденты.

Как мы выбирали модель
При выборе LLM было одно важное условие: согласно внутренней ИБ-политике, мы не можем передавать информацию во внешние сервисы. Это требование сразу отсекло облачные LLM-сервисы независимо от их условий обработки данных. Трафик наружу в нашем контуре недопустим, так что речь даже не о доверии к вендору.
В Selectel есть несколько моделей, развернутых локально. В шорт-лист попали две: Qwen 3.6-27B и GLM-5.1, которую мы затем заменили на более свежую GLM-5.2.
Модель |
Чем не устроила |
Выводы |
ChatGPT |
Не предполагается локального исполнения, чего требует наш закрытый контекст. |
Отказались на начальном этапе: не соответствует требованиям безопасности. |
Qwen 3.6-27B |
Теряет фокус на разборе длинных инцидентов, галлюцинирует. |
Не обеспечила нужной стабильности при расследовании длинно-контекстных инцидентов. |
GLM-5.1 / 5.2 |
Тяжеловесная, отвечает медленнее остальных. |
Высокая точность, приемлемое качество на длинном контексте, открытая архитектура. |
Также проверили бенчмарки для понимания способностей моделей.

Почему GLM лучше Qwen
Я прогнал набор инцидентов через обе модели и составил сравнительную таблицу:
Метрика |
Qwen 3.6 27B |
GLM-5.2 |
Accuracy |
48,5% |
67,6% |
Error Rate |
32,5% |
24,4% |
Miss Rate |
12,5% |
7,1% |
False Escalation |
9,1% |
4% |
Mean Confluence |
0,42% |
0,62% |
Mean Agreement |
0,7% |
0,92% |
Разница заметна, но не критична. Ключевая метрика здесь — False Escalation, эскалация ложного инцидента на L2 (Level 2, углубленный анализ). Лишние задачи и ложные отчеты по инцидентам никому не нужны, а GLM куда точнее по этому критерию, да и по всем остальным превзошла конкурента.
Я прогонял набор «золотых инцидентов» с известным решением, по которым и проверял, что модель вообще способна дать осмысленный и похожий на человеческий ответ.
RAG или файнтюнинг
Удобно убрать лишние слои из модели, дообучить ее на H100 и эффективно закрывать инциденты. Но тут есть несколько нюансов.
У нас нет огромного датасета. Для файнтюнинга нужны тысячи размеченных примеров формата «как делать надо». Времени на разметку датасета, как и двух тысяч инцидентов, не было.
Времени на дообучение модели тоже не было. При каждом обновлении документации пришлось бы заново размечать и готовить данные, да еще и выделять GPU для дообучения — все это долго и дорого.
Хотелось сделать быстро и эффективно. RAG позволяет собрать данные из внутренней документации, которая содержит информацию по хостам, доменам и инфраструктуре. Модель получает только нужную информацию и на ее основе принимает решение.
Полнотекстовый поиск вместо векторного — это осознанный выбор на старте. Данные собираются по небольшому спейсу, а в будущем планируется подключение еще одной ИИ с семантическим поиском.

Почему n8n
Как оркестратор был выбран n8n. Он развернут локально, данные не покидают сеть. У него удобный визуальный воркфлоу, и новичку легко втянуться и понять суть. Продуманные интеграции облегчают жизнь — все запросы выполняются через стандартные ноды. Настроить автоматизацию легко и удобно.
Обработка инцидента по шагам
Теперь взглянем на общую схему нашего решения. Если вкратце, то в SIEM стекаются логи со всех систем. Далее по заранее заданным корреляционным правилам события связываются в единые инциденты, которые и отправляются в n8n.

Шаг 1. Сырой инцидент
Инцидент из SIEM приходит как JSON и его структура сильно варьируется:
событий может быть 3 или 200 — заранее неизвестно;
поля приходят как
null, как пустая строка или какundefined;src.ip— иногда строка, а иногда и массив;есть лишние поля, которые модели не нужны.
Корреляция содержит symptoms, tags, correlation.description, raw_event с полным JSON события. Если отдать все это модели как есть, она утонет в контексте и потеряется в 200 строках лишней информации.

Шаг 2. Нормализация
Неструктурированный JSON необходимо привести к нормализованному виду. С этой задачей справляется специальный скрипт.

Структура данных должна быть предсказуемой, ведь модель ожидает единообразный JSON.
Шаг 3. Обогащение через OSV API
Если indicators.cve не пустой — выполняем запрос к OSV (Open Source Vulnerability, открытая база уязвимостей, созданная и поддерживаемая Google). В результате получаем следующую информацию:
оценку (score), критичность (severity) и вектор атаки (vector) из CVSS (Common Vulnerability Scoring System, балльная оценка опасности уязвимости);
идентификатор уязвимости по реестру CVE;
информацию о публичной доступности эксплойта;
ссылки на подробности и бюллетени безопасности.

Поскольку данные подтягиваются из внешних систем еще до вызова модели, та оперирует готовыми фактами и не придумывает метрики.
Шаг 4. Сбор CQL для Confluence
Из нормализованных полей строится запрос на языке CQL (Confluence Query Language). Информацию по hostname, ip, CVE, user ищем в спейсах отделов в Confluence.

Шаг 5. RAG обработка + промпт
Чтобы не забивать контекст модели, чистим HTML и вырезаем релевантные куски, которые нужны для анализа инцидента. Так мы получаем обработанный RAG.
Перед вызовом модели задаем промпты:
User prompt — собранная информация и RAG по инциденту;
System prompt — жесткие правила, чтобы модель не выходила за рамки L1.

Шаг 6. Анализ инцидента
Системный и пользовательский промпты склеиваются в один запрос.

На выходе отдается JSON с нужными полями: classification, severity, confidence, l1_decision.
Шаг 7. Валидация ответа
Результат анализа передаем валидатору. Он получает только нужную информацию — классификацию, severity, confidence, решение L1, — и далее проверяет их на противоречия.

Валидатор — вторая пара глаз, которая соглашается или не соглашается с выводами первой модели.
if (v.validation_result === "confirmed") { // Валидатор согласен с решением модели, ничего не меняем finalResult = { final_severity: l1.severity, // значение от L1 final_true_positive: l1.true_positive, // значение от L1 final_decision: l1.l1_decision, // решение от L1 final_escalate_to_l2: l1.escalate_to_l2 || false, validation_status: "confirmed", agreement_score: v.agreement_score, human_review_required: false }; } else if (v.validation_result === "corrected") { // Валидатор не согласен с решением модели — учитываем его правки finalResult = { classification: (v.corrections && v.corrections.classification) || l1.classification, final_severity: v.final_severity, // значение от валидатора final_true_positive: v.final_true_positive, // значение от валидатора final_decision: v.final_decision, // решение валидатора final_escalate_to_l2: v.final_escalate_to_l2, validation_status: "corrected", agreement_score: v.agreement_score, human_review_required: false }; } else { // disputed / insufficient — ручная проверка человеком finalResult = { final_decision: "insufficient_data", validation_status: v.validation_result, agreement_score: v.agreement_score, human_review_required: true, disputed_fields: v.disputed_fields, validator_notes: v.validator_notes }; }
Валидатор возвращает два ключевых параметра:
validation_result— статус проверки: подтверждение исходного решения (confirmed), исправление его (corrected), признание спорным (disputed) или нехватка данных (insufficient).agreement_score— число от 0 до 1, которое показывает степень согласия валидатора с результатами первичного анализа.
Если agreement_score ≥ 0,8 — результат подтвержден, идем по решению L1 от модели (но проверяем это решение по-человечески, просто без исследования инцидента), в противном случае — валидатор поправил. Если validation_resultпринимает значение disputed или insufficient — инцидент уходит на ручную проверку человеком.
Шаг 8. Финальное решение
По результатам анализа и валидации формируется итог с полем action_type:
close_fp— инцидент закрывается как ложный;escalate_l2— эскалация до L2, с заведением задачи и оповещением в Telegram;monitor— помечаем инцидент как мониторящийся;human_review— отправляем на разбор человеком (могло не хватить информации для принятия решения).
Аналитик открывает Telegram и видит заключение по инциденту.

Как это работает на практике
Мы записали небольшое видео, чтобы наглядно показать весь процесс обработки инцидента. Здесь инцидент обогащается информацией из OSV API и Confluence, а затем на этапе принятия решения демонстрируются две ветки развития: когда нейросеть уверена, а также когда она сомневается и создает задачу на разбор инцидента живым аналитиком.
Типовые ошибки при внедрении
Ошибки у нас тоже были, так что если вы решите реализовать предоставленную в статье схему, предусмотрите несколько важных моментов.
Markdown-разметка в ответах. Нейросеть часто возвращает результат не в виде чистого текста, а оборачивает его в Markdown-блоки с тегами JSON и обратными кавычками. Если передать такую строку напрямую в JSON.parse, скрипт выдаст ошибку. Проблема легко решается с помощью регулярных выражений. Перед парсингом необходимо вырезать из ответа лишние символы, оставляя только чистый код.
502 от API при последовательных вызовах. GLM — тяжелая модель, а два последовательных запроса без паузы могут вызвать ошибку 502. Решить проблему можно либо вызовом двух разных моделей, либо задержкой перед вторым запросом.
Захламление контекста. Длинные инциденты забивают память модели, и она теряет фокус. Проблема решается фильтрацией лишней информации: нормализацией, точечными обогащениями, очисткой обертки и «шелухи», которая модели не нужна.
Итоги и планы
LLM в контуре SOC — это освобождение сотрудника от части рутины. Связка промт‑инжиниринга, валидации и RAG — это проще, быстрее и эффективнее, чем файнтюнинг. При этом защита от галлюцинаций, достигаемая за счет жесткого промпта и логических проверок, делает систему управляемой.
Около 80% инцидентов закрываются практически без участия аналитика, но обязательно под его присмотром. Помимо прочего, время на разбор тех инцидентов, которые требуют внимания, заметно сократилось, так как аналитик получает готовый анализ, а не сырой JSON.
Сейчас есть идеи, как улучшить решение:
перейти с полнотекстового CQL на семантический поиск по Confluence через внутреннюю ИИ, чтобы контекст стал релевантнее по смыслу, а не по строковому совпадению;
протестировать валидатор на независимой второй модели по типу Qwen;
проработать документирование разбора инцидента аналитиком, чтобы переиспользовать информацию в промптах и обогащать RAG-документацию;
изменить канал оповещения, заменив Telegram внутренним мессенджером.

Каталог готовых ИИ‑моделей
Сервис для запуска и управления LLM в облаке Selectel. Выберите модель, конфигурацию и получите готовый эндпоинт для работы с ней.
Комментарии (10)

Ribera-sun
23.09.2026 09:49Ради 100 инцидентов в месяц?
Аналитик не может разобрать ~3 в день?

Flampanzer Автор
23.09.2026 09:49Добрый день! Я решал нашу проблему нашего отдела, который помимо анализа инцидентов занимается и другими делами, связанными с ИБ. До этого автоматизировал сканирования клиентских и служебных сетей по API с помощью Сканера ВС(статейка есть на хабре). А до этого другие процессы.
Особенно остро эта проблема стоит в командах ИБ, которые одновременно занимаются инфраструктурой, клиентскими задачами и другими проектами
ToxaBes
Сначала подумал, хм, так одно не отменяет второго.
Затем увидел:
Дальнейшие вопросы отпали, вы просто не умеете это делать и это нормально, тк вы не ML инженер. Достаточно датасета до 100 инциндентов, обучить можно за день и тд, модели ввбраны неверно под задачу и тд.
Если есть желание скиньте сотню примеров сырых данных (обезличенных) с результатами. Я покажу чего можно добиться.
akardapolov
Так можно же более мощную модель для этих целей привлечь? Или данные в контекст не влезут (в статье не нашел объем БД)?
Flampanzer Автор
Добрый день. Сначала была идея развернуть для команды свой ИИ, но оказалось очень дорого и нецелесообразно, т.к. есть общекомпанейский. А там уже и урезания контекста и мощи модели появляются. Все думаю про мелкий Qwen, из которого удалены все лишние слои. но это пока в мыслях.
ToxaBes
Не надо удалять слои, вы так модели лоботомию сделаете.
Flampanzer Автор
Здравствуйте. Да, можно было и затюнить, и заRAGать модельку, но времени на познание новых компетенций пока нет)
Постараюсь вернуться к вопросу в этом году, но не факт.
С радостью почитаю вашу статью, как разметитть дата сет и обучить за день, чтобы набраться опыта) Спасибо за коммент
ToxaBes
С вас данные, с меня статья.
Ribera-sun
А научить модель на прогнозы аварийности можно?
Понятно дело, чтобы не просто по количеству и сезонности, а более глубоко, по типам инцидентов, локации, производителю, нагрузки и прочего прочего?
Про инциденты от абонентов тоже интересно. Местный ИТ пытался научнить на исторических данных (40тыс), но на новых обращениям модель ведет однообразно слишком.
ToxaBes
Да, если есть возможность собрать необходимые данные. На производствах так выход из строя всяких двигателей и механизмов предсказывается, в ИТ сложнее тк зачастую данных нужных нет. Все упирается в данные.
Вот это не так сложно сделать, тем более что исторические данные есть.