1. Параллельный workflow ломается на размытых границах
Параллельный workflow чаще всего ломается именно на размытых границах, и сама схема ролей ещё ничего не спасает. Пока у ролей нет scope, forbidden zones, stop condition и handoff, pattern остаётся диаграммой. Тут и parallel workflow трещит по швам.
Когда люди впервые пробуют несколько агентов, ошибка почти всегда одна и та же: они разделят не задачу, а надежду. В голове звучит что-то вроде «один пусть делает backend, второй frontend, третий проверяет». Это не инженерный дизайн, а пожелание Вселенной. Claude работает там, где границы заданы файлами, контрактами и артефактами, а не настроением.
Проще всего представить это как ремонт кухни. Сказали троим «ну вы тут покрасьте нормально» — один покрасит стены, второй заодно тронет потолок, третий принесёт мнение о палитре. В коде то же самое, только вместо потолка страдает OrderService.java, а вместо запаха краски остаётся merge conflict.
Проблема параллельной работы редко в том, что агент «недостаточно умный». Гораздо чаще дело в слишком широкой постановке.
| Размытая постановка | Что обычно происходит | Рабочая постановка |
|---|---|---|
| «Агент 1 делает backend» | Тронет API, utils, тесты, а иногда и конфиг «заодно» | «Меняет только src/api/orders/*, публичный контракт не трогает» |
| «Агент 2 делает frontend» | Полезет в общий ui-kit, потому что “так удобнее” | «Меняет только src/web/orders/*, не редактирует общие компоненты» |
| «Агент 3 проверяет» | Вернёт мнение, а не проверяемый результат | «Читает diff, запускает smoke-check, возвращает findings с evidence» |
В хорошей параллельной работе вы заранее отвечаете на три вопроса. Кто владеет какой областью изменений. По какому сигналу роль останавливается. Какой артефакт передаёт дальше. Оставили хоть один в режиме «по ходу разберёмся» — конфликт уже записан в календарь.
Именно поэтому parallel workflow начинается не с запуска второго агента, а с границ. Сначала карта. Потом двигатели.
2. По какой оси резать работу
Когда вы слышите «разделить ownership», легко скатиться в грубое «backend отдельно, frontend отдельно». Иногда хватает. Но чаще важнее спросить: по какой оси задача делится естественно. Иначе роли разные только на бумаге, а фактически толкаются локтями в одном месте. Вот карта осей.
| Ось разделения | Когда полезна | Пример |
|---|---|---|
| Файлы | Маленькая точечная задача | Один агент меняет только OrderRefundService.java |
| Каталоги | Изолированные куски проекта | src/api/orders/* отдельно от src/web/orders/* |
| Модули | Бизнес-области уже разделены архитектурой | orders, support, dashboard |
| Слои | Есть стабильный контракт между UI и API | backend-слой отдельно от frontend-слоя |
| Пользовательские сценарии | Задача режется по flow, а не по слоям | «фильтр заказов» отдельно от «экспорт CSV» |
| Артефакты | Нужны разные типы результата | один делает PLAN.md, другой — diff, третий — review notes |
| Риск-зоны | Важно изолировать опасные части | payments/, migrations/, auth/ как отдельные зоны внимания |
Ключевая идея здесь в том, что ось должна быть одна главная. Факторов в жизни всегда несколько, но базовая логика деления обязана читаться. Режете одновременно по слоям, по сценариям и по папкам, не назвав главного, — получите не делегирование, а квест на внимательность.
Например, если в Commerce OS нужно добавить фильтр по статусу возврата на страницу заказов, то главная ось здесь слой плюс каталог: backend-исполнителю src/api/orders/*, frontend-исполнителю src/web/orders/*. А переработать один legacy-класс рядом с платежами по слоям делить бессмысленно: один owner, одна сессия, максимум — отдельный reviewer.
Есть ещё одно полезное правило: один owner на один файл или модуль, если это вообще возможно. Как только двое правят один класс, DTO или общий util, вы перестаёте выигрывать время и начинаете инвестировать в конфликт. Инвестиция очень дорогая.
3. Delegation brief короче, чем кажется
Вот здесь pattern наконец превращается в исполнимый контракт. После verdict о параллельности и схемы ролей появляется третий слой — delegation brief: кто, где, до какого сигнала и что возвращает дальше.
У новичков тут часто два режима, и вас потянет в одну из крайностей. «Слишком мало»: “сделай backend”. «Слишком много»: полторы страницы, где полезное утонуло в проекте. Хороший бриф посередине — короткая инженерная записка, которую роль либо принимает, либо сразу возвращает на уточнение.
У брифа есть пять обязательных частей. Не бюрократия, а минимум, без которого роль начинает «полезно» выходить за границы.
| Поле | Зачем нужно | Пример |
|---|---|---|
| Scope | Где именно можно работать | |
| Preserve | Что нельзя сломать | публичный API, контракт ответа |
| Don’t touch | Запретные зоны | migrations/, UI, shared utils |
| Stop when | Условие остановки | тесты зелёные, diff не вырос |
| Return | Что передать дальше | список файлов, вывод тестов, риски |
Вот пример плохого брифа. Он короткий, но бесполезный:
# Плохо
Агент 1 делает backend.
Агент 2 делает frontend.
Агент 3 проверяет.
Такой бриф не говорит вообще ничего. Где backend? Что нельзя трогать? Когда работа закончена? Что вернёт reviewer? Ответ один: «да как-нибудь». А «как-нибудь» в multi-agent работе переводится как «дорого и неприятно».
Теперь нормальный вариант для backend owner:
# Backend owner
Scope: src/api/orders/*
Preserve: публичный API из api/orders/openapi.yaml
Add: 1 integration test в tests/api/orders/
Don't touch: UI, shared utils, migrations/
Stop when: тесты проходят, diff <= 200 LOC
Return: changed files + test output + risk note
Здесь нет магии, зато есть всё, что нужно. Исполнитель знает, куда можно, а куда нельзя. Reviewer знает, по чему проверять. Вы знаете, что читать в handoff.
Особенно полезно беречь строку Don't touch. Выглядит сурово — экономит массу времени. У Claude, как у людей, есть склонность «ну раз уж я здесь, давайте ещё немножко улучшу». Так в PR на 120 строк внезапно приезжают правки DateUtils и переименование половины полей формы. Не запретили лишнее явно — разрешили его молча.
4. Исследование, реализация и проверка — разные роли
Когда задача только что исследована, возникает соблазн сразу дать тому же агенту писать код: «он же уже прочитал файлы, пусть и меняет». Но тут есть подвох. Read-only исследование и write-работа — разные режимы мышления. В первом вы собираете evidence, во втором принимаете решения, меняющие проект. Смешаете без контроля — проскочите путь от «нашёл причину» к «заодно всё поправил».
Для этого в Workflow Kit и существует идея формального контракта передачи. Не «я устно рассказал», а короткий handoff, который проверяется глазами. Кусок из AGENT_HANDOFF_CONTRACT.md:
## Передача
Input: PLAN.md + affected files list
Allowed scope: src/web/orders/*
Forbidden: src/api/**, migrations/**
Stop condition: фильтр работает локально
Output: diff + screenshot + changed files
Evidence: smoke result + file refs
Такой формат кажется сухим только до первого конфликта. После него он выглядит как очень добрая и заботливая вещь.
Отдельно полезно по умолчанию разделять роли и по характеру доступа. Исследователь читает и собирает evidence. Исполнитель меняет код в узкой зоне. Reviewer работает на свежем контексте и ничего не редактирует. Tester запускает тесты и при необходимости меняет тестовые файлы, но не production-код. Как только reviewer начинает «немного подправлять» код, он превращается во второго исполнителя — а это другой тип риска.
Хорошая новость в том, что это правило не делает процесс медленнее — наоборот: с явным разделением вам потом не надо гадать, откуда в diff изменения и кто тронул лишний файл.
5. Условие остановки важнее энтузиазма
Одна из самых недооценённых частей брифа — stop condition. Нет её — агент остановится по внутреннему чувству прекрасного. А оно у AI, мягко говоря, щедрое: он не знает, что вам нужен маленький PR на сегодня, а не «ещё чуть-чуть улучшить архитектуру».
Поэтому условие остановки должно быть либо проверяемым машиной, либо очень конкретным для человека. Не «когда всё готово», а «когда локально проходит такой-то тест и изменения не вышли за approved scope». Не «когда UI выглядит нормально», а «когда фильтр виден на странице, отправляет параметр в запрос и smoke-check проходит».
| Формулировка | Что с ней не так | Рабочий вариант |
|---|---|---|
| «Остановись, когда будет готово» | никто не знает, что такое «готово» | «остановись после зелёного smoke-check и diff summary» |
| «Верни результат» | результат может быть чем угодно | «верни список файлов, вывод тестов и risk note» |
| «Проверь изменения» | review без evidence превращается в мнение | «верни findings с file refs и severity» |
Пример в YAML-стиле:
stop_when:
- "gradle test --tests OrdersFilterIT green"
- "changed files only in src/api/orders/* and tests/api/orders/*"
return:
- "git diff summary"
- "test output"
- "risk note"
Здесь прекрасно то, что такой brief читается и человеком, и Claude — и его легко оспорить до старта: видите, что diff <= 200 LOC для задачи нереалистичен, меняете ожидание заранее, а не в конце на эмоциях.
И ещё одна важная вещь: evidence — не украшение. Исполнитель пишет «всё работает», а в handoff нет списка файлов, вывода тестов и хотя бы короткой заметки о рисках — проверять нечего. У вас есть только вера. А курс, напомню, строится не на вере, а на проверяемых артефактах.
6. Порядок интеграции придумывают до старта
Когда несколько ролей действительно работают параллельно, встаёт ещё один практический вопрос: в каком порядке их результаты соединятся. И вот тут многие совершают классическую ошибку — считают, что merge order придумается потом. «Потом» обычно значит «когда два агента уже поменяли один контракт и смотрят на вас как на виновника».
Порядок не обязан быть сложным, но обязан быть назван заранее — базовый нужен даже без полноценной merge-стратегии. Например, для фильтра заказов в Commerce OS он может быть таким:
| Порядок | Роль | Что отдаёт |
|---|---|---|
| 1 | Planner | PLAN.md + frozen API contract |
| 2 | Backend owner | diff + integration test output |
| 3 | Frontend owner | diff + screenshot/smoke result |
| 4 | Verifier | REVIEW.md с findings |
| 5 | Human | решение о merge |
Заметьте, здесь frontend идёт после backend не потому, что «так всегда надо», а потому, что UI зависит от контракта ответа. Пока контракт плавает, frontend-исполнитель стреляет по движущейся мишени. Иногда допустимо, но чаще — лишний риск.
Бывает и обратная ситуация: два исполнителя кажутся независимыми, а у них общий OrderFilterDto. Если оба меняют его одновременно, настоящей параллельности нет. Либо сначала заморозить контракт, либо честно сериализовать работу. Трагедии тут никакой. Хуже — делать вид, что работа параллельная, хотя вы просто отложили конфликт на полчаса.
Можно сформулировать простое правило: не можете в двух-трёх строках описать порядок передачи результатов — задача ещё не готова к параллельному исполнению. Роли придумали, а как они живут вместе — нет.
7. Agent pipeline для Commerce OS: один артефакт
Теперь давайте соберём всё на одном реальном сценарии. Задача в Commerce OS: добавить фильтр по статусу возврата на страницу заказов в админке. Крупная — в одной сессии не хочется, но не настолько хаотичная, чтобы звать целую agent team. Хороший кандидат на чёткий pipeline.
Сначала фиксируем схему ролей — не ради красоты, а чтобы каждый в цепочке понимал своё место.
[Planner / plan mode]
artifact: PLAN.md + API contract
↓
[Backend owner / subagent]
scope: src/api/orders/* + tests/api/orders/*
output: diff + test output
↓
[Frontend owner / fresh session]
scope: src/web/orders/*
output: diff + screenshot + smoke result
↓
[Verifier / reviewer agent]
read-only, checks diff bundle + tests
output: REVIEW.md
↓
[Human]
merge decision
Вот в этот момент обычно и становится видно, здорова задача или нет. Pipeline рисуется коротко — ownership достаточно ясен. Вместо схемы получается полстраницы уточнений и стрелок «возможно» — значит, вы либо рано полезли в параллельность, либо задачу ещё не дорезали.
Теперь пример handoff от backend owner к frontend owner:
Input: PLAN.md + updated API response example
Frontend assumes: контракт ответа заморожен
Forbidden: backend edits, shared utils
Stop when: фильтр виден и отправляет параметр
Return: screenshot + changed files + smoke result
Обратите внимание, сколько конфликтов снимает эта маленькая записка. Frontend получает не «ну backend уже вроде что-то сделал», а конкретный вход и конкретные границы. Знает, что API-контракт не поплывёт под ногами. Знает, чего не трогать. Знает, какой результат вернуть дальше verifier-у.
Всё это и есть практический смысл лекции. Не выучить термин delegation design, а перестать запускать параллельную работу в режиме «надеюсь, агенты сами договорятся». Договориться сами они не должны. Это ваша работа как разработчика.
Соберите четыре вещи вместе — названную границу, короткий проверяемый brief, конкретное условие остановки и заранее продуманный порядок передачи — и параллельная работа перестаёт быть генератором merge conflict'ов. Конфликт больше не назначается в календарь по умолчанию: он либо исключён разделением ownership, либо честно превращён в последовательный шаг. Вы не надеетесь, что агенты разойдутся по своим зонам, — вы эти зоны нарезали заранее. Именно это отличает делегирование от раздачи задач в пустоту.
С этого места важны уже не новые названия ролей, а обычная рабочая дисциплина: где вы держите status потоков — в agent view, task list или issue note, — как ставите checkpoints, в каком порядке сводите результаты и по каким метрикам понимаете, что pipeline не расползается.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ