В статье я расскажу, как мы запускаем ИИ‑агентов для простых повторяющихся задач в Gitlab‑CI с помощью opencode‑cli.
Я всё‑таки родом из QA, так что в качестве примера буду использовать типичную для тестеров задачу — анализ прогона автотестов. Но в целом подход сгодится и для других задач, не связанных с написанием кода напрямую.
Упор постараюсь сделать на том, как исполнить это достаточно безопасно на обычной и всем привычной инфраструктуре: gitlab‑ci + раннеры в докере.
Рецепт
Шаг 1 — подготовить скилл и отладить его локально
Делаем репозиторий, в котором будут храниться скиллы, AGENTS.md с описанием проекта и инфраструктуры, файлы с конфигами для opencode и.gitlab‑ci.yml. В условиях небольших команд такой репозиторий можно сделать один на команду.
Структура проекта примерно следующая:
├── .agents │ └── skills │ ├── nightly-test-run-analysis │ │ └── SKILL.md │ └── testops-launch-report │ └── SKILL.md ├── .env ├── .gitlab-ci.yml ├── README.md ├── AGENTS.md ├── opencode.json ├── opencode_config_nightly-test-run-analysis │ └── opencode.json └── opencode_config_testops-launch-report └── opencode.json
Тут не совсем уж очевидными являются только директории opencode_config_*, но про них поговорим дальше.
А так алгоритм работы следующий:
Инженер клонирует себе подобный репозиторий.
Добавляет MCP для работы с необходимыми сервисами в opencode.json.
В сессии выдаёт агенту задачу — проанализируй последний прогон автотестов из ТестОПС.
Получает результат, а потом долго и томно поясняет агенту, как именно и какой прогон тестов надо анализировать, как и куда о результатах надо доложить.
В конце сессии просит агента из этой задачи сформировать скилл. Что бы результат был более предсказуемым, можно предварительно установить скилл для создания скиллов, вроде writing‑skills.
Дальше этим скиллом пользуется какое‑то время, исправляя и дополняя по мелочам. Ну и пушит «на всех».
После этого скилл можно попытаться завернуть в CI.
Шаг 2 — составляем строгий конфиг для opencode
Для разных задач мы составляем разные opencode.json файлы. Крайне полезное чтиво по теме — вот https://opencode.ai/v2/docs/config.
В каждом мы явно указываем модель и агента, описываем провайдера, перечисляем MCP, и если вы тоже решили использовать нестандартную директорию для скиллов — явно прописываем её в конфиге.
Секреты можно подкладывать через переменные окружения так: "apiKey": "{env:API_KEY}".
Крайне важно ограничить количество шагов для агента. Про шаги написано тут. В opencode.json это можно сделать так:
"agent": { "build": { "steps": 50 } },
Подбирать количество шагов можно, глядя в логи выполнения аналогичной задачи.
В секции permissions сперва необходимо запретить всё, а уже потом точечно разрешать только те инструменты, которые действительно необходимы агенту для выполнения задачи:
"permission": { "*": "deny", "external_directory": "deny", "read": { "*": "allow", "*.env": "deny", "*.env.*": "deny" }, "glob": "allow", "grep": "allow", "list": "allow", "skill": "allow", "todowrite": "allow", "TestOps__testops_find_launches": "allow", "TestOps__testops_get_launch_statistics": "allow", … }
Шаг 3 — проброс токенов и секретов в джобу
Тут всё стандартно, либо через Settings → CI/CD на уровне проекта, либо через Vault на уровне джобы. Важно напомнить, что для агента получать токены нужно с минимально необходимыми уровнями доступа. Желательно делать токен под конкретную задачу (главное потом в токенах не запутаться:) ).
Шаг 4 — настройка.gitlab‑ci
Вот пример джобы:
check_nightly_tests: stage: ai-agent image: ***/node:24-alpine3.22 timeout: 5 minutes variables: NEXUS_PROXY: "https://nexus***" NPM_CONFIG_REGISTRY: "${NEXUS_PROXY}/repository/npm-group/" OPENCODE_CONFIG: "$CI_PROJECT_DIR/opencode_config_testops-launch-report/opencode.json" OPENCODE_DISABLE_PROJECT_CONFIG: "1" OPENCODE_DISABLE_AUTOUPDATE: "1" OPENCODE_DISABLE_LSP_DOWNLOAD: "1" OPENCODE_DISABLE_MODELS_FETCH: "1" before_script: - npm install --global opencode-ai script: - opencode --version - 'opencode run -m "$OPENCODE_MODEL" --print-logs --format json "Используй скилл testops-launch-report для анализа последнего ночного прогона и напиши отчет в канал Nightly tests"' rules: - if: '$CI_PIPELINE_SOURCE == "schedule" && $CHECK_NIGHTLY_TEST == "True"' when: always - when: manual allow_failure: true
Тут есть ряд важных нюансов:
Берём минималистичный докер‑образ. Чем тоньше — тем лучше.
Выставляем timeout с небольшим запасом.
OPENCODE_CONFIG — явно указываем наш «максимально строгий» конфиг.
OPENCODE_DISABLE_PROJECT_CONFIG — opencode будет использовать только указанный конфиг, а не собирать единый из четырёх мест, как обычно.
«‑print‑logs ‑format json» — лучше больше логов, чем меньше логов.
$CHECK_NIGHTLY_TEST == «True» в блоке rules — костыль, чтобы можно было в шедуллере настроить запуск только этой джобы.
when: manual — этот пункт также обязателен, чтобы джоба не триггерилась, когда не нужно.
Шаг 5 — настройка шедуллера
В gitlab в Build → Pipeline scheduller можно настроить шедулер конкретной джобы, задав соответствующую переменную из блока rules в.gitlab‑ci в «True».
Шаг 6 — сетевые ограничения
Для меня этот шаг исключительно теоретический, так как у нас из раннеров CI и так доступны только избранные внутренние ресурсы. В дикий интернет прямого доступа нет. А ограничение по количеству шагов у агента должно сильно снизить вероятность побега через условный нексус:). Но забывать про этот шаг не стоит. Следует убедиться, что на уровне докер‑раннера или кубера настроены сетевые ограничения. Не стоит пытаться настроить фаервол внутри контейнера, так как это сильно менее надёжный метод защиты.
Результаты, Бонусы и Риски
Чего мы добились?
Ну, достаточно многого.
Во‑первых, для скептиков и консерваторов мы предоставили кучу примеров применения ИИ‑агентов именно на нашей инфраструктуре именно для наших задач (у нас на серверах крутятся вполне современные модели, доступные по запросу любому сотруднику, так что даже на подписку тратиться не нужно).
Во‑вторых, товарищей прогрессивных мы вывели из тени, дали возможность не только свою работу ускорять, но и коллегам помогать. А взамен получать почёт, уважение, очищение кармы (и чем там ещё могут в современном IT поощрять?).
В‑третьих, заложили основу для ревью подобных автоматизаций.
Ну и в‑четвёртых, смогли снять ряд рутинных задач с инженеров. Может даже производительность в итоге вырастет (но это не точно).
Создали ли мы какие‑то проблемы?
Да, не без этого.
Первое — люди, которые этим не интересовались и в этом не разбирались, начали массово с новым инструментом играться, и, вполне возможно, в итоге они проиграют. И придётся последствия расхлёбывать...
Второе — растёт количество нейрослопа ещё и на работе. Появляется куча каналов с отчётами, статистиками, аналитикой. Комменты в таск‑трекерах теперь похожи на эссе с таблицами, списками, структурой и выводами, и даже в личку бывает люди пишут вместо скупых 2–3 строк ответа целые сочинения по поллиста в минуту. Хотя уверен, что это временно.
Заключение
Вот так, вводя минимум новых инструментов и концепций мы и «автономных агентов» по расписанию запускать научились, и скептиков‑консерваторов мягко подсадили на полезный инструмент, и количество «теневого ИИ» уменьшили.
П. С.
Я недавно на Хабре мысль встретил, что статьи — это не столько про «рассказать о чём‑то», сколько про пообщаться с людьми. Вот и тут я очень рассчитываю на эффект такого общения. Напишите пожалуйста, если мы упустили что‑то важное, пропустили какой‑то нюанс, ну или в целом ерунду сотворили, и так больше никто не делает.