AI-агенту нельзя давать прод-ключи: новые control plane и approval-gates для действий, которые нельзя откатить
Я Denis Shokhirev, Agentic AI Systems Architect из Freiburg im Breisgau, Germany; в DennisCraft AI Studio я собираю production-grade AI-системы для DACH B2B на Claude, Supabase, n8n, Doppler и self-hosted Postgres. Самый неприятный момент в таких системах не “галлюцинация в чате”, а когда агент с реальными ключами уже готов удалить данные, перевести деньги, отправить письмо клиенту или изменить ACL — и откат либо дорогой, либо невозможен. Если у агента есть прямой доступ к production secrets, в
Я Denis Shokhirev, Agentic AI Systems Architect из Freiburg im Breisgau, Germany; в DennisCraft AI Studio я собираю production-grade AI-системы для DACH B2B на Claude, Supabase, n8n, Doppler и self-hosted Postgres. Самый неприятный момент в таких системах не “галлюцинация в чате”, а когда агент с реальными ключами уже готов удалить данные, перевести деньги, отправить письмо клиенту или изменить ACL — и откат либо дорогой, либо невозможен.
Если у агента есть прямой доступ к production secrets, вы смешали 2 роли в одной сущности: reasoning и authority. Это архитектурная ошибка. Я вижу ее регулярно в ранних agentic-проектах: сначала команда радуется, что агент “сам ходит в API”, потом начинает латать промпты, добавлять предупреждения и писать длинные system instructions. Но проблема не в промпте. Проблема в том, что модель получила право на необратимое действие без отдельного control plane.
Почему прямые прод-ключи у агента — плохая идея
У LLM нет встроенного понимания обратимости, юридической значимости действия и операционного blast radius. Она выбирает следующий шаг по вероятности и контексту. Даже если вы хорошо описали политику, это не равняется enforcement. OWASP в LLM Top 10 2025 отдельно выделяет excessive agency и insecure output handling как реальные классы риска для систем, где вывод модели напрямую вызывает действия: https://genai.owasp.org/llm-top-10/
Что именно ломается в проде
На практике я почти всегда вижу 4 класса ошибок:
| Класс действия | Пример | Почему опасно | Что делать |
|---|---|---|---|
| Data mutation | DELETE/UPDATE в Postgres | Потеря данных, нарушение аудита | Вынести в signed action + approval |
| External side effects | Письмо клиенту, webhook, ticket closure | Репутационный и договорный ущерб | Dry-run, diff, human gate |
| Privilege changes | Смена ролей, API scopes | Эскалация доступа | Только через policy engine |
| Financial actions | Инвойс, refund, payout | Необратимые деньги | 2-step approval + журнал |
Ключевой принцип простой: агенту можно давать capability на предложение действия, но не authority на его финальное выполнение. Это разница между “сгенерируй план” и “нажми кнопку в production”.
Как выглядит рабочий control plane
Вместо того чтобы класть prod API keys в среду выполнения агента, я разделяю систему на 3 слоя.
1. Reasoning plane
Здесь живет Claude или другой LLM. Он читает контекст, предлагает следующее действие, формирует аргументы. Но у него нет прямых секретов от production API. Максимум — доступ к read-only данным и к реестру разрешенных action types.
2. Policy and approval plane
Отдельный сервис принимает proposed action, нормализует ее в JSON, классифицирует риск и решает: auto-approve, require-human, deny. Здесь же хранятся правила по типу ресурса, сумме, среде, пользователю, времени и blast radius.
3. Execution plane
Только этот слой имеет короткоживущие credentials и право выполнить действие. Он исполняет не “произвольный tool call от модели”, а заранее описанный action contract с валидацией, идемпотентностью и аудитом.
from dataclasses import dataclass
from typing import Literal
@dataclass
class ProposedAction:
action_type: Literal["send_email", "run_sql", "issue_refund"]
payload: dict
reason: str
actor_id: str
environment: Literal["staging", "prod"]
def requires_human_approval(a: ProposedAction) -> bool:
if a.environment == "prod":
return True
if a.action_type in {"issue_refund", "run_sql"}:
return True
if a.action_type == "send_email" and a.payload.get("recipient_count", 1) > 5:
return True
return FalseЭто не сложная магия. Это обычное разделение обязанностей, только примененное к LLM-агентам.
Approval-gates должны быть формализованы, а не “на усмотрение промпта”
Я не считаю полезным правило “если действие кажется опасным, спроси человека”. Слово “кажется” здесь и есть дыра. Агент должен выдавать структурированное намерение, а gate — оценивать его по четким условиям.
Какие поля должны попадать в gate
Минимальный набор: action_type, target_resource, environment, initiator, expected impact, reversibility, idempotency key, human-readable diff. Если SQL меняет строки, нужен estimate affected rows. Если агент отправляет email, нужен список получателей и финальный body preview. Если меняется конфигурация, нужен before/after diff.
approval_rules:
- action_type: run_sql
environment: prod
require_human: true
- action_type: send_email
environment: prod
recipient_count_gt: 5
require_human: true
- action_type: issue_refund
amount_eur_gt: 0
require_human: true
- action_type: update_user_role
environment: any
require_human: trueТакой формат удобно хранить в Postgres или Supabase и вызывать из n8n workflow. В regulated-среде это важнее “автономности”, потому что аудитор смотрит не на красоту демо, а на то, кто, когда и по какому правилу разрешил действие.
Практический стек: что ставить вокруг агента уже сейчас
Если вы работаете на моем типовом стеке, базовая защита собирается без экзотики.
Secrets
Doppler или другой secret manager должен выдавать ключи только execution layer, а не LLM runtime. Модели не нужен permanent доступ к production tokens.
Code and prompt hygiene
Для репозитория полезны semgrep, bandit и gitleaks. bandit проверяет Python на небезопасные паттерны; gitleaks ищет утечки секретов; semgrep хорошо ловит policy violations в glue code. Это не решает проблему authority, но снижает вероятность банальных ошибок.
python -m pip install bandit
bandit -r app/
docker run --rm -v "$PWD:/repo" semgrep/semgrep semgrep \
--config=p/security-audit /repo
gitleaks detect --source . --verboseDatabase access
Для Postgres я предпочитаю отдельные DB roles: read_only_agent, action_executor, human_admin. Агент никогда не получает action_executor credentials. SQL на изменение либо проходит через хранимую процедуру с узким контрактом, либо уходит на approval.
Anthropic в документации по tool use и Claude Code прямо рекомендует ограничивать права инструментов и проверять действия вне модели, а не надеяться только на инструкции: https://docs.anthropic.com/ Это совпадает с тем, что я вижу в production. Инструкция полезна как UX-слой, но enforcement должен жить вне LLM.
Что считать необратимым действием в европейском B2B
Многие команды думают только про DELETE в базе. Это слишком узко. В DACH B2B необратимость часто юридическая или процессная, а не только техническая.
Примеры, которые я сразу отношу к gated actions
Отправка клиентского письма с обещанием SLA. Изменение KYC-статуса в fintech. Закрытие инцидента в логистике без подтверждения оператора. Массовое обновление персональных данных. Удаление или экспорт данных субъекта. Любое изменение retention policy. Все это нельзя сводить к “tool call from agent”.
Если у вас есть DSGVO obligations, журнал решений и approval trail уже сам по себе часть архитектуры. Когда приходит вопрос “почему система так поступила”, нужен не красивый reasoning trace модели, а конкретный audit record: кто инициировал, какое правило сработало, кто одобрил, какой payload был выполнен.
FAQ
Достаточно ли human-in-the-loop?
Нет, если он добавлен как ручная заплатка без формального action schema. Человек должен утверждать структурированное действие с diff и контекстом, а не читать свободный текст от агента и угадывать риск.
Можно ли дать агенту write-access только в staging?
Да, это нормальный шаг для ускорения цикла. Но не путайте staging autonomy с production authority: граница между ними должна быть жесткой и проверяемой.
Если действие обратимо, можно обойтись без approval?
Иногда да, если у вас есть идемпотентность, журнал и быстрый rollback. Но критерий “обратимо” надо определять на уровне системы, а не оставлять это на интерпретацию модели.
Нужен ли отдельный policy service для небольшой команды?
Даже в маленькой команде нужен хотя бы тонкий слой, который принимает proposed actions и применяет правила. Это может быть простой Python service с Postgres, не обязательно большой platform-проект.
Что делать первым делом в уже работающей agent-системе?
Инвентаризируйте все действия, которые агент может выполнить сегодня, и пометьте необратимые. Затем заберите production secrets из runtime агента и перенесите их в отдельный execution layer с approval и аудитом.
На каком этапе ваш LLM pipeline сегодня ловит больше всего проблем в проде: статический анализ, runtime sandbox или человеческое согласование перед действием? Мне правда интересно сравнить практику разных команд.
Я провожу бесплатный 30-мин stack audit для DACH founders, которые строят AI в regulated markets. Напишите мне в LinkedIn или в @ger_dennis_ai.
Solche Agenten baue ich für Betriebe in Südbaden und ganz Deutschland.
Schreiben Sie in zwei Sätzen, was bei Ihnen Zeit frisst – Antwort innerhalb von 24 Stunden.
Aus einem Ablauf ein System machen, das läuft
Gebaut für den Betriebsalltag, nicht als Demo.