- BrainTools - https://www.braintools.ru -
Полгода назад по сети разошлась история про AI-агента, который слил 441 тысячу за один твит [1] — модель приняла решение, у неё был доступ к исполнению, и никто не стоял между решением и деньгами. С тех пор каждый раз, когда речь заходит про «дать агенту управлять чем-то важным», всплывает один и тот же страх [2]: а если он сделает глупость с реальными деньгами?
Я строю сервис, где AI-агент управляет рекламными кампаниями в Яндекс.Директе, Google Ads и VK — то есть ровно тем, где ошибка [3] агента стоит денег напрямую. И главный вопрос проектирования был не «как научить агента управлять рекламой», а «как сделать так, чтобы он физически не мог потратить деньги без человека».
Ниже — архитектура, в которой у агента нет ни одной кнопки, которая тратит бюджет сама. Разберу, где проходит граница между тем, что агент делает свободно, и тем, что требует подтверждения, как устроен этот контур, и почему я не доверяю агенту деньги, даже когда доверяю его аналитике.
Сразу честно про рамки: сервис в открытом бета-тесте, и — тьфу-тьфу — за время разработки агент ни разу не пытался сделать ничего катастрофического. Так что это статья не про пойманный инцидент, а про архитектуру, спроектированную так, чтобы инцидент был невозможен by design. Проверять её в бою будем на бете.
Сначала о том, почему это вообще нетривиально.
Современный подход к агентам — дать модели набор инструментов (tools) и позволить самой решать, какие вызывать. Через протокол MCP это делается красиво: описываешь инструменты, агент читает описания и оркестрирует их под задачу пользователя. «Проанализируй, какие кампании сливают бюджет, и оптимизируй» — агент сам ходит по метрикам, находит проблемы, принимает решения.
Проблема в последнем слове. Аналитику агенту доверить не страшно: ошибётся в выводе — поправишь. А вот исполнение решения, которое тратит деньги, — это точка невозврата. Агент, который неверно понял метрику и поднял ставку в десять раз, потратит реальный бюджет за минуты, и откатить это уже нельзя.
История с 441 тысячей — ровно про отсутствие этого барьера. Модель имела право исполнять, между её решением и деньгами никого не было. Мой вывод из неё простой: агенту можно дать думать, но нельзя дать платить в одиночку.
Вся архитектура строится на одном разделении. Инструменты агента делятся на два класса по признаку «тратит ли это деньги и меняет ли что-то необратимо».
Read-инструменты агент вызывает свободно, сколько нужно: получить баланс, список кампаний, метрики эффективности, найти аномалии, сравнить площадки, построить отчёт. Всё это только читает данные — навредить невозможно, поэтому агент оркестрирует их без ограничений.
Write-инструменты — те, что меняют состояние рекламы и тратят бюджет — их ровно три, и это сознательно короткий список: управление кампанией (пауза, возобновление, архивация), изменение ставки, изменение бюджета. Плюс создание объявления. Всё, что может стоить денег, собрано в этот узкий набор, и каждый из них проходит через контур подтверждения.
В коде это разделение — не пожелание, а жёсткая проверка. Write-инструмент физически не выполнится без права на запись у API-ключа, и в описании самого инструмента для агента стоит пометка, что операция разрушительная:
annotations: { readOnlyHint: false, destructiveHint: true },
// ...
requireWritePermission(authInfo); // упадёт без write-права
requirePlatformAccess(authInfo, params.platform);
Причём агент обязан объяснить, зачем он это делает — параметр reason со свободным текстом обязателен, минимум пять символов. Это не формальность: обоснование показывается человеку в момент подтверждения, чтобы он видел логику [4] агента, а не голое «изменить ставку на X».
Теперь главное — что происходит, когда агент хочет потратить деньги.
Перед выполнением write-операции сервис проверяет сумму, которую она затронет, против порога, заданного пользователем. Ниже порога — выполняется сразу (агенту не нужно дёргать человека из-за копеечной корректировки). Выше порога — вместо выполнения создаётся подтверждение (pending approval), и действие замирает до решения человека.
В коде это выглядит так: инструмент не исполняет действие напрямую, а сперва спрашивает у бэкенда, не превышен ли лимит, и при превышении заводит подтверждение:
const check = await checkSpendLimit({ userId, platform, amount });
if (check.exceedsThreshold) {
const approval = await createApproval({
userId, actionType: 'adjust_budget', platform,
description: `Изменить бюджет кампании X на ${amount} ₽`,
payload, // что именно исполнить после одобрения
expiresInHours: 24,
});
return `Действие требует подтверждения. Ссылка: /app/approvals`;
}
Ключевой момент: агент не исполняет отложенное действие — он его только предлагает. Само исполнение произойдёт, лишь когда человек нажмёт «одобрить» в личном кабинете, и уже не агент его выполнит, а отдельный серверный исполнитель, по сохранённому payload.
У подтверждения есть три свойства, каждое из которых закрывает свою дыру:
Срок годности. Подтверждение живёт заданное время (по умолчанию сутки) и потом истекает само. Это защита от ситуации, когда одобрение висит неделю, реклама за это время изменилась, а человек нажимает «да» на устаревшее решение. Истекло — деньги, зарезервированные под операцию, возвращаются.
Защита от двойного исполнения. Одобренное действие исполняется ровно один раз — на время исполнения ставится блокировка, и повторный клик или гонка двух вкладок не проведут операцию дважды:
const locked = await r.set(lockKey, '1', 'EX', 120, 'NX');
if (!locked) return { success: false, error: 'Approval is already being executed' };
Белый список исполняемого. Даже одобренное подтверждение может запустить только действие из явного списка разрешённых — три write-инструмента, и всё. Никакой одобренный payload не выполнит ничего за пределами этого списка, даже если бы кто-то попытался его подсунуть.
export const APPROVAL_EXECUTABLE_TOOL_NAMES = [
'manage_campaign', 'adjust_bid', 'adjust_budget',
] as const;
Итог этой конструкции: между решением агента потратить деньги и фактической тратой всегда стоит человек, у него перед глазами обоснование агента, а окно на раздумье ограничено по времени. Повторить историю с 441 тысячей тут структурно невозможно — агенту просто некуда нажать, чтобы потратить бюджет самому.
Отдельный слой защиты, о котором обычно не думают, — экономический. Каждый вызов инструмента стоит денег, списываемых с предоплаченного баланса пользователя.
Чтение метрики — полрубля, поиск аномалий или отчёт — полтора, write-операция — три рубля, создание объявления — пять. Read-операции дешёвые, потому что безопасные; действия дороже, потому что значимые.
Это не только модель монетизации, но и естественный ограничитель. Агент, застрявший в цикле и дёргающий инструменты по кругу, упрётся в баланс и остановится, а не будет молотить бесконечно. А когда одобрение отклоняется или истекает, списанная за него стоимость возвращается на баланс — платишь только за то, что реально произошло.
Теперь про то, чему агенту доверять как раз можно и нужно, — потому что статья была бы неполной, если бы создавала впечатление [5], что агент тут связан по рукам. Связан он ровно в одном: тратить деньги. Всё остальное — его сила.
Агент читает метрики со всех подключённых площадок сразу и отвечает на вопросы, которые иначе требуют ручного сведения трёх кабинетов: где сливается бюджет, какие кампании дают лучший ROAS, где просела конверсия за неделю. Инструмент поиска аномалий подсвечивает резкие изменения, которые легко пропустить глазами.
И то, что получается особенно наглядно, — агент собирает дашборды. Просишь «покажи сводку по рекламе за месяц» — агент собирает данные и генерирует дашборд с метриками, графиками и таблицами, который возвращается ссылкой:
Здесь агенту дана полная свобода, потому что дашборд ничего не тратит и ничего не ломает — это чтение, оформленное красиво. Виджеты четырёх типов: метрика, график (линия, столбцы, круг, область), таблица, текст. Агент сам решает, что показать под задачу, — и это ровно тот случай, где автономия модели работает на тебя без риска.
Коротко про механику, чтобы было понятно, что это не игрушка.
Сервис — это MCP-сервер, который подключается к любому MCP-совместимому клиенту (Claude, например) одной строкой конфига. После подключения агент видит инструменты и может ими пользоваться от лица пользователя.
Рекламные площадки подключаются через OAuth — Яндекс.Директ, Google Ads, VK. Токены хранятся зашифрованными, у каждого API-ключа своя область прав: можно выдать ключ только на чтение, тогда write-инструменты будут недоступны в принципе, даже до контура подтверждения. То есть у осторожного пользователя агент может быть вообще лишён доступа к тратам на уровне ключа.
Отдельная сложность, которую стоит упомянуть: каждая рекламная площадка устроена по-своему, и агенту нельзя показывать этот зоопарк.
У Яндекс.Директа своё API со своей моделью кампаний, у Google Ads — совершенно другое, с иерархией аккаунтов и своими типами ставок, у VK — третье. Метрики называются по-разному, ставки задаются в разных единицах, статусы кампаний не совпадают. Если бы агент видел три разных API напрямую, ему пришлось бы держать в контексте три несовместимые модели — и ошибаться на стыках.
Поэтому каждая площадка спрятана за адаптером с единым интерфейсом. Агент вызывает list_campaigns или adjust_bid одинаково для любой площадки, а адаптер переводит это в специфику конкретного API и приводит ответ к общему формату. Добавить новую площадку — значит написать ещё один адаптер, не трогая ни агента, ни контур подтверждения.
Это та же идея, что и с границей read/write: сложность прячется внутрь, наружу торчит простой и предсказуемый интерфейс. Агенту проще, ошибок меньше, а человек в контуре видит унифицированное «изменить бюджет кампании X на Y рублей», а не сырой ответ чужого API.
Можно было сделать проще — например, дать агенту всё, но с общим дневным лимитом трат. Я сознательно не пошёл этим путём, и вот почему.
Дневной лимит защищает от масштаба катастрофы, но не от самой ошибки. Агент всё равно потратит деньги не туда, просто не больше лимита в день. А человек узнает об этом постфактум. Контур подтверждения работает иначе: он ловит ошибку до траты, и не по сумме, а по факту — любое значимое действие проходит через живой взгляд.
Вот три подхода к тому, чтобы агент не разорил, рядом:
|
Подход |
Что защищает |
Слабое место |
|---|---|---|
|
Ничего, полный доступ |
ничего |
история с 441 тысячей |
|
Дневной лимит трат |
масштаб убытка |
ошибка всё равно случается, узнаёшь постфактум |
|
Человек в контуре (здесь) |
сам факт ошибочной траты |
меньше автономии: крупное ждёт одобрения |
Первый подход — это ровно то, что привело к катастрофе с твитом. Второй кажется разумным, но он про «потерять не слишком много», а не про «не потерять». Третий — единственный, где ошибочная трата не происходит вовсе, ценой того, что агент не всесилен.
Да, это менее автономно. Агент не может сам оптимизировать кампании ночью, пока ты спишь, — крупные изменения дождутся твоего одобрения. Но это осознанный размен: я выбираю чуть меньше автономии в обмен на то, что не проснусь с пустым рекламным бюджетом. Для денег это правильный размен.
Дать AI-агенту доступ к деньгам можно — но не давать ему право тратить их в одиночку. Вся архитектура сервиса построена вокруг одной границы: агент свободно читает, анализирует и предлагает, но любое действие, которое тратит бюджет, проходит через человека — с обоснованием агента перед глазами, с ограниченным окном на решение, с исполнением из белого списка и защитой от повторов.
История с агентом, слившим 441 тысячу, была про отсутствие этого барьера. Здесь барьер — центральный элемент конструкции, а не надстройка. Агент получился полезным ассистентом по рекламе, который при этом структурно не способен разорить.
Сервис в открытой бете. Если хотите подключить своего агента к рекламным кабинетам и посмотреть, как это работает на ваших данных, — ads.synapsea.agency [6], тестовый доступ бесплатный. За баг-репорты, особенно про обход контура подтверждения, благодарю продлением подписки — если найдёте способ заставить агента потратить деньги без одобрения, мне очень нужно об этом знать.
Процесс разработки пишу в личном канале — https://t.me/synapseaa [7]
А как вы относитесь к автономным агентам с доступом к деньгам — где для вас граница доверия?
Автор: ShyDamn
Источник [8]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/34428
URLs in this post:
[1] 441 тысячу за один твит: https://habr.com/ru/articles/1025110/
[2] страх: http://www.braintools.ru/article/6134
[3] ошибка: http://www.braintools.ru/article/4192
[4] логику: http://www.braintools.ru/article/7640
[5] впечатление: http://www.braintools.ru/article/2012
[6] ads.synapsea.agency: https://ads.synapsea.agency
[7] https://t.me/synapseaa: https://t.me/synapseaa
[8] Источник: https://habr.com/ru/articles/1061872/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1061872
Нажмите здесь для печати.