Amiga
Оглавление курса · урок 17 из 24

Модуль 4 · Масштаб · урок 17 из 24

Оркестрация параллельных агентов

Когда один агент работает хорошо, следующий вопрос — как запустить десять. Узким местом очень быстро становится не модель и не железо, а человек, который переключается между сессиями. В этом уроке — уровни оркестрации от простого к сложному, разбор спецификации Symphony и набросок своей схемы для связки Kaiten и GitLab.

Узкое место — переключение контекста

Команда OpenAI, которая вела эксперимент с полностью агентным кодом, описала следующий шаг в статье о Symphony. После того как код стали писать агенты, узким местом оказалось переключение контекста: большинству людей комфортно вести три-пять сессий одновременно, дальше продуктивность падает. Авторы сравнивают это с командой очень способных джунов, которых инженеры вынуждены микроменеджить.

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

Уровень 1: субагенты внутри сессии

Главный агент поручает ограниченные подзадачи субагентам, у каждого свой контекст, и получает обратно выжимку. В Codex встроены агенты default, worker и explorer, свои описываются TOML-файлами в .codex/agents/ с обязательными полями name, description, developer_instructions. Субагенты наследуют песочницу и режим одобрений родителя — файл агента не может их переопределить. Число одновременных потоков ограничивает agents.max_concurrent_threads_per_session. Подробности — в уроке о субагентах.

Когда подходит: исследование кода, параллельные независимые проверки, ревью с разных сторон. Цена: субагенты расходуют больше токенов, чем один агент. Ограничение: всё живёт внутри одной сессии и одной рабочей копии, так что параллельные правки одних файлов по-прежнему опасны.

Уровень 2: несколько сессий в worktree

Человек сам запускает несколько задач, каждую в своём worktree со своим стендом (см. урок об окружениях), и переключается между ними. Это рабочий режим большинства команд сегодня. Предел — те самые три-пять сессий на человека.

Что помогает растянуть предел: агент доводит задачу до проверяемого результата без вопросов (хорошая постановка, критерии готовности, петли обратной связи), уведомление по завершении хода (ключ notify в конфиге), и пакет доказательств в конце — скриншоты, отчёт тестов, — чтобы приёмка занимала минуты.

Уровень 3: трекер как пульт управления

Symphony переворачивает схему: не человек запускает агентов, а трекер задач (в эталонной реализации — Linear) служит пультом управления (control plane). Каждой открытой задаче соответствует отдельный workspace с агентом, статусы тикетов работают как машина состояний, упавшие и застрявшие агенты перезапускаются. Работа отвязана от сессий и PR.

Из статьи и спецификации:

  • крупную задачу агент сначала раскладывает в план и дерево задач с блокерами (пример авторов: обновление React заблокировано миграцией на Vite) и сам заводит follow-up задачи;
  • конфигурация лежит в WORKFLOW.md: YAML-шапка и строгий шаблон промпта, где неизвестная переменная — ошибка;
  • значения по умолчанию в спецификации: опрос трекера раз в 30 секунд, до 10 агентов одновременно, таймаут хода — час, агент считается застрявшим после 5 минут без событий, повтор с экспоненциальной задержкой до 5 минут;
  • успешный прогон может заканчиваться не в «Done», а в состоянии передачи человеку, например «Human Review»;
  • агенты запускаются через App Server, а доступ к Linear выдан инструментом linear_graphql — токен трекера в контейнер не попадает.

Результаты авторы приводят с атрибуцией к своим командам: у некоторых из них число смёрженных PR выросло на 500% за первые три недели. Это цифра одной компании на её внутренних проектах, не ориентир.

Два вывода авторов стоит запомнить больше, чем цифры. Первый: агенты как жёсткие узлы машины состояний работают плохо, им лучше давать цели, инструменты и контекст. Второй: за автономию платят возможностью поправлять агента на лету, поэтому неоднозначные задачи, требующие суждения, остаются интерактивными. Провалы авторы рассматривают как пробелы обвязки и отвечают новыми навыками и проверками — e2e-тестами, Chrome DevTools, smoke-тестами.

Symphony — эталонная реализация и спецификация, а не поддерживаемый продукт. Авторы описывают её прежде всего как SPEC.md: реализацию на Elixir Codex написал с одной попытки, а чтобы найти неоднозначности в тексте, спецификацию реализовали ещё на пяти языках.

Уровень 4: свой оркестратор

Для агентства с Kaiten и GitLab готового Symphony нет: адаптера к Kaiten в эталонной реализации нет. Но спецификация описывает, что нужно повторить, а минимальный оркестратор помещается в сотню строк. Ниже набросок: задачи берутся из JSON-выгрузки (замените на запрос к API Kaiten), каждая получает worktree и ветку по правилу проекта, агент запускается через codex exec, не больше трёх одновременно.

python · scripts/agent/orchestrate.py
import json
import subprocess
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path

MAX_AGENTS = 3
ROOT = Path.cwd()
WORKSPACES = ROOT.parent / "agent-workspaces"
PROMPT = (ROOT / "docs/agent/TASK_PROMPT.md").read_text()


def run_task(task: dict) -> dict:
    branch = f"task-{task['id']}"
    ws = WORKSPACES / branch
    if not ws.exists():
        subprocess.run(["git", "worktree", "add", "-b", branch, str(ws), "origin/main"], check=True)
    prompt = PROMPT.format(title=task["title"], description=task["description"])
    result = subprocess.run(
        ["codex", "exec", "-C", str(ws), "--sandbox", "workspace-write",
         "-o", str(ws / "agent-report.md"), "-"],
        input=prompt, text=True, capture_output=True, timeout=3600,
    )
    return {"id": task["id"], "ok": result.returncode == 0, "report": str(ws / "agent-report.md")}


def main() -> None:
    tasks = [t for t in json.loads(Path("tasks.json").read_text()) if t.get("agent_ready")]
    WORKSPACES.mkdir(exist_ok=True)
    with ThreadPoolExecutor(max_workers=MAX_AGENTS) as pool:
        for outcome in pool.map(run_task, tasks):
            print(json.dumps(outcome, ensure_ascii=False))


if __name__ == "__main__":
    main()

Чего здесь сознательно нет и что придётся добавить, если схема приживётся: перевод карточки в колонку «Ревью» и комментарий со ссылкой на MR, обнаружение застрявших агентов и повторы, уборка worktree и стендов, журнал событий. Когда понадобятся потоковые события, одобрения со стороны сервера и продолжение тредов, codex exec станет тесен — это задача для App Server, о нём урок об App Server.

PROMPT.format использует фигурные скобки, поэтому в шаблоне промпта их нужно удваивать или перейти на шаблонизатор со строгими переменными — как Liquid в Symphony.

Как разрезать работу

Параллельность ломается на конфликтах. Несколько правил, которые снижают их число:

  • Делите по владению файлами, а не по фичам. Две задачи, правящие один и тот же layouts/default.htm, параллельно не запускайте — или заведите блокер, как в DAG у Symphony.
  • Мелкие задачи. Чем короче живёт ветка, тем меньше она расходится с main.
  • Общие изменения — первыми. Миграция базы, новый общий компонент, обновление зависимостей идут отдельной задачей до тех, что на них опираются.
  • Одна задача — один MR. Агент не должен «заодно» чинить соседнее: это рождает конфликты и усложняет ревью.

Напряжения

Цели или жёсткий процесс. Symphony советует давать агентам цели, а не переходы. Тяжёлые процессы spec-driven инструментов идут в обратную сторону. Наш вывод: жёстким должен быть контур — workspace, проверки, точка передачи человеку, — а путь внутри него агент выбирает сам.

Пропускная способность или контроль. Оркестратор легко производит больше MR, чем команда успевает принять. Это не победа, а перенос узкого места на ревью и приёмку. Что с этим делать — следующий урок, о мерже и ревью при большом потоке.

Цена. Десять агентов параллельно — это десять стендов, десять потоков токенов и десять результатов на приёмку. Начинайте с двух-трёх и увеличивайте, только когда доля задач, принятых без доработок, стабильно высока.

Попробуйте сами

10–15 мин на рабочем месте
  1. Посчитайте, сколько сессий агента вы реально ведёте одновременно и где теряете время: ожидание, переключение, разбор результата.
  2. Опишите в docs/agent/TASK_PROMPT.md промпт для задачи из трекера: ритуал старта, критерии готовности, что положить в отчёт. Запустите оркестратор на двух реальных небольших задачах.
  3. Пройдитесь по бэклогу и отметьте задачи, которые можно отдать без интерактива, и те, что требуют суждения. Сформулируйте признак, по которому их различать, и запишите его рядом с промптом.

Коротко

  • Узкое место параллельной работы — переключение контекста человека, обычно три-пять сессий.
  • Субагенты делят контекст внутри сессии, worktree — файлы, трекер как пульт снимает с человека роль диспетчера.
  • Symphony — спецификация с полезными решениями: workspace на задачу, перезапуск застрявших, передача человеку, токены вне контейнера.
  • Свой оркестратор начинается с сотни строк на codex exec; когда нужны события и одобрения — App Server.
  • Режьте работу по владению файлами, жёстким делайте контур, а не путь агента.
Отметка хранится только в вашем браузере
Хотите связаться с владельцем
компании напрямую?
Дмитрий Тарасов
Дмитрий Тарасов
СЕО

НАПИСАТЬ

Написать в MAX