Агенты опроса в AI-ассистентах: 11 паттернов реализации
Надёжные шаблоны опроса для ИИ-агентов.
Агенты опроса (Polling agents) — одна из наименее привлекательных частей архитектуры ИИ-ассистентов, но при этом одна из самых полезных.
Обычный чат-ассистент ждет, пока пользователь задаст вопрос. Агент опроса постоянно наблюдает. Он проверяет источник данных, замечает изменения, решает, имеют ли они значение, и затем предпринимает действие. Это действие может быть уведомлением, сводкой, черновиком, вызовом инструмента или полным рабочим процессом.
Таким образом ассистент переходит от режима «ответь на мой вопрос» к режиму «последи за этим для меня». Вместо реактивного подхода он становится фоновым процессом, который замечает события от имени пользователя и действует при выполнении определенных условий.

Важный архитектурный принцип прост: не возлагайте на языковую модель ответственность за время, состояние, повторные попытки или блокировки. Используйте для этого обычную бэкенд-инфраструктуру. Используйте модель там, где она действительно ценна: для интерпретации сложного контекста, принятия семантических решений и генерации полезного текста.
Что такое агент опроса?
Агент опроса — это фоновый процесс, который периодически проверяет источник и запускает действие ассистента при выполнении определенного условия. В более широком стеке AI Systems — где ассистент сочетает LLM, память, инструменты, маршрутизацию и наблюдаемость — слой опроса делает ассистента проактивным, а не просто реактивным. Для полного обзора пяти слоев см. Архитектура ИИ-ассистентов: LLM, память, инструменты, маршрутизация, наблюдаемость.
Примеры:
- Проверять входящие сообщения каждое утро и суммировать важные.
- Следить за списком задач в Notion и выполнять следующую задачу.
- Мониторить issue на GitHub до изменения его статуса.
- Опросить долгую задачу ИИ до получения результата.
- Проверять доступность слота для бронирования, пока он не освободится.
- Следить за порталом поставщика до появления документа.
- Сканировать новые научные статьи раз в неделю и суммировать релевантные.
Практический агент опроса имеет пять обязанностей:
- Пробуждаться в нужное время.
- Читать данные из источника.
- Запоминать то, что уже было обработано.
- Решать, имеет ли новое состояние значение.
- Действовать один раз, безопасно, без повторений.
Типичный рабочий процесс в продакшене выглядит так:
планировщик
-> воркер опроса
-> исходная система
-> хранилище состояния
-> детерминированные фильтры
-> опциональная оценка LLM
-> действие ассистента
Эта структура скучна в самом лучшем смысле этого слова. Скучные системы легче отлаживать в 2 часа ночи.
Состояние, необходимое каждому агенту опроса
Агентам опроса требуется надежное состояние (durable state). Истории диалога недостаточно. Ассистент может помнить разговор, но системе требуется надежная операционная запись.
Хорошая запись состояния опроса обычно содержит:
{
"poll_id": "poll_123",
"user_id": "user_456",
"source_type": "notion",
"source_ref": "database_tasks",
"condition": "взять одну задачу в состоянии Todo и выполнить её",
"interval_seconds": 600,
"last_run_at": "2026-06-19T01:00:00Z",
"next_run_at": "2026-06-19T01:10:00Z",
"last_seen_cursor": "cursor_or_timestamp",
"last_result_hash": "b64e8a...",
"failure_count": 0,
"status": "active"
}
Точная схема зависит от источника, но большинству систем нужны эти концепции.
Определение опроса
Это описывает, что наблюдает агент и почему.
poll_id
user_id
workspace_id
source_type
source_ref
condition_text
priority
status
Например:
source_type: notion
source_ref: Tasks database
condition_text: Найти одну задачу Todo, забрать её, выполнить, отметить как Complete.
Расписание
Это описывает, когда агент должен запускаться.
interval_seconds
cron_expression
timezone
last_run_at
next_run_at
jitter
Для агента Hermes, проверяющего Notion каждые 10 минут:
interval_seconds: 600
timezone: Australia/Melbourne
Курсор или снимок (Snapshot)
Это помогает агенту избежать повторной обработки одних и тех же данных.
В зависимости от источником это может быть:
last_seen_id
last_seen_timestamp
api_cursor
etag
version
content_hash
Для очереди задач в Notion курсор может быть менее важен, чем статус задачи и поля захвата (claim). Для Gmail, GitHub или API синхронизации курсор обычно критичен.
Захват или аренда (Claim or Lease)
Это предотвращает выполнение одной и той же работы двумя воркерами.
claimed_by
claimed_at
claim_expires_at
run_id
Например, задача в Notion может быть изменена с:
Status: Todo
на:
Status: InProgress
ClaimedBy: hermes
ClaimedAt: 2026-06-19T01:00:00Z
ClaimExpiresAt: 2026-06-19T01:30:00Z
RunId: run_789
Это разница между надеждой на то, что только один воркер возьмет задачу, и наличием в системе протокола захвата.
Запись выполнения
Это фиксирует, что произошло во время запуска.
run_id
poll_id
source_object_id
started_at
finished_at
status
items_checked
items_changed
decision_summary
error
Запись выполнения должна храниться в бэкенде ассистента, а не только в Notion или другом внешнем инструменте. Notion хорош для видимости для человека. Он не идеален в качестве единственного журнала выполнения.
Запись дедупликации
Это предотвращает дублирование уведомлений или повторяющиеся действия.
dedupe_key
poll_id
source_object_id
condition_version
action_type
delivered_at
Например:
user_456:poll_123:notion_page_999:execute:v1
Если то же действие попытается выполниться снова, система сможет подавить его.
Метод 1: Воркер опроса по расписанию
Это самый простой надежный паттерн.
Планировщик просыпается через фиксированные интервалы и вызывает воркер. Воркер читает источник, обновляет состояние и запускает действие ассистента, если это необходимо.
планировщик
-> воркер
-> API источника
-> база данных
-> действие ассистента
Как это работает
Планировщик отвечает за время. Это может быть cron, облачный планировщик, Kubernetes CronJob или небольшой внутренний планировщик.
Каждый интервал он запускает воркер. Воркер загружает конфигурацию, запрашивает целевой источник, сравнивает результат с сохраненным состоянием и действует при необходимости.
Для простого ассистента этого часто достаточно. Одиночный планировщик и легкий воркер могут обрабатывать десятки ежедневных проверок без необходимости использования очередей, аренд или распределенной координации.
Модель состояния
Планировщик хранит очень мало данных. Обычно он знает только, когда запускать задачу.
База данных приложения хранит важное состояние:
определение опроса
расписание
курсор или снимок
время последнего запуска
счетчик ошибок
статус
Воркер должен быть без состояния (stateless). Он может удерживать временные данные во время выполнения, но надежная истина должна быть в базе данных.
Пример потока
Каждые 10 минут:
запустить воркер опроса Hermes
Воркер:
загрузить активную конфигурацию опроса
запросить источник
сравнить с предыдущим состоянием
выполнить детерминированные проверки
вызвать LLM только если нужно
обновить состояние
сгенерировать событие ассистента
Лучшее применение
Используйте воркеры опроса по расписанию для:
- Ежедневных сводок.
- Часовых проверок.
- Мелких внутренних автоматизаций.
- Простых задач «последи за этим».
- Задач ассистента с низким и средним объемом.
Недостатки
Опрос по расписанию прост для понимания, но может стать хрупким при масштабировании. Если много опросов запускаются одновременно, вы можете перегрузить воркеры или достичь лимитов скорости провайдера. Повторные попытки также могут стать хаотичными, если планировщик напрямую запускает работу.
Метод 2: Воркеры опроса на основе очередей
Опрос на основе очередей обычно является лучшим вариантом по умолчанию для ИИ-ассистентов в продакшене.
Планировщик не выполняет опрос напрямую. Он кладет задачу в очередь. Воркеры потребляют задачи из очереди.
планировщик
-> очередь
-> пул воркеров
-> API источника
-> хранилище состояния
-> действие ассистента
Как это работает
Планировщик сканирует просроченные опросы и ставит задачи в очередь. Воркеры забирают задачи, когда у них есть мощность.
Это дает вам обратное давление (backpressure). Если система занята, задачи ждут в очереди, вместо того чтобы перегружать API источника или провайдера LLM.
Модель состояния
База данных хранит состояние опроса:
poll_id
user_id
source_ref
condition_text
next_run_at
cursor
status
failure_count
Сообщение в очереди должно быть маленьким:
{
"poll_id": "poll_123",
"scheduled_for": "2026-06-19T01:10:00Z",
"attempt": 1
}
Воркер загружает полное состояние из базы данных при старте.
Пример потока
Каждую минуту:
планировщик находит опросы, где next_run_at <= now
планировщик ставит задачи в очередь
Воркеры:
забирают задачи из очереди
блокируют или арендуют опрос
запрашивают источник
обновляют состояние
генерируют действие ассистента если нужно
устанавливают next_run_at
Лучшее применение
Используйте опрос на основе очередей для:
- Многопользовательских ИИ-ассистентов.
- Множества одновременных опросов.
- Интеграций с лимитами скорости.
- Повторяемой фоновой работы.
- Задач, которые могут занимать разное количество времени.
- SaaS-продуктов, где важна надежность.
Недостатки
Очереди добавляют инфраструктуру. Вам нужна обработка мертвых писем, идемпотентность, таймауты видимости и политики повторных попыток. Это стоит того для продакшен-систем, но, вероятно, избыточно для маленького прототипа.
Метод 3: Внешний инструмент как очередь задач
Это паттерн в примере Notion плюс Hermes.
Внешний инструмент — это не просто источник данных. Он становится ориентированным на человека интерфейсом очереди задач. Агент периодически проверяет инструмент, захватывает одну задачу, выполняет ее и обновляет статус задачи.
планировщик
-> воркер Hermes
-> база данных Notion
-> захватить одну задачу
-> выполнить задачу
-> обновить статус Notion
Как это работает
Каждые 10 минут Hermes запрашивает базу данных Notion на наличие одной задачи в состоянии Todo. Он выбирает следующую задачу, обычно по приоритету и времени создания. Затем он захватывает задачу, установив статус InProgress.
После этого Hermes выполняет задачу. Если выполнение успешно, он помечает задачу как Complete. Если выполнение завершается ошибкой, он помечает задачу как Failed или возвращает её в Todo с счетчиком повторных попыток.
Модель состояния
Notion хранит ориентированное на человека состояние задачи:
Title
Description
Status: Todo | InProgress | Complete | Failed
Priority
CreatedAt
ClaimedBy
ClaimedAt
ClaimExpiresAt
RunId
RetryCount
LastError
CompletedAt
Бэкенд Hermes хранит операционное состояние выполнения:
run_id
notion_page_id
started_at
finished_at
execution_status
tool_calls
LLM trace
error details
idempotency_key
Это разделение важно. Notion отлично подходит для видимости и ручного редактирования. Бэкенд Hermes лучше подходит для журналов, повторных попыток, дедупликации и истории аудита.
Пример потока
Каждые 10 минут:
Hermes просыпается
Hermes:
запросить Notion на одну задачу где Status = Todo
отсортировать по Priority, CreatedAt
обновить выбранную задачу на InProgress
установить ClaimedBy, ClaimedAt, ClaimExpiresAt, RunId
выполнить задачу
записать журнал выполнения
установить статус задачи Complete или Failed
Лучшее применение
Используйте этот паттерн, когда:
- Люди уже управляют работой в Notion, Jira, Linear, Trello или другом инструменте.
- Вы хотите, чтобы ассистент обрабатывал видимые задачи.
- Доска задач является пользовательским интерфейсом.
- Вам нужна простая модель автоматизации с участием человека (human-in-the-loop).
Недостатки
Внешние инструменты редко бывают идеальными очередями. Атомарный захват может быть ограничен. Согласованность запросов может отставать. Могут применяться лимиты скорости. Если агент может запускаться в нескольких экземплярах, вам нужна тщательная стратегия захвата или аренды.
Практическая рекомендация — использовать Notion как ориентированный на человека почтовый ящик задач, сохраняя все журналы выполнения, записи о повторных попытках, трассировки и ключи идемпотентности в Hermes. Notion дает пользователям видимость; Hermes сохраняет надежность системы. Для диспетчера и механики конкурентности, лежащих в основе этого паттерна в Hermes, см. Kanban в агенте Hermes для self-hosted LLM рабочих процессов.
Метод 4: Долгоживущий цикл воркера
Долгоживущий цикл — это самая простая реализация.
while True:
due_polls = db.find_due_polls()
for poll in due_polls:
run_poll(poll)
sleep(30)
Этот паттерн объединяет планирование и выполнение в одном сервисе, что делает его самой простой стартовой точкой для фоновой работы агентов.
Как это работает
Процесс воркера работает непрерывно. Каждые несколько секунд или минут он проверяет базу данных на наличие просроченных опросов и выполняет их. Это легко построить, легко рассуждать о и быстро итерировать во время разработки.
Модель состояния
База данных все еще хранит надежное состояние:
конфигурация опроса
next_run_at
курсор
последний результат
счетчик ошибок
статус
Память процесса должна содержать только временное состояние:
текущий пакет
кратковременный кэш
запущенный run
Никогда не храните важный прогресс только в памяти. Если процесс упадет, любое состояние, которое не было записано в надежное хранилище, исчезнет, и следующий запуск не будет знать, на чем остановиться.
Лучшее применение
Используйте долгоживущие циклы для:
- Прототипов.
- Локальной разработки.
- Внутренних инструментов.
- Систем с одним арендатором.
- Агентов с низким объемом.
Недостатки
Этот паттерн становится рискованным с несколькими репликами. Без аренд два воркера могут выполнить один и тот же опрос. Также отсутствуют операционные функции реальной очереди или движка рабочих процессов.
Долгоживущий цикл — не ошибка как стартовая точка, но это не распределенный планировщик, и к нему не следует относиться как к такому. Как только вам понадобятся несколько реплик или более сильные гарантии надежности, вам придется перейти к одному из вышеуказанных структурированных паттернов.
Метод 5: Webhook-first с опросом как резервным
Если источник поддерживает вебхуки, используйте их. Опрос часто должен быть резервным, а не основным механизмом.
внешняя система
-> конечная точка вебхука
-> хранилище событий
-> действие ассистента
опрос согласования
-> API источника
-> сравнить с хранилищем событий
-> восстановить пропущенные события
Как это работает
Внешняя система отправляет события в вашу конечную точку вебхука, когда что-то меняется. Ваша система сохраняет событие и обрабатывает его асинхронно.
Более медленный опрос согласования запускается каждые несколько часов или раз в день. Он проверяет, были ли пропущены какие-либо события.
Модель состояния
Хранилище событий записывает входящие вебхуки:
event_id
source_type
source_object_id
event_type
received_at
payload_hash
processed_at
signature_valid
Опрос согласования хранит:
last_reconciliation_at
last_seen_cursor
last_seen_version
Таблица объектов источника хранит последнее известное состояние:
external_id
current_status
external_updated_at
last_processed_event_id
Лучшее применение
Используйте архитектуру webhook-first для:
- Событий GitHub.
- Событий Stripe.
- Событий Slack.
- Обновлений CRM.
- Уведомлений о развертывании.
- Систем тикетов.
Недостатки
Вебхуки требуют публичной конечной точки, проверки подписи, защиты от повторной отправки и дедупликации событий. Некоторые провайдеры также отправляют неполные события, поэтому вам все равно может понадобиться получить полный объект.
Тем не менее, если существуют хорошие вебхуки, опрос каждую минуту обычно является расточительством.
Метод 6: Опрос фоновых задач на стороне провайдера
Иногда то, что опрашивается, — это сама задача ИИ.
Приложение запускает долгоживущую задачу провайдера, сохраняет идентификатор задачи и позже проверяет, завершена ли она.
приложение
-> запустить фоновую задачу ИИ
-> сохранить ID задачи провайдера
-> опросить статус
-> получить результат
-> уведомить пользователя
Как это работает
Ассистент запускает задачу у провайдера. Провайдер возвращает ID. Ваш бэкенд сохраняет этот ID и проверяет его статус, пока задача не завершится успешно, не провалится, не истечет или не завершится по таймауту.
Модель состояния
Ваш бэкенд хранит:
assistant_task_id
provider_job_id
user_id
status
created_at
last_checked_at
expires_at
result_ref
Провайдер хранит временное состояние задачи и вывод.
Если вывод имеет значение, скопируйте его в собственное надежное хранилище сразу после завершения задачи. Хранилище результатов на стороне провайдера имеет короткие окна удержания и не является заменой правильного архива в вашей собственной системе.
Лучшее применение
Используйте опрос фоновых задач на стороне провайдера для:
- Долгих исследовательских задач ИИ.
- Обработки больших документов.
- Анализа кодовой базы.
- Генерации отчетов.
- Задач извлечения данных.
- Задач, превышающих обычные таймауты HTTP-запросов.
Недостатки
Этот паттерн решает одну проблему: ожидание долгой задачи провайдера. Он не заменяет ваш движок рабочих процессов, планировщик, очередь или хранилище бизнес-состояния.
Метод 7: Надежный движок рабочих процессов
Надежный движок рабочих процессов управляет долгоживущим выполнением, таймерами, повторными попытками и восстановлением. Temporal — наиболее распространенный выбор для бэкендов ассистентов на Go и Python; для полного руководства по реализации см. Реализация приложений рабочих процессов с Temporal на Go.
Вместо ручной настройки каждого ожидания и повторной попытки, вы моделируете процесс как рабочий процесс.
движок рабочих процессов
-> активность: проверить источник
-> таймер: ждать
-> активность: оценить результат
-> активность: уведомить пользователя
Как это работает
Рабочий процесс запускается один раз, а затем управляет собственным ожиданием. Он может спать минуты, дни или недели. Если процесс воркера упадет, движок рабочих процессов может возобновить работу из записанного состояния.
Модель состояния
Движок рабочих процессов хранит:
workflow_id
история выполнения
состояние таймера
попытки активности
политика повторных попыток
текущее состояние рабочего процесса
База данных вашего приложения хранит:
определение опроса для пользователя
ссылки авторизации
бизнес-записи
записи уведомлений
Движок рабочих процессов владеет состоянием процесса — историей выполнения, таймерами, повторными попытками и попытками активности. Ваша база данных владеет бизнес-состоянием — конфигурациями пользователя, записями авторизации, уведомлениями и журналами аудита. Разделение этих слоев предотвращает превращение каждого из них в запутанный гибрид обоих.
Лучшее применение
Используйте надежные рабочие процессы для:
- Многошаговых бизнес-процессов.
- Долгих автоматизаций.
- Потоков одобрения человеком.
- Надежных повторных попыток.
- Аудируемой фоновой работы.
- Процессов, которые должны возобновляться после сбоя.
Недостатки
Движки рабочих процессов добавляют концепции и инфраструктуру. Они великолепны, когда процесс важен, но тяжелы для простых часовых проверок.
Метод 8: Постоянный runtime агента
Некоторые фреймворки агентов могут сохранять состояние агента, делать контрольные точки выполнения и возобновлять работу позже.
Это полезно, когда сам агент имеет многошаговый процесс рассуждений.
планировщик или рабочий процесс
-> runtime агента
-> загрузить контрольную точку
-> вызвать инструменты
-> сохранить контрольную точку
-> возобновить позже
Как это работает
Внешний планировщик или рабочий процесс запускает агента. Runtime агента загружает предыдущее состояние, выполняет следующий шаг, вызывает инструменты при необходимости и пишет контрольную точку.
Runtime агента не должен быть вашим единственным планировщиком. Его лучше рассматривать как слой рассуждений внутри более крупной архитектуры бэкенда.
Модель состояния
Хранилище контрольных точек агента содержит:
текущий узел
сообщения
выводы инструментов
промежуточное состояние рассуждений
отложенное действие
Долгосрочная память содержит:
устойчивые предпочтения пользователя
факты
контекст проекта
ссылки на источники
Операционное состояние по-прежнему принадлежит где-то еще:
расписание опроса
курсор
статус
счетчик повторных попыток
записи дедупликации
Пользовательское правило: память — это не курсор, а контрольная точка — не очередь. Память агента хранит то, что знает модель; операционное состояние отслеживает, где находится процесс и что он сделал. Смешение этих двух приводит к тонким ошибкам, которые проявляются только при конкурентном доступе или после перезапуска. Полное пространство дизайна для рабочей памяти, надежного состояния и слоев извлечения описано в Системы памяти в ИИ-ассистентах.
Лучшее применение
Используйте постоянный runtime агента для:
- Многошаговых исследований.
- Агентов, которые приостанавливаются и возобновляются.
- Работы с участием человека.
- Рассуждений с интенсивным использованием инструментов.
- Задач, где контекст накапливается со временем.
Недостатки
Персистентность агента не то же самое, что операционная надежность. Вам все еще нужны планирование, блокировки, повторные попытки, лимиты скорости и журналы аудита.
Метод 9: Синхронизация базы данных плюс оценка изменений
В этом паттерне опрос используется для синхронизации внешних данных в вашу собственную базу данных. Затем ассистент реагирует на изменения в локальной базе данных, а не запрашивает внешние API напрямую при каждом цикле оценки.
синхронизатор опроса
-> внешний API
-> локальная база данных
-> оценщик изменений
-> действие ассистента
Это разделяет синхронизацию данных и интеллект ассистента. Воркер синхронизации отвечает за обновление локальных записей; оценщик отвечает за решение, что делать с изменениями. Каждый слой можно тестировать, мониторить и масштабировать независимо.
Как это работает
Воркер синхронизации периодически получает внешние изменения и записывает нормализованные записи в вашу базу данных. Второй воркер или поток изменений обнаруживает обновленные строки и решает, должен ли ассистент действовать.
Модель состояния
Таблица синхронизации хранит:
external_id
source_type
raw_payload
normalized_fields
external_updated_at
synced_at
version
content_hash
Состояние синхронизации хранит:
source_cursor
last_sync_at
rate_limit_status
failure_count
Таблица оценки ассистента хранит:
object_id
evaluation_status
last_evaluated_hash
decision
notification_id
Лучшее применение
Используйте этот паттерн для:
- Синхронизации CRM.
- Систем тикетов.
- Бухгалтерских документов.
- Инвентаря продуктов.
- Отзыва соответствия (compliance review).
- Индексирования поиска.
- Внутренних дашбордов.
Недостатки
Синхронизация всего может быть дорогой и ненужной. Она также может создать обязательства по конфиденциальности и удержанию данных. Используйте этот паттерн, когда локальные данные имеют ценность за пределами одного действия ассистента.
Метод 10: Адаптивный опрос
Адаптивный опрос изменяет частоту на основе состояния, срочности или недавней активности.
активный объект: опрос каждые 1 минуту
ожидание объекта: опрос каждые 1 час
устаревший объект: опрос раз в день
завершенный объект: остановить опрос
Как это работает
После каждого запуска воркер решает, когда должен произойти следующий запуск.
Если объект недавно изменился, опрашивайте чаще. Если ничего не менялось долгое время, замедлите. Если задача завершена, остановитесь.
Модель состояния
Состояние опроса включает:
current_interval
minimum_interval
maximum_interval
backoff_policy
last_activity_at
priority
stop_condition
Снимок источника включает:
status
updated_at
activity_level
expected_next_change
Лучшее применение
Используйте адаптивный опрос для:
- Статуса развертывания.
- Отслеживания доставки.
- Доступности слотов календаря.
- Мониторинга цен.
- Задач сборки.
- Долгих задач провайдера.
- Лютого источника с всплесками обновлений.
Недостатки
Адаптивный опрос может быть сложнее для анализа. Если задача должна выполняться в строго определенное время, держитесь его. Не делайте задачи соответствия (compliance jobs) «умными».
Метод 11: Семантический опрос с оценщиком LLM
Семантический опрос используется, когда условие размыто.
Код может ответить:
Статус равен Complete?
Цена ниже 100?
Есть ли новое сообщение?
LLM может помочь ответить:
Звучит ли это письмо срочным?
Вероятно ли, что этот клиент недоволен?
Реlevant ли эта научная статья?
Требует ли это изменение моего внимания?
Как это работает
Воркер сначала применяет дешевые детерминированные фильтры. Только кандидаты идут к LLM.
новый элемент?
соответствует фильтрам источника?
не обработан ранее?
не очевидно нерелевантен?
Затем LLM оценивает меньший набор кандидатов и возвращает структурированный вывод.
{
"should_notify": true,
"urgency": "high",
"reason": "Клиент сообщает о сбое в производстве."
}
Модель состояния
Определение опроса хранит:
semantic_condition
examples
negative_examples
user_preference_summary
model_config
Журнал оценки хранит:
input_reference
model
prompt_version
structured_output
confidence
cost
latency
Состояние опроса хранит:
last_seen_ids
last_evaluated_hashes
last_decision
last_decision_reason
Лучшее применение
Используйте семантический опрос для:
- Обнаружения важных писем.
- Мониторинга настроения клиентов.
- Исследовательских оповещений.
- Обнаружения возможностей для продаж.
- Триажа безопасности.
- Исполнительных сводок.
Недостатки
Вызовы LLM стоят денег и добавляют задержку. Они также могут быть неконсистентными, если промпты и схемы неточны. Используйте детерминированные фильтры сначала. Обращайтесь к модели только тогда, когда действительно нужно суждение.
Таблица решений: Выбор метода агента опроса
| Метод | Лучшее применение | Плюсы | Минусы |
|---|---|---|---|
| Воркер опроса по расписанию | Простые повторяющиеся задачи ассистента | Легко строить, легко отлаживать, минимальная инфраструктура | Ограниченное масштабирование, базовые повторные попытки, может перегрузить воркеры, если много опросов срабатывают вместе |
| Воркеры опроса на основе очередей | Продакшен-ассистенты SaaS с множеством пользователей | Масштабируемо, устойчиво, поддерживает повторные попытки и обратное давление | Требует инфраструктуры очередей, идемпотентности, обработки мертвых писем |
| Внешний инструмент как очередь задач | Выполнение задач на базе Notion, Jira, Linear, Trello | Дружелюбно к человеку, легко проверять, работает с существующими рабочими процессами | Внешние инструменты не являются идеальными очередями, атомарный захват может быть сложным |
| Долгоживущий цикл воркера | Прототипы и внутренние инструменты | Очень просто, быстро внедрять, мало движущихся частей | Слабая надежность, плохое поведение с несколькими репликами, ограниченный операционный контроль |
| Webhook-first с опросом как резервным | Интеграции, управляемые событиями | Быстрая реакция, меньше вызовов API, согласование ловит пропущенные события | Нужна публичная конечная точка, валидация событий, дедупликация, поддержка вебхуков провайдером |
| Опрос фоновых задач на стороне провайдера | Долгие задачи ИИ провайдера | Обрабатывает медленные задачи ИИ, простая модель статуса, хорош для асинхронного UX | Управляет только статусом задачи провайдера, а не полным бизнес-процессом |
| Надежный движок рабочих процессов | Долгие многошаговые процессы | Сильные повторные попытки, таймеры, история аудита, восстановление после сбоев | Больше инфраструктуры и концепций, тяжел для простого опроса |
| Постоянный runtime агента | Агенты с многошаговым рассуждением | Сохраняет контекст агента, поддерживает паузу и возобновление, хорош для задач с инструментами | Не является заменой планировщика или очереди, все еще нужен операционный бэкенд |
| Синхронизация БД плюс оценка изменений | Системы, где внешние данные имеют локальную ценность | Чистое разделение, локальная отчетность, меньше повторяющихся внешних вызовов | Больше хранилища, больше сложности синхронизации, возможные проблемы конфиденциальности и удержания |
| Адаптивный опрос | Источники со всплесками или задачи с переменной срочностью | Снижает затраты, уважает лимиты скорости, реагирует быстрее, когда активность высока | Сложнее анализировать, не идеален для строгих расписаний |
| Семантический опрос с оценщиком LLM | Размытые условия, требующие суждения | Обрабатывает намерения на естественном языке, полезные сводки, гибкие решения | Стоимость, задержка, риск качества промпта, не должен заменять простые проверки кода |
Рекомендуемая архитектура по умолчанию
Для большинства продакшен-ассистентов ИИ начните с этого:
таблица опросов
-> планировщик
-> очередь
-> безсостоятельные воркеры
-> детерминированные фильтры
-> опциональный оценщик LLM
-> уведомление или действие ассистента
Минимальная схема:
CREATE TABLE polls (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
source_type TEXT NOT NULL,
source_ref TEXT NOT NULL,
condition_text TEXT NOT NULL,
schedule_type TEXT NOT NULL,
interval_seconds INTEGER,
timezone TEXT,
next_run_at TIMESTAMP NOT NULL,
last_run_at TIMESTAMP,
cursor_value TEXT,
last_hash TEXT,
status TEXT NOT NULL,
failure_count INTEGER NOT NULL DEFAULT 0,
last_error TEXT,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL
);
CREATE TABLE poll_runs (
id TEXT PRIMARY KEY,
poll_id TEXT NOT NULL,
started_at TIMESTAMP NOT NULL,
finished_at TIMESTAMP,
status TEXT NOT NULL,
items_checked INTEGER,
items_matched INTEGER,
decision_summary TEXT,
error TEXT
);
CREATE TABLE notifications (
id TEXT PRIMARY KEY,
poll_id TEXT NOT NULL,
user_id TEXT NOT NULL,
dedupe_key TEXT NOT NULL,
title TEXT NOT NULL,
body TEXT NOT NULL,
delivered_at TIMESTAMP,
UNIQUE (dedupe_key)
);
Это дает вам чистое разделение:
планировщик владеет временем
очередь владеет буферизацией
воркер владеет выполнением
база данных владеет состоянием
LLM владеет семантическим суждением
ассистент владеет взаимодействием с пользователем
Это разделение — сердце надежного агента опроса.
Пример: Агент Hermes обрабатывает задачи Notion
Теперь давайте применим архитектуру к конкретному случаю.
Предположим, база данных Notion содержит задачи. Hermes должен запускаться каждые 10 минут, брать одну задачу в состоянии Todo, устанавливать её в InProgress, выполнять, а затем помечать как Complete.
Это лучше всего описать как:
внешний инструмент как очередь задач
+
воркер опроса по расписанию
+
выполнение на основе захвата или аренды
Для продакшен-версии это становится:
опрос на основе очередей с Notion как ориентированным на человека почтовым ящиком задач
Свойства задач Notion
База данных Notion должна содержать поля, такие как:
Name
Status: Todo | InProgress | Complete | Failed
Priority
CreatedAt
ClaimedBy
ClaimedAt
ClaimExpiresAt
RunId
RetryCount
LastError
CompletedAt
Важные поля — ClaimedAt, ClaimExpiresAt и RunId. Они делают захват задачи видимым и восстанавливаемым.
Состояние выполнения Hermes
Hermes также должен хранить собственную запись выполнения:
run_id
notion_page_id
started_at
finished_at
status
input_snapshot
tool_calls
result_summary
error
idempotency_key
Это защищает вас, если Notion редактируется вручную, если вызов API завершается ошибкой, или если вам нужно аудировать, что именно сделал Hermes.
Поток выполнения
Каждые 10 минут:
планировщик Hermes создает run
Воркер Hermes:
находит одну задачу Notion где Status = Todo
сортирует по Priority и CreatedAt
захватывает задачу, устанавливая Status = InProgress
записывает ClaimedBy, ClaimedAt, ClaimExpiresAt и RunId
выполняет задачу
записывает журналы выполнения в бэкенд Hermes
устанавливает Status Notion = Complete при успехе
устанавливает Status Notion = Failed при ошибке
Если Hermes упадет после захвата задачи, аренда может истечь:
Status = InProgress
ClaimExpiresAt < now
Будущий запуск может затем восстановить задачу или пометить её как не выполненную.
Обработка ошибок
При успехе:
Status = Complete
CompletedAt = now
LastError = пусто
При восстанавливаемой ошибке:
Status = Todo
RetryCount = RetryCount + 1
LastError = короткое сообщение об ошибке
При невосстанавливаемой ошибке:
Status = Failed
LastError = четкое объяснение
Для безопасности Hermes также должен использовать ключ идемпотентности:
notion_page_id + task_version + action_type
Это предотвращает выполнение одной и той же задачи дважды, если повторная попытка происходит в неправильное время.
Почему это не просто опрос
Часть опроса — это только механизм пробуждения. Реальная архитектура — это захват задач и надежное выполнение.
Наивная реализация говорит:
Каждые 10 минут, найти задачу Todo и сделать её.
Надежная реализация говорит:
Каждые 10 минут, захватить точно одну подходящую задачу, записать run, выполнить идемпотентно и переместить задачу в терминальное состояние.
В этом разница между демо и агентом, которому можно доверять.
Общие ошибки агентов опроса
Ошибка 1: Нет протокола захвата
Если два воркера могут видеть одну и ту же задачу, они могут выполнить её оба.
Используйте:
ClaimedBy
ClaimedAt
ClaimExpiresAt
RunId
Даже если вы сейчас запускаете одного воркера, проектируйте так, как будто второй воркер может появиться позже.
Ошибка 2: Нет ключа дедупликации
Каждое внешнее действие должно иметь ключ дедупликации.
user_id + poll_id + source_object_id + action_type + condition_version
Это предотвращает повторные уведомления, повторные письма, повторное выполнение задач и повторные вызовы инструментов. Более широкие принципы скроппинга, хранения и тестирования этих ключей применимы здесь так же — см. Идемпотентность в распределенных системах, которая действительно работает.
Ошибка 3: Слишком ранний вызов LLM
Не просите модель выполнять фильтрацию базы данных.
Плохо:
Отправить все задачи в LLM и спросить, какая из них Todo.
Лучше:
Используйте фильтр API Notion для получения задач Todo.
Затем используйте LLM только если интерпретация задачи необходима.
Ошибка 4: Отношение к Notion как к единственному бэкенду
Notion — хороший интерфейс для человека. Это не полный бэкенд выполнения.
Храните журналы выполнения, повторные попытки, трассировки и записи идемпотентности в Hermes.
Ошибка 5: Бесконечный опрос
Каждый опрос должен иметь условие остановки.
Примеры:
остановиться после успеха
остановиться после даты
остановиться после макс. повторных попыток
остановиться, когда пользователь отключит
остановиться после повторяющейся ошибки авторизации
Агент опроса без условия остановки — это тихая утечка затрат.
Ошибка 6: Нет наблюдаемости
Вы должны быть able to ответить:
Что запускал агент?
Почему он запустился?
Что он прочитал?
Что он изменил?
Почему он провалился?
Уведомил ли он пользователя?
Запускался ли он дважды?
Если вы не можете ответить на эти вопросы, система не готова к важной работе.
Чек-лист наблюдаемости
Отслеживайте метрики, такие как:
polls_due
polls_started
polls_succeeded
polls_failed
tasks_claimed
tasks_completed
tasks_failed
claim_expired_count
duplicate_suppressed_count
llm_calls
llm_cost
rate_limit_count
average_run_duration
Логируйте поля, такие как:
poll_id
run_id
source_type
source_object_id
claim_id
cursor_before
cursor_after
decision
dedupe_key
error
Постройте админ-предпросмотр для:
активных опросов
зависших задач InProgress
недавних ошибок
задач с высокими повторными попытками
задач мертвых писем
дорогих оценок LLM
отключенных интеграций
Агенты опроса работают в фоне, где ошибки тихи, и проблемы могут накапливаться, прежде чем кто-либо заметит. Фоновым системам нужна видимость, встроенная с самого начала, а не добавленная постфактум, когда что-то пойдет не так. Для полного стека наблюдаемости для систем ИИ и LLM — метрик, трассировок, структурированных логов и SLO — см. Наблюдаемость для систем LLM: метрики, трассировки, логи и тестирование в продакшене.
Итоговая рекомендация
Для серьезного ИИ-ассистента начните с воркеров опроса на основе очередей и надежного хранилища состояния. Добавьте вебхуки там, где провайдеры их поддерживают. Используйте адаптивный опрос, когда важны лимиты скорости. Используйте надежный движок рабочих процессов, когда процесс долгий и многошаговый. Используйте постоянный runtime агента, когда агенту нужно рассуждать со временем.
Для примера Hermes и Notion правильная архитектура:
Notion как ориентированный на человека почтовый ящик задач
Планировщик Hermes каждые 10 минут
Воркер Hermes с логикой захвата или аренды
Бэкенд Hermes для журналов выполнения и идемпотентности
Обновления статуса Notion для видимости
Интервал опроса — не самая сложная часть. Сложная часть — убедиться, что агент захватывает одну задачу, выполняет её один раз, записывает, что произошло, и оставляет систему в состоянии, которое понимают люди.
В этом и заключается превращение скрипта опроса в надежного ИИ-ассистента — не интервал, не модель, а дисциплина вокруг захвата работы, её записи и оставления системы в состоянии, понятном как людям, так и будущим запускам.