Alejandro Rioja.
AI Agents

Агенты по Событиям vs Агенты по Расписанию: Какой Паттерн для Какой Задачи

Alejandro Rioja
Alejandro Rioja
6 мин чтения
TL;DR

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

Бесплатная рассылка

Каждую среду. 28 400+ читателей. Никакой воды.

Содержание

Обновлено май 2026.

TL;DR: Используй агентов по событиям, когда действие пользователя требует немедленного ответа — задержка больше нескольких секунд ломает опыт. Используй агентов по расписанию для пакетной или периодической работы, где тайминг предсказуем. Ограничение: агенты по событиям должны быть без состояния и быстрыми; агенты по расписанию могут быть с состоянием и медленнее.

[Взгляд оператора] Я запускаю 30+ продакшн-агентов для своего консалтингового бренда и Pickleland — площадки для пиклбола в Пфлюгервилле, Техас. Каждый из них относится к одному из двух паттернов: срабатывает по событию или срабатывает по часам. Ошибиться здесь — значит тратить деньги впустую и доставлять сломанный опыт.

Два паттерна простыми словами

Агент по событиям просыпается, потому что что-то случилось. Пришло бронирование. Был опубликован комментарий. Отправлена форма. Триггер внешний и непредсказуемый по времени. Задача: ответить быстро.

Агент по расписанию просыпается, потому что так сказали часы. Каждое утро в 7:00. Каждое воскресенье в 18:00. Каждый час в начале часа. Триггер внутренний и полностью предсказуемый. Задача: выполнить тщательную работу.

Вот и всё. Не усложняй. Архитектура следует из ответа на один вопрос: нужен ли пользователю или системе ответ прямо сейчас, или можно подождать до определённого времени?

По событиям: агент ответов в социальных сетях

Мой агент ответов в соцсетях срабатывает каждый раз, когда под отслеживаемым постом Facebook появляется новый комментарий. Агент читает комментарий, классифицирует намерение (вопрос, жалоба, похвала, спам), составляет ответ и публикует его — или отмечает для ручной проверки, если уверенность низкая.

Весь цикл должен завершаться менее чем за 30 секунд, иначе ответ кажется запоздалым. Это проблема паттерна по событиям.

Вот упрощённый Cloudflare Worker, который обрабатывает webhook от сервиса мониторинга соцсетей:

typescript
// workers/social-reply.ts
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    if (request.method !== "POST") {
      return new Response("Method not allowed", { status: 405 });
    }

    // Проверяем подпись webhook
    const sig = request.headers.get("x-webhook-signature") ?? "";
    const body = await request.text();
    const valid = await verifySignature(body, sig, env.WEBHOOK_SECRET);
    if (!valid) return new Response("Unauthorized", { status: 401 });

    const event = JSON.parse(body) as SocialCommentEvent;

    // Классифицируем и отвечаем — держим async, чтобы быстро вернуть 200
    env.REPLY_QUEUE.send(event);

    return new Response("OK", { status: 200 });
  },
};

// Потребитель очереди — выполняет реальную работу ИИ
export const queue: ExportedHandlerQueueHandler<Env, SocialCommentEvent> =
  async (batch, env) => {
    for (const msg of batch.messages) {
      const comment = msg.body;

      const classification = await classifyComment(comment.text, env);
      if (classification.intent === "spam") {
        msg.ack();
        continue;
      }

      const reply = await draftReply(comment, classification, env);

      if (classification.confidence > 0.85) {
        await postReply(comment.postId, comment.id, reply, env);
      } else {
        await flagForReview(comment, reply, env);
      }

      msg.ack();
    }
  };

Две вещи стоит отметить. Во-первых, обработчик fetch сразу возвращает 200 и передаёт реальную работу в очередь. Это сохраняет быстрый ответ на webhook и не даёт сервису мониторинга делать повторные попытки. Во-вторых, потребитель очереди выполняет реальный вызов ИИ — классификацию и составление ответа — без временного давления от открытого HTTP-соединения.

По расписанию: промоутер мероприятий Pickleland

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

Промоутер мероприятий Pickleland работает по cron, проверяет систему бронирований на мероприятия в ближайшие 4 дня, составляет посты для каждой подходящей группы Facebook и предоставляет их для моего просмотра перед публикацией.

typescript
// workers/event-promoter.ts
export default {
  async scheduled(
    event: ScheduledEvent,
    env: Env,
    ctx: ExecutionContext
  ): Promise<void> {
    ctx.waitUntil(runPromoter(env));
  },
};

async function runPromoter(env: Env): Promise<void> {
  // Получаем мероприятия из системы бронирования
  const upcomingEvents = await fetchUpcomingEvents(env, { daysAhead: 4 });

  if (upcomingEvents.length === 0) return;

  const drafts: PromoDraft[] = [];

  for (const event of upcomingEvents) {
    // Сопоставляем каждое мероприятие с подходящими FB-группами
    const groups = await matchFacebookGroups(event, env);

    for (const group of groups) {
      const post = await draftPromoPost(event, group, env);
      drafts.push({ event, group, post });
    }
  }

  // Сохраняем черновики в Airtable для проверки — ничего не публикуется автоматически
  await saveDraftsForReview(drafts, env);

  // Уведомляю себя через Slack
  await notifyOperator(
    `${drafts.length} промо-черновиков готовы к проверке`,
    env
  );
}

Конфигурация wrangler, связывающая всё воедино:

toml
# wrangler.toml
[[triggers]]
crons = ["0 18 * * 0"]  # Каждое воскресенье в 18:00 UTC

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

По расписанию: ежедневный брифинг

Каждое утро в 7:00 запускается мой агент ежедневного брифинга. Он забирает ночные письма, мой календарь, главные задачи и новости, которые я отметил как важные. Форматирует всё в один документ и помещает в папку AI Workspace.

Это чистое расписание. Нет никакого события, которое его бы запустило — я просто хочу его каждое утро перед началом работы.

typescript
// workers/daily-brief.ts
export default {
  async scheduled(
    event: ScheduledEvent,
    env: Env,
    ctx: ExecutionContext
  ): Promise<void> {
    ctx.waitUntil(buildDailyBrief(env));
  },
};

async function buildDailyBrief(env: Env): Promise<void> {
  const [emails, calendar, tasks] = await Promise.all([
    fetchOvernightEmails(env),
    fetchTodayCalendar(env),
    fetchTopTasks(env),
  ]);

  const brief = await synthesizeBrief({ emails, calendar, tasks }, env);

  await writeToWorkspace(brief, env);
}
toml
[[triggers]]
crons = ["0 7 * * *"]  # Каждый день в 7:00 UTC

Параллельный Promise.all сделан намеренно. У агентов по расписанию нет ожидающего человека — но они всё равно не должны быть медленнее, чем нужно. Получай все источники данных параллельно, потом один раз делай синтез ИИ.

Когда агенты по событиям дают сбой

Самый частый сценарий провала: кто-то создаёт агента по событиям, который делает слишком много работы в обработчике.

Приходит бронирование. Агент получает профиль клиента, обогащает его из трёх внешних API, запускает модель персонализации, записывает в CRM, отправляет письмо с подтверждением и обновляет дашборд. Всё это занимает 45 секунд. Платформа бронирования делает повторную попытку, потому что не получила 200 достаточно быстро. Теперь агент запускается дважды.

Исправь так же, как построен агент ответов в соцсетях: немедленно вернуть 200, отправить событие в очередь, пусть потребитель очереди асинхронно выполняет тяжёлую работу.

Другой сценарий провала: использовать события для работы, которая на самом деле периодическая. «Отправить еженедельный дайджест» — это не событие. Не подключай это к синтетическому cron webhook — используй нормальный запланированный триггер.

Когда агенты по расписанию дают сбой

Агенты по расписанию дают сбой, когда работа на самом деле чувствительна к задержке. Если пользователь отправляет форму, а обрабатывающий агент работает на 5-минутном cron, пользователь смотрит на спиннер до 5 минут. Это не плановое задание — это медленный агент по событиям, притворяющийся плановым.

Другой провал: агенты по расписанию, расширяющиеся до неограниченного объёма работы. Если cron запускается каждую минуту и каждый вызов может обрабатывать сотни записей, ты быстро упрёшься в лимиты CPU Cloudflare. Либо увеличь интервал cron, добавь очередь для ограничения работы на один вызов, либо переходи на Durable Objects для долгосрочной координации.

Смешивание паттернов: конвейер бронирований

Некоторые рабочие процессы по-настоящему требуют обоих. Конвейер бронирований Pickleland работает так:

  1. По событию: webhook нового бронирования → подтвердить бронирование, отправить клиенту чек, обновить доступность. Должно завершиться менее чем за 10 секунд.
  2. По расписанию: каждое воскресенье → просмотреть все бронирования за прошлую неделю, сформировать итоговый отчёт, отметить аномалии (дублирующие бронирования, необычные коэффициенты отмены).

Тот же домен, два паттерна, два агента. Агент по событиям отвечает за пользовательский опыт в реальном времени. Агент по расписанию отвечает за еженедельный операционный обзор. Они разделяют базу данных, но ничего больше.

Не пытайся объединить их в одного агента, который «делает всё». Получишь нечто слишком медленное для событий и слишком тесно связанное с потоком реального времени для пакетной работы.

Cloudflare Workers: почему это правильная инфраструктура для обоих

Cloudflare Workers нативно поддерживает оба паттерна:

Развёртывание на граничных узлах означает, что агенты по событиям быстро отвечают по всему миру. Бесплатного тарифа достаточно для прототипирования обоих паттернов без расходов. А единая конфигурация wrangler.toml означает, что не нужно управлять двумя отдельными инфраструктурными настройками для двух паттернов.

Единственное, что Workers не решает хорошо: агенты, которым нужно работать дольше нескольких минут. Для них используй Durable Objects или передавай работу на более долгоживущий бэкенд.

Вывод оператора

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

Читать дальше

Получайте ИИ-руководство на почту

Каждую среду. 28 400+ читателей. Никакой воды.

↵ — все результаты esc esc — закрыть