AI-агент для инфраструктурных операций: пилот GigaChat + Ansible с guardrails
Пилотируем операционного агента на GigaChat API: запуск Ansible playbook по запросу, архитектура разрешений, аудит-лог и почему чат-бот тут не подходит.
AI-агенты для управления инфраструктурой: переход от чат-ботов к автономным операционным агентам
Когда мы в январе запускали LLM-агента на IT-хелпдеске, тот агент работал только с текстом: читал базу знаний, писал ответы, эскалировал тикеты. Ничего в инфраструктуре не менял. Это принципиальное ограничение - и оно было сознательным, потому что цена ошибки там низкая. Пользователь получил неверный ответ - написал снова.
Теперь мы пилотируем кое-что другое: агент, который не только читает, но и исполняет. Конкретно - запускает Ansible playbook по запросу инженера в интерфейсе служебного чата. Это уже другая история с точки зрения рисков.
Откуда задача
Есть клиент - около двухсот хостов, несколько сред: dev, staging, prod. Инженеры регулярно прогоняют однотипные playbook-и: обновить пакеты на группе хостов, перезапустить сервис, снять диагностику. Каждый раз - открыть AWX, найти template, проверить параметры, запустить, подождать, посмотреть результат. Не сложно, но монотонно, особенно когда таких запросов в день пять-десять.
Идея - интерфейс на естественном языке поверх Ansible Controller API. Инженер пишет в чат: «перезапусти nginx на стейджинге», агент разбирает запрос, выбирает нужный playbook, подтверждает параметры с инженером и запускает.
Звучит просто. На деле - вся сложность в том, чтобы агент делал только это и не больше.
Архитектура: что внутри
Схема получилась трёхуровневой.
flowchart TD
ENG[Инженер в чате] -->|запрос| AGENT[Агент GigaChat]
AGENT -->|intent + params| GUARD[Guardrail-слой]
GUARD -->|разрешено?| POLICY{Policy check}
POLICY -->|нет| DENY[Отказ + объяснение]
POLICY -->|да| CONFIRM[Запрос подтверждения]
CONFIRM -->|инженер подтвердил| AWX[Ansible Controller API]
AWX -->|job_id| AGENT
AGENT -->|статус + лог| ENG
AWX --> AUDITLOG[(Аудит-лог)]
GUARD --> AUDITLOG
Слой 1 - LLM (GigaChat API). Парсит запрос на естественном языке, извлекает intent и параметры, формирует структурированный вызов инструмента. Модель не знает про AWX напрямую - она возвращает JSON с полями playbook_alias, target_scope, extra_vars. GigaChat взят по той же причине, что в январе: требование клиента, локализация данных.
Слой 2 - guardrail-слой. Это обычный Python-сервис, никакого LLM. Принимает структурированный запрос от агента и прогоняет через policy:
- разрешён ли данный playbook для данного инженера (RBAC по ролям в AWX)
- разрешён ли target_scope (prod-хосты заблокированы для всех, кроме senior-инженеров)
- нет ли параметров из blocklist (например,
hosts: allбез явного указания группы) - не превышен ли rate limit (не более трёх prod-запусков в час на инженера)
Если что-то не прошло - агент получает отказ с кодом причины и объясняет инженеру человекочитаемым текстом почему нельзя.
Слой 3 - Ansible Controller API. Guardrail-слой вызывает AWX job_template launch API. Агент получает job_id, опрашивает статус и возвращает результат в чат. Если job упал - агент передаёт последние строки stdout, не пытается интерпретировать ошибку самостоятельно.
Guardrails: где реально пришлось думать
Самое интересное - не LLM-часть, а именно policy. Несколько решений, к которым пришли не сразу.
Обязательное подтверждение для любого prod-запроса. Агент не запускает ничего в prod без явного «да» от инженера в следующем сообщении. Мы рассматривали вариант с таймаутом (как в паттерне карантина из EDA), но остановились на жёстком подтверждении - автозапуск в prod нам не нужен ни при каком сценарии.
Playbook-whitelist, не blacklist. Агент умеет запускать только явно разрешённые playbook-и из списка. Это значит, что новый playbook нельзя вызвать через агента до тех пор, пока его не добавят в whitelist вручную. Неудобно, зато понятна граница.
Параметры только из явного списка. extra_vars, которые инженер может передавать, тоже ограничены схемой для каждого playbook. Если агент извлёк из запроса параметр, которого нет в схеме - запрос блокируется, не молча игнорируется.
Scope prod только для senior. Это не в AWX, а в guardrail-слое - потому что AWX RBAC и наши операционные роли не совпадают один в один.
Аудит-лог
Каждое взаимодействие пишется в отдельную таблицу: кто запросил, что именно сказал (исходный текст), что агент распарсил, прошёл ли policy check, если нет - почему, если да - какой job_id запустился. Лог пишется до обращения к AWX, не после - чтобы отказ guardrail-а тоже фиксировался.
Это оказалось полезным уже через неделю после запуска: один из инженеров попытался вызвать несуществующий playbook-алиас несколько раз подряд - не со злым умыслом, просто не знал точного названия. Лог показал паттерн, мы добавили в агента подсказку с доступными aliases при ошибке. Без лога мы бы об этом не узнали.
Где сейчас и что не работает
Пилот идёт вторую неделю, только dev и staging. Prod - ещё не подключали, хотя policy для него уже написана. Хотим накопить данные по ложным парсингам в низкорисковой среде.
Главная открытая проблема - неоднозначные запросы. Инженер пишет «обнови конфиг на фронтах» - а агент не всегда понимает, это nginx-конфиг или конфиг приложения. В таких случаях агент должен переспросить, и он это делает, но иногда переспрашивает слишком подробно, превращая диалог в анкету. Ищем баланс между точностью и удобством интерфейса.
Второй момент - инженеры пока относятся к агенту немного настороженно, особенно после того как один раз агент неверно распознал target_scope и guardrail-слой это поймал и заблокировал. С одной стороны - система сработала как надо. С другой - доверие строится медленно, и один неловкий момент отбрасывает его назад.
Это, в общем, честный результат для второй недели пилота. Продолжаем.