Как дать нейросети управлять рекламой и не разориться: MCP-сервер, где деньги тратит только человек. google ads.. google ads. llm.. google ads. llm. mcp.. google ads. llm. mcp. model context protocol.. google ads. llm. mcp. model context protocol. автоматизация.. google ads. llm. mcp. model context protocol. автоматизация. безопасность агентов.. google ads. llm. mcp. model context protocol. автоматизация. безопасность агентов. рекламный бюджет.. google ads. llm. mcp. model context protocol. автоматизация. безопасность агентов. рекламный бюджет. Я пиарюсь.

Полгода назад по сети разошлась история про AI-агента, который слил 441 тысячу за один твит — модель приняла решение, у неё был доступ к исполнению, и никто не стоял между решением и деньгами. С тех пор каждый раз, когда речь заходит про «дать агенту управлять чем-то важным», всплывает один и тот же страх: а если он сделает глупость с реальными деньгами?

Я строю сервис, где AI-агент управляет рекламными кампаниями в Яндекс.Директе, Google Ads и VK — то есть ровно тем, где ошибка агента стоит денег напрямую. И главный вопрос проектирования был не «как научить агента управлять рекламой», а «как сделать так, чтобы он физически не мог потратить деньги без человека».

Ниже — архитектура, в которой у агента нет ни одной кнопки, которая тратит бюджет сама. Разберу, где проходит граница между тем, что агент делает свободно, и тем, что требует подтверждения, как устроен этот контур, и почему я не доверяю агенту деньги, даже когда доверяю его аналитике.

Сразу честно про рамки: сервис в открытом бета-тесте, и — тьфу-тьфу — за время разработки агент ни разу не пытался сделать ничего катастрофического. Так что это статья не про пойманный инцидент, а про архитектуру, спроектированную так, чтобы инцидент был невозможен by design. Проверять её в бою будем на бете.

Проблема доверия агенту

Сначала о том, почему это вообще нетривиально.

Современный подход к агентам — дать модели набор инструментов (tools) и позволить самой решать, какие вызывать. Через протокол MCP это делается красиво: описываешь инструменты, агент читает описания и оркестрирует их под задачу пользователя. «Проанализируй, какие кампании сливают бюджет, и оптимизируй» — агент сам ходит по метрикам, находит проблемы, принимает решения.

Проблема в последнем слове. Аналитику агенту доверить не страшно: ошибётся в выводе — поправишь. А вот исполнение решения, которое тратит деньги, — это точка невозврата. Агент, который неверно понял метрику и поднял ставку в десять раз, потратит реальный бюджет за минуты, и откатить это уже нельзя.

История с 441 тысячей — ровно про отсутствие этого барьера. Модель имела право исполнять, между её решением и деньгами никого не было. Мой вывод из неё простой: агенту можно дать думать, но нельзя дать платить в одиночку.

Граница: read свободно, write — через человека

Вся архитектура строится на одном разделении. Инструменты агента делятся на два класса по признаку «тратит ли это деньги и меняет ли что-то необратимо».

Что агент делает сам, а что — только с подтверждением

Что агент делает сам, а что — только с подтверждением

Read-инструменты агент вызывает свободно, сколько нужно: получить баланс, список кампаний, метрики эффективности, найти аномалии, сравнить площадки, построить отчёт. Всё это только читает данные — навредить невозможно, поэтому агент оркестрирует их без ограничений.

Write-инструменты — те, что меняют состояние рекламы и тратят бюджет — их ровно три, и это сознательно короткий список: управление кампанией (пауза, возобновление, архивация), изменение ставки, изменение бюджета. Плюс создание объявления. Всё, что может стоить денег, собрано в этот узкий набор, и каждый из них проходит через контур подтверждения.

В коде это разделение — не пожелание, а жёсткая проверка. Write-инструмент физически не выполнится без права на запись у API-ключа, и в описании самого инструмента для агента стоит пометка, что операция разрушительная:

annotations: { readOnlyHint: false, destructiveHint: true },
// ...
requireWritePermission(authInfo);   // упадёт без write-права
requirePlatformAccess(authInfo, params.platform);

Причём агент обязан объяснить, зачем он это делает — параметр reason со свободным текстом обязателен, минимум пять символов. Это не формальность: обоснование показывается человеку в момент подтверждения, чтобы он видел логику агента, а не голое «изменить ставку на 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 тысячей тут структурно невозможно — агенту просто некуда нажать, чтобы потратить бюджет самому.

Prepaid-модель: агент платит за каждое действие

Отдельный слой защиты, о котором обычно не думают, — экономический. Каждый вызов инструмента стоит денег, списываемых с предоплаченного баланса пользователя.

Стоимость операций агента: платишь за действие, а не подписку

Стоимость операций агента: платишь за действие, а не подписку

Чтение метрики — полрубля, поиск аномалий или отчёт — полтора, write-операция — три рубля, создание объявления — пять. Read-операции дешёвые, потому что безопасные; действия дороже, потому что значимые.

Это не только модель монетизации, но и естественный ограничитель. Агент, застрявший в цикле и дёргающий инструменты по кругу, упрётся в баланс и остановится, а не будет молотить бесконечно. А когда одобрение отклоняется или истекает, списанная за него стоимость возвращается на баланс — платишь только за то, что реально произошло.

Что агент делает хорошо: аналитика и дашборды

Теперь про то, чему агенту доверять как раз можно и нужно, — потому что статья была бы неполной, если бы создавала впечатление, что агент тут связан по рукам. Связан он ровно в одном: тратить деньги. Всё остальное — его сила.

Агент читает метрики со всех подключённых площадок сразу и отвечает на вопросы, которые иначе требуют ручного сведения трёх кабинетов: где сливается бюджет, какие кампании дают лучший 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, тестовый доступ бесплатный. За баг-репорты, особенно про обход контура подтверждения, благодарю продлением подписки — если найдёте способ заставить агента потратить деньги без одобрения, мне очень нужно об этом знать.

Процесс разработки пишу в личном канале — https://t.me/synapseaa

А как вы относитесь к автономным агентам с доступом к деньгам — где для вас граница доверия?

Автор: ShyDamn

Источник