Когда я начал регулярно работать с AI-агентом, выяснилась неприятная вещь: само выполнение задачи часто уже не было главным узким местом. Узкое место появлялось раньше. Нужно было каждый раз вручную понять, какие задачи вообще можно отдать агенту, какие должен сделать человек, какие уже выполнены, но требуют проверки, а какие нельзя двигать без внешнего решения или доступа.
То есть вместе с AI появился новый слой работы: диспетчеризация. До этого я воспринимал таск-трекер как список дел. После нескольких недель работы с агентами стало понятно, что список дел сам по себе не отвечает на главный операционный вопрос:
кто должен сделать следующий шаг?
Именно из этого вопроса выросла маленькая система очередей для работы человека и AI-агента. В этой статье разберу модель, API и архитектурные решения, которые в итоге оказались полезными.
Почему обычная доска задач плохо ложится на agent workflow
Обычная доска хорошо показывает, что задача существует. Например, есть колонки Backlog, In progress, Done. Этого хватает, пока все задачи делает человек или команда людей.
С AI-агентом появляется дополнительное состояние, которого в классической доске обычно нет. Агент может уже сделать работу, но человек еще не принял результат. Или задача может быть технически исполнимой, но агенту не хватает доступа. Или наоборот: задача выглядит сложной, но для агента она полностью готова, потому что контекст, репозиторий и критерий готовности уже известны.
В результате простая колонка In progress перестает быть достаточно точной. В ней могут лежать совершенно разные ситуации:
-
задача сейчас делается человеком;
-
задача сейчас делается агентом;
-
агент закончил, но результат должен проверить человек;
-
задача заблокирована секретом, логином или решением;
-
задача не имеет владельца следующего действия.
Проблема не в названии колонки. Проблема в том, что система не отделяет жизненный цикл задачи от владельца следующего действия.
Два измерения вместо одного
Я разделил задачу на два независимых измерения:
-
статус;
-
владелец следующего действия.
Статус отвечает на вопрос: где задача находится в жизненном цикле. В моей модели достаточно таких состояний:
backlogin_progresswaiting_reviewblockeddonecancelled
Владелец следующего действия отвечает на другой вопрос: кто должен двигать задачу дальше.
mecodexunassigned
Смысл не в конкретном имени codex. В реальной системе это может быть любой AI-агент или несколько разных агентов. Важно другое: задача может быть в backlog, но уже иметь владельца codex, если для нее достаточно контекста. Точно так же задача может быть blocked, но владельцем следующего действия будет человек, потому что нужно принять решение или дать доступ.
Самое важное состояние для agent workflow — waiting_review. Агент не должен переводить свою работу сразу в done, если результат еще не принят человеком. Например, он мог открыть pull request, подготовить черновик письма, изменить конфигурацию или собрать отчет. Во всех этих случаях работа технически выполнена, но финальная ответственность остается у человека. Поэтому результат попадает в очередь проверки.
Как выглядит минимальная модель задачи
Я намеренно оставил модель небольшой. В MVP мне хватило таких полей:
titledescriptionstatusassigneeoriginprioritydue_atreminder_atsource_namesource_urlsource_context
origin нужен, чтобы понимать источник: ручной ввод, почта, мессенджер, задача из внешнего трекера или действие агента. source_context хранит краткий контекст, из которого была извлечена задача. Это позволяет не открывать заново письмо или тред в Slack только для того, чтобы понять, почему задача появилась.
При этом я специально не стал тащить в модель десятки полей из Jira, Linear или Asana. Если пытаться совместить все возможные трекеры в одной схеме, получается тяжелая универсальная сущность, которую неудобно использовать локально. Для очереди делегирования важнее компактность и понятный следующий шаг.
Очередь для агента
Отдельный UI для человека полезен, но агенту он не нужен. Агенту нужен машиночитаемый список задач, которые можно выполнять.
Поэтому отдельный endpoint возвращает очередь:
GET /api/agent/queue
Пример запроса:
curl "$TASK_TRACKER_URL/api/agent/queue?assignee=codex&sort=smart&limit=25" \ -H "Authorization: Bearer $TASK_TRACKER_API_KEY"
В ответе есть summary, чтобы вызывающая сторона понимала общее состояние доски:
{ "summary": { "active": 42, "overdue": 3, "due_soon": 4, "codex_ready": 12, "human_input": 18, "review": 5, "blocked": 2, "unassigned": 1 }, "tasks": []}
Для агента это удобнее, чем читать всю доску. Он может запросить только задачи с владельцем codex, отсортировать их по приоритету и дедлайну, взять верхнюю задачу, перевести ее в in_progress, а после выполнения вернуть в waiting_review.
Захват задач из контекста
Следующая часть системы — нормализация задач из внешнего контекста. В моем случае источниками могут быть письма, сообщения, заметки встреч или другие трекеры. Но ядро системы не должно знать детали каждого источника. Иначе оно очень быстро превращается в комбайн со множеством OAuth-flow, токенов и исключений.
Я остановился на модели маленьких адаптеров:
-
webhook-адаптер получает событие из внешней системы и отправляет нормализованную задачу;
-
polling-адаптер периодически читает источник и создает задачи;
-
sync-адаптер читает очередь агента и при необходимости обновляет внешний трекер.
Контракт для загрузки задач из контекста выглядит так:
POST /api/agent/ingest/context
Пример payload:
{ "origin": "email", "source_name": "Gmail thread from Alice", "source_url": "https://mail.google.com/...", "source_context": "Alice asked for revised numbers by Friday.", "tasks": [ { "title": "Send Alice revised numbers", "assignee": "me", "priority": 2, "reminder_at": "2026-05-07T09:00:00Z" } ]}
В такой схеме ядро отвечает только за очередь, статусы, дедлайны и API. Адаптеры отвечают за конкретные источники и хранят свои секреты отдельно. Это оказалось проще и безопаснее, чем пытаться встроить все интеграции в основное приложение.
Дедлайны по умолчанию
Еще одна практическая проблема: многие задачи приходят без явного срока. Если оставить их без даты, они быстро перестают всплывать в нужный момент.
Я добавил простое правило: если due_at не передан, сервер оценивает дедлайн по приоритету.
P1 -> около 1 дняP2 -> около 3 днейP3 -> около 7 днейP4 -> около 14 днейP5 -> около 30 дней
Это не попытка угадать настоящий дедлайн. Это защита от задач, которые бесконечно лежат без даты. Реальный срок, если он есть в исходном письме или трекере, всегда должен иметь приоритет над такой оценкой.
Архитектура MVP
Технически MVP получился довольно прямолинейным:
-
FastAPI отдает web UI и JSON API;
-
SQLite используется для локальной разработки;
-
Firestore можно использовать как hosted-хранилище;
-
Google OAuth защищает браузерный UI;
-
Bearer token защищает API для агентов и адаптеров;
-
отдельный reminder job может периодически читать
/api/reminders/due.
Эта архитектура не самая модная, но у нее есть важное преимущество: она понятная. Локально можно запустить SQLite-версию, а production-вариант можно развернуть как Cloud Run + Firestore + Secret Manager.
Локальный запуск выглядит так:
python3 -m venv .venv. .venv/bin/activatepip install -r requirements.txtcp .env.example .envuvicorn app.main:app --reload
После этого UI доступен на http://127.0.0.1:8000.
Что я бы сделал иначе
Первое, что стало понятно после использования: определение “AI-ready” задачи лучше не зашивать только в один признак assignee=codex. В будущем полезно хранить объяснение, почему задача считается готовой для агента. Например: “есть ссылка на репозиторий”, “есть критерий готовности”, “не требуется внешний логин”, “не требуется отправка сообщения без подтверждения”.
Второй момент — ревью должно быть более структурированным. Сейчас waiting_review просто показывает, что человек должен проверить результат. Но для agent workflow полезно хранить артефакты: ссылку на PR, список измененных файлов, тесты, summary, риски и следующий шаг.
Третий момент — адаптеры лучше держать отдельно от ядра. Сначала хочется положить в основной репозиторий все интеграции сразу, но это быстро усложняет безопасность и поддержку. Гораздо чище иметь маленькое ядро и набор примеров адаптеров.
Вывод
Чем лучше AI-агенты выполняют задачи, тем заметнее становится проблема маршрутизации. Человек не должен каждый раз вручную разбирать список дел и решать, что можно поручить агенту.
Для меня полезной оказалась модель, где задача описывает не только состояние, но и владельца следующего действия. Тогда доска превращается не просто в список, а в очередь делегирования:
-
что делает человек;
-
что может взять агент;
-
что ждет проверки;
-
что заблокировано;
-
что еще не разобрано.
ссылка на оригинал статьи https://habr.com/ru/articles/1044554/