Перейти к содержанию

Delegation

На этой странице

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

Одиночная задача​

[code] delegate_task( goal="Отладить причину падения тестов", context="Ошибка: assertion в test_foo.py строка 42", toolsets=["terminal", "file"] )

[/code]

Пакетный параллельный запуск​

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

[code] delegate_task(tasks=[ {"goal": "Исследовать тему A", "toolsets": ["web"]}, {"goal": "Исследовать тему B", "toolsets": ["web"]}, {"goal": "Исправить сборку", "toolsets": ["terminal", "file"]} ])

[/code]

Как работает контекст дочернего агента​

Важно: дочерние агенты ничего не знают

Дочерние агенты начинают с полностью нового разговора. У них нет никаких знаний об истории общения родительского агента, предыдущих вызовах инструментов или чём-либо, что обсуждалось до делегирования. Единственный контекст дочернего агента — это поля goal и context, которые родительский агент заполняет при вызове delegate_task.

Это означает, что родительский агент должен передать всё, что нужно дочернему агенту, в вызове:

[code] # ПЛОХО — дочерний агент понятия не имеет, что такое «ошибка» delegate_task(goal="Исправить ошибку")

# ХОРОШО — дочерний агент имеет весь необходимый контекст
delegate_task(
    goal="Исправить TypeError в api/handlers.py",
    context="""Файл api/handlers.py содержит TypeError на строке 47:
    Объект 'NoneType' не имеет атрибута 'get'.
    Функция process_request() получает словарь от parse_body(),
    но parse_body() возвращает None, если заголовок Content-Type отсутствует.
    Проект находится в /home/user/myproject и использует Python 3.11."""
)

[/code]

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

Практические примеры​

Параллельное исследование​

Исследуйте несколько тем одновременно и соберите сводки:

[code] delegate_task(tasks=[ { "goal": "Исследовать текущее состояние WebAssembly в 2025 году", "context": "Сосредоточиться на: поддержке браузеров, средах выполнения вне браузера, поддержке языков", "toolsets": ["web"] }, { "goal": "Исследовать текущий уровень внедрения RISC-V в 2025 году", "context": "Сосредоточиться на: серверных чипах, встраиваемых системах, экосистеме ПО", "toolsets": ["web"] }, { "goal": "Исследовать прогресс квантовых вычислений в 2025 году", "context": "Сосредоточиться на: прорывах в коррекции ошибок, практических применениях, ключевых игроках", "toolsets": ["web"] } ])

[/code]

Ревью кода + исправление​

Делегируйте рабочий процесс ревью и исправления в новый контекст:

[code] delegate_task( goal="Проверить модуль аутентификации на уязвимости и исправить найденные", context="""Проект в /home/user/webapp. Файлы модуля аутентификации: src/auth/login.py, src/auth/jwt.py, src/auth/middleware.py. Проект использует Flask, PyJWT и bcrypt. Сосредоточиться на: SQL-инъекциях, валидации JWT, обработке паролей, управлении сессиями. Исправить все найденные проблемы и запустить тесты (pytest tests/auth/).""", toolsets=["terminal", "file"] )

[/code]

Многофайловый рефакторинг​

Делегируйте крупную задачу рефакторинга, которая перегрузила бы контекст родителя:

[code] delegate_task( goal="Выполнить рефакторинг всех Python-файлов в src/ — заменить print() на правильное логирование", context="""Проект в /home/user/myproject. Использовать модуль 'logging' с logger = logging.getLogger(name). Заменить вызовы print() на соответствующие уровни логирования: - print(f"Ошибка: ...") -> logger.error(...) - print(f"Предупреждение: ...") -> logger.warning(...) - print(f"Отладка: ...") -> logger.debug(...) - Остальные print -> logger.info(...) Не изменять print() в тестовых файлах или CLI-выводе. Запустить pytest после для проверки.""", toolsets=["terminal", "file"] )

[/code]

Детали пакетного режима​

Когда вы передаёте массив tasks, дочерние агенты выполняются параллельно с использованием пула потоков:

  • Максимальная конкурентность: по умолчанию 3 задачи (настраивается через delegation.max_concurrent_children или переменную окружения DELEGATION_MAX_CONCURRENT_CHILDREN; минимум 1, без жёсткого ограничения). Пакеты, превышающие лимит, возвращают ошибку инструмента, а не молча усекаются.
  • Пул потоков: использует ThreadPoolExecutor с заданным лимитом конкурентности в качестве максимального количества рабочих потоков
  • Отображение прогресса: в CLI-режиме древовидное представление показывает вызовы инструментов каждого дочернего агента в реальном времени со строками завершения каждой задачи. В шлюзовом режиме прогресс собирается в пакеты и передаётся в колбэк прогресса родительского агента
  • Упорядочивание результатов: результаты сортируются по индексу задачи, чтобы соответствовать порядку ввода независимо от порядка завершения
  • Распространение прерывания: прерывание родительского агента (например, отправка нового сообщения) прерывает всех активных дочерних агентов

Одиночная задача выполняется напрямую без накладных расходов пула потоков.

Переопределение модели​

Вы можете настроить другую модель для дочерних агентов через config.yaml — полезно для делегирования простых задач более дешёвым/быстрым моделям:

[code] # В ~/.hermes/config.yaml delegation: model: "google/gemini-flash-2.0" # Более дешёвая модель для дочерних агентов provider: "openrouter" # Опционально: направить дочерних агентов к другому провайдеру

[/code]

Если не указано, дочерние агенты используют ту же модель, что и родительский.

Советы по выбору набора инструментов​

Параметр toolsets управляет тем, к каким инструментам имеет доступ дочерний агент. Выбирайте в зависимости от задачи:

Набор инструментов Сценарий использования
["terminal", "file"] Работа с кодом, отладка, редактирование файлов, сборки
["web"] Исследования, проверка фактов, поиск документации
["terminal", "file", "web"] Полнофункциональные задачи (по умолчанию)
["file"] Анализ только для чтения, ревью кода без выполнения
["terminal"] Системное администрирование, управление процессами

Некоторые наборы инструментов заблокированы для дочерних агентов независимо от того, что вы укажете:

  • delegation — заблокирован для листовых дочерних агентов (по умолчанию). Сохраняется для дочерних агентов с role="orchestrator", ограничен max_spawn_depth — см. Глубина и вложенная оркестрация ниже.
  • clarify — дочерние агенты не могут взаимодействовать с пользователем
  • memory — запрещена запись в общую постоянную память
  • code_execution — дочерние агенты должны рассуждать пошагово
  • send_message — нет кроссплатформенных побочных эффектов (например, отправка сообщений Telegram)

Максимальное количество итераций​

У каждого дочернего агента есть лимит итераций (по умолчанию: 50), который ограничивает количество шагов с вызовом инструментов:

[code] delegate_task( goal="Быстрая проверка файла", context="Проверить, существует ли /etc/nginx/nginx.conf, и вывести первые 10 строк", max_iterations=10 # Простая задача, много шагов не нужно )

[/code]

Тайм-аут дочернего агента​

Дочерние агенты считаются зависшими и завершаются, если они молчат дольше, чем delegation.child_timeout_seconds секунд реального времени. По умолчанию — 600 (10 минут) — увеличено с 300 с в предыдущих версиях, потому что модели с глубокими рассуждениями при нетривиальных исследовательских задачах завершались посередине размышления. Настраивается для каждой установки:

[code] delegation: child_timeout_seconds: 600 # по умолчанию

[/code]

Снижайте для быстрых локальных моделей; увеличивайте для медленных моделей рассуждения на сложных задачах. Таймер сбрасывается каждый раз, когда дочерний агент совершает API-вызов или вызов инструмента — только действительно простаивающие работники вызывают завершение.

Диагностический дамп при тайм-ауте без вызовов

Если у дочернего агента истёк тайм-аут при нулевом количестве API-вызовов (обычно: провайдер недоступен, ошибка аутентификации или отклонение схемы инструмента), delegate_task записывает структурированную диагностику в ~/.hermes/logs/subagent-timeout-<session>-<timestamp>.log, содержащую снимок конфигурации дочернего агента, трассировку разрешения учётных данных и любые сообщения о ранних ошибках. Это значительно упрощает поиск корневой причины по сравнению с прежним молчаливым тайм-аутом.

Мониторинг запущенных дочерних агентов (/agents)​

TUI предоставляет наложение /agents (псевдоним /tasks), которое превращает рекурсивное разветвление delegate_task в первоклассную поверхность аудита:

  • Древовидное представление запущенных и недавно завершённых дочерних агентов в реальном времени, сгруппированных по родителю
  • Сводки затрат, токенов и затронутых файлов по каждой ветке
  • Элементы управления завершением и приостановкой — отмените конкретного дочернего агента на лету, не прерывая его собратьев
  • Пост-анализ: просмотр пошаговой истории каждого дочернего агента даже после возврата к родителю

Классический CLI просто выводит /agents в виде текстовой сводки; в TUI наложение раскрывается наиболее полно. См. TUI — Слэш-команды.

Глубина и вложенная оркестрация​

По умолчанию делегирование является плоским: родитель (глубина 0) порождает дочерних агентов (глубина 1), и эти дочерние агенты не могут делегировать дальше. Это предотвращает неконтролируемую рекурсивную делегацию.

Для многоэтапных рабочих процессов (исследование → синтез или параллельная оркестрация подзадач) родитель может порождать оркестраторов — дочерних агентов, которые могут делегировать свои собственные задачи:

[code] delegate_task( goal="Изучить три подхода к ревью кода и рекомендовать один", role="orchestrator", # Позволяет этому дочернему агенту порождать свои задачи context="...", )

[/code]

  • role="leaf" (по умолчанию): дочерний агент не может делегировать дальше — идентично поведению плоского делегирования.
  • role="orchestrator": дочерний агент сохраняет набор инструментов delegation. Ограничивается delegation.max_spawn_depth (по умолчанию 1 = плоское, поэтому role="orchestrator" ничего не меняет при настройках по умолчанию). Увеличьте max_spawn_depth до 2, чтобы позволить дочерним оркестраторам порождать листовых внуков; до 3 для трёх уровней (максимум).
  • delegation.orchestrator_enabled: false: глобальный выключатель, который принудительно устанавливает всем дочерним агентам роль leaf независимо от параметра role.

Предупреждение о затратах: При max_spawn_depth: 3 и max_concurrent_children: 3 дерево может достичь 3×3×3 = 27 параллельных листовых агентов. Каждый дополнительный уровень умножает расходы — увеличивайте max_spawn_depth осознанно.

Время жизни и долговечность​

delegate_task синхронен — не долговечен

delegate_task выполняется внутри текущего шага родительского агента. Он блокирует родительского агента до тех пор, пока каждый дочерний агент не завершится (или не будет отменён). Это не фоновая очередь заданий:

  • Если родительский агент прерван (пользователь отправил новое сообщение, /stop, /new), все активные дочерние агенты отменяются и возвращают status="interrupted". Их текущая работа отбрасывается.
  • Дочерние агенты не продолжают работать после завершения шага родительского агента.
  • Отменённые дочерние агенты возвращают структурированный результат (status="interrupted", exit_reason="interrupted"), но поскольку родительский агент также был прерван, этот результат часто не попадает в видимый пользователю ответ.

Для долговечной фоновой работы, которая должна переживать прерывания или выходить за пределы текущего шага, используйте:

  • cronjob (action=create) — планирует отдельный запуск агента; не подвержен прерываниям текущего шага.
  • terminal(background=True, notify_on_complete=True) — долго выполняющиеся команды оболочки, которые продолжают работу, пока агент занимается другими делами.

Ключевые свойства​

  • Каждый дочерний агент получает собственный сеанс терминала (отдельный от родительского)
  • Вложенное делегирование — по желанию — только дочерние агенты с role="orchestrator" могут делегировать дальше, и только если max_spawn_depth увеличен со значения по умолчанию 1 (плоское). Отключите глобально с помощью orchestrator_enabled: false.
  • Листовые дочерние агенты не могут вызывать: delegate_task, clarify, memory, send_message, execute_code. Оркестраторы сохраняют delegate_task, но всё ещё не могут использовать остальные четыре.
  • Распространение прерывания — прерывание родительского агента прерывает всех активных дочерних (включая внуков под оркестраторами)
  • Только итоговая сводка попадает в контекст родительского агента, что обеспечивает эффективное использование токенов
  • Дочерние агенты наследуют API-ключ, конфигурацию провайдера и пул учётных данных родительского агента (включая ротацию ключей при ограничениях скорости)

Сравнение: Delegation vs execute_code​

Фактор delegate_task execute_code
Рассуждение Полный цикл рассуждения LLM Только выполнение Python-кода
Контекст Новый изолированный разговор Нет разговора, только скрипт
Доступ к инструментам Все незаблокированные инструменты с рассуждением 7 инструментов через RPC, без рассуждения
Параллелизм 3 параллельных дочерних агента по умолчанию (настраивается) Один скрипт
Для чего лучше Сложные задачи, требующие суждения Механические многошаговые конвейеры
Стоимость токенов Выше (полный цикл LLM) Ниже (возвращается только stdout)
Взаимодействие с пользователем Нет (дочерние агенты не могут задавать уточняющие вопросы) Нет

Правило: Используйте delegate_task, когда подзадача требует рассуждения, суждения или многошагового решения проблем. Используйте execute_code, когда нужна механическая обработка данных или скриптовые рабочие процессы.

Конфигурация​

[code] # В ~/.hermes/config.yaml delegation: max_iterations: 50 # Макс. шагов на дочернего агента (по умолч.: 50) # max_concurrent_children: 3 # Параллельных дочерних агентов на пакет (по умолч.: 3) # max_spawn_depth: 1 # Глубина дерева (1–3, по умолч. 1 = плоское). Увеличьте до 2, чтобы разрешить оркестраторам порождать листовых агентов; до 3 для трёх уровней. # orchestrator_enabled: true # Отключите, чтобы принудительно установить всем дочерним агентам роль leaf. model: "google/gemini-3-flash-preview" # Опциональное переопределение модели/провайдера provider: "openrouter" # Опциональный встроенный провайдер

# Или используйте прямой кастомный эндпоинт вместо провайдера:
delegation:
  model: "qwen2.5-coder"
  base_url: "http://localhost:1234/v1"
  api_key: "local-key"

[/code]

tip Агент обрабатывает делегирование автоматически на основе сложности задачи. Вам не нужно явно просить его делегировать — он сделает это, когда это имеет смысл.