Графовая инженерия: как запустить 1000 AI-агентов параллельно с помощью одного промпта

@0xWast3
АНГЛИЙСКИЙ1 день назад · 22 июл. 2026 г.
146K
151
19
13
376

Суть

Технический разбор графовой инженерии для AI-агентов: как выявлять реальные зависимости и использовать параллельное выполнение для масштабирования рабочих процессов.

Все, кто строит мультиагентные системы в 2026 году, всё ещё пишут прямые линии. Шаг первый, затем шаг второй, затем шаг третий — каждый ждёт предыдущий. Вот почему это медленно и как это исправить.

wast3 - inline image

Проблема, которую никто не проверяет

Вы построили многошагового агента. Он работает. И он медленный.

Вы думаете, что узкое место — модель. Это не так.

Узкое место — это форма, которую вы нарисовали. Цепочка — шаг 1 ждёт шаг 2, шаг 2 ждёт шаг 3 — заставляет последовательное выполнение, даже когда половина этих шагов никак не связаны друг с другом.

«Суммируй этот документ, затем проверь погоду» — это две независимые задачи, наряженные в плащ одного рабочего процесса. Задача с погодой не нуждается в сводке. Никогда и не нуждалась. Но если вы записали это как цепочку, она всё равно ждёт.

Это бесполезное ожидание, умноженное на десятки шагов, — вот куда уходит большая часть времени выполнения.

Глава 1 — Циклы против графов

Цикл — это одна единица самосовершенствования:

text
1попробовать что-то → проверить результат → скорректировать → попробовать снова

Это атом. Один агент, одна метрика, цикл до сходимости.

У циклов есть известный режим отказа: они оптимизируют ровно то, что вы измеряете, и ничего больше. Чат-бот поддержки, настроенный на быстрое закрытие тикетов, будет быстро закрывать тикеты — пока удовлетворённость незаметно не рухнет. Цикл не видит ничего за пределами своей метрики. Это закон Гудхарта в вашей архитектуре агента.

Граф исправляет это по своей сути. Вместо одного цикла, гоняющегося за одним числом, вы строите сеть циклов, которые следят друг за другом и корректируют. Вывод узла A подаётся на вход узла B. Узел C работает независимо и проверяет оба. Ни одна метрика не управляет всей системой — это делает структура.

wast3 - inline image

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

Глава 2 — Узлы, рёбра и тест, который их разделяет

Граф состоит ровно из двух компонентов:

Узел — одна единица работы. Один агент, одно задание, один вход, один выход.

Ребро — реальная зависимость. Вход узла B требует выход узла A.

Ошибка, которую допускают почти все: считать «а затем» ребром по умолчанию.

text
1«Прочитай эту кодовую базу и затем напиши список изменений»
2«Загрузи страницу с ценами и затем суммируй фичи конкурентов»

Задайте один вопрос для каждого «а затем» в вашем рабочем процессе:

Действительно ли следующий шаг читает вывод предыдущего шага?

Если да → настоящее ребро. Сохраняйте последовательный порядок. Если нет → ребра нет. Ожидание впустую. Запускайте их параллельно.

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

Вот тест в коде:

python
1from dataclasses import dataclass
2
3@dataclass
4class TaskNode:
5 id: str
6 prompt: str
7 depends_on: list[str] # ID узлов, которые этому реально нужны
8
9def has_real_edge(node_a: TaskNode, node_b: TaskNode) -> bool:
10 """
11 Основной тест графовой инженерии:
12 действительно ли промпт node_b требует вывод node_a?
13 """
14 return node_a.id in node_b.depends_on
15
16# Пример: большинство «цепочек» сворачиваются в 2-3 группы реальных зависимостей
17nodes = [
18 TaskNode("audit_routes", "Список всех файлов маршрутов API", []),
19 TaskNode("check_auth", "Проверить покрытие auth middleware", []),
20 TaskNode("fetch_weather", "Получить сегодняшнюю погоду", []),
21 TaskNode("summarize", "Суммировать результаты маршрутов и аудита",
22 depends_on=["audit_routes", "check_auth"]),
23]
24
25# audit_routes, check_auth, fetch_weather НЕ имеют рёбер между собой
26# Они выполняются параллельно. Только "summarize" имеет реальные рёбра — он ждёт.

Ваш текущий агент «сделай A, затем B, затем C» технически уже является графом. Просто это наихудший из возможных — одна цепочка, где если C зависает, ничего ниже по потоку никогда не выполняется.

Глава 3 — Строим ваш первый граф

wast3 - inline image

Требования:

  • Claude Code (последняя версия с поддержкой Dynamic Workflows).
  • План Max, Team или Enterprise — рабочие процессы включены по умолчанию. На плане Pro включите вручную.

Откройте реальный репозиторий. Не игрушечный пример — результат проявится только в реальном масштабе.

Промпт, который запускает ваш первый граф:

text
1Создай рабочий процесс для аудита каждого файла маршрутов в этой кодовой базе.
2
3Для каждого файла маршрутов проверь независимо:
4- наличие middleware аутентификации
5- валидацию входных данных на всех параметрах
6- настройку ограничения скорости (rate limiting)
7- обработку ошибок, не раскрывающую стектрейсы
8
9Запусти эти проверки параллельно для всех файлов маршрутов —
10они не зависят друг от друга.
11
12После того как все файлы проверены, создай один сводный
13отчёт, сгруппированный по серьёзности: критический, предупреждение, информация.
14
15Этап сводки должен ждать завершения всех проверок.
16Всё до него — не должно.

Обратите внимание на структуру, встроенную в сам промпт: параллельная работа явно указана, одна реальная зависимость (сводка ждёт все проверки) явно названа. Вы не надеетесь, что агент сам выведет граф — вы его описываете.

Что происходит под капотом — упрощённая версия оркестрации:

python
1import asyncio
2from anthropic import Anthropic
3
4client = Anthropic()
5
6async def audit_route_file(filepath: str) -> dict:
7 """Один узел. Выполняется независимо от любого другого файла маршрутов."""
8 response = await client.messages.create(
9 model="claude-sonnet-5",
10 max_tokens=1000,
11 messages=[{
12 "role": "user",
13 "content": f"""Проверь этот файл маршрутов на:
14 - auth middleware, валидацию ввода,
15 ограничение скорости, обработку ошибок
16
17 Файл: {filepath}
18
19 Верни JSON: {{"file": "", "issues": [], "severity": ""}}"""
20 }]
21 )
22 return {"file": filepath, "result": response.content[0].text}
23
24async def consolidate(results: list[dict]) -> str:
25 """Единственное реальное ребро — ждёт завершения каждого узла аудита."""
26 response = await client.messages.create(
27 model="claude-opus-4-8",
28 max_tokens=2000,
29 messages=[{
30 "role": "user",
31 "content": f"""Объедини эти {len(results)} аудитов маршрутов
32 в один отчёт, сгруппированный по серьёзности:
33
34 {results}"""
35 }]
36 )
37 return response.content[0].text
38
39async def run_graph(route_files: list[str]):
40 # Разветвление — все независимые узлы выполняются конкурентно
41 audit_tasks = [audit_route_file(f) for f in route_files]
42 results = await asyncio.gather(*audit_tasks)
43
44 # Схождение — один узел с реальной зависимостью
45 report = await consolidate(results)
46 return report
47
48# 40 файлов маршрутов, один промпт, один параллельный проход
49results = asyncio.run(run_graph([
50 f"routes/{f}.py" for f in ["auth", "users", "billing", "orders"]
51 # ...ещё 36

40 последовательных API-вызовов по ~8 секунд каждый — это более 5 минут. Те же 40 вызовов, развёрнутых параллельно: менее 15 секунд, ограничено вашим самым медленным файлом, а не суммой всех.

Глава 4 — Где графы на самом деле ломаются

Графовая инженерия терпит неудачу в трёх предсказуемых местах. Знайте их, прежде чем столкнётесь.

Коллапс контекста. Разверните 1000 узлов и попытайтесь скормить все 1000 выводов одному этапу сводки — вы выйдете за пределы любого контекстного окна ещё до начала синтеза. Исправление: многоуровневое схождение. Группируйте узлы в пакеты по 20–50, суммируйте каждый пакет, затем объединяйте сводки — а не сырые выводы.

python
1async def layered_consolidate(results: list[dict], batch_size: int = 30):
2 """Схождение по уровням — никогда не синтезируйте сырые выводы в масштабе."""
3 batches = [results[i:i+batch_size]
4 for i in range(0, len(results), batch_size)]
5
6 batch_summaries = await asyncio.gather(*[
7 summarize_batch(batch) for batch in batches
8 ])
9
10 # Финальная сводка работает со сводками, а не с 1000 сырых результатов
11 return await consolidate(batch_summaries)

Ложная независимость. Вы будете считать два узла независимыми, потому что их промпты не ссылаются друг на друга — но оба пишут в один и тот же файл или обращаются к одному API с ограничением скорости. Это скрытое ребро. Исправление: проверяйте общие ресурсы, а не только общие данные. Два узла с конфликтом записи нуждаются в ребре, даже если нет зависимости по данным.

Тихий отказ узла. В цепочке один сбой останавливает всё — раздражающе, но очевидно. В графе один отказавший узел из 200 может исчезнуть в отчёте, который выглядит полным. Исправление: каждый этап схождения проверяет количество узлов относительно ожидаемого перед синтезом и явно отмечает пробелы, вместо того чтобы тихо работать с неполными данными.

python
1async def safe_consolidate(results: list[dict], expected_count: int):
2 if len(results) < expected_count:
3 missing = expected_count - len(results)
4 print(f"ПРЕДУПРЕЖДЕНИЕ: {missing} узлов отказали молча. "
5 f"Отчёт будет неполным.")
6 return await consolidate(results)

Глава 5 — Масштабирование до реального флота

wast3 - inline image

Как только шаблон работает на 40 узлах, масштабирование до сотен — это изменение конфигурации, а не перепроектирование, при условии, что вы правильно построили граф, начиная с Главы 2.

Полная форма для продакшена:

text
1 Orchestrator
2 |
3 +--------+-------+-------+--------+
4 v v v v v
5 Node 1 Node 2 Node 3 ... Node N
6 (parallel, no edges between any of them)
7 | | | |
8 +--------+-------+-------+-------+
9 v
10 Batch Summary <- layered fan-in
11 (groups of 30)
12 v
13 Final Report <- the one true edge

Единственная работа оркестратора: разложить задачу на узлы, определить реальные рёбра и отправить на выполнение. Он сам не работает — он рисует граф.

python
1async def orchestrate(task: str, resources: list[str]):
2 """
3 Узел оркестратора — декомпозирует, не выполняет.
4 """
5 plan = await client.messages.create(
6 model="claude-opus-4-8",
7 max_tokens=2000,
8 messages=[{
9 "role": "user",
10 "content": f"""Задача: {task}
11 Доступные ресурсы: {resources}
12
13 Разложи на граф:
14 - Перечисли каждый независимый узел (без общих рёбер)
15 - Перечисли любые реальные зависимости между узлами
16 - Сгруппируй узлы в пакеты схождения, если количество > 50
17
18 Верни JSON с: nodes, edges, batch_groups"""
19 }]
20 )
21
22 graph = parse_plan(plan.content[0].text)
23
24 # Выполнение независимых узлов параллельно
25 node_results = await asyncio.gather(*[
26 execute_node(n) for n in graph["nodes"] if not n["depends_on"]
27 ])
28
29 # Затем выполнение зависимых узлов, соблюдая только реальные рёбра
30 final = await execute_dependent_chain(graph["edges"], node_results)
31
32 return final

Именно это и представляет собой реальный сдвиг графовой инженерии: вы перестаёте быть тем, кто пишет каждый шаг, и становитесь тем, кто проектирует структуру зависимостей. Агенты заполняют узлы. Вы владеете рёбрами.

Что меняется, когда вы мыслите графами, а не линиями

Линейный агент с 40 шагами имеет 40 точек последовательного отказа и задержку в 40 раз больше, чем его самый медленный отдельный шаг.

Граф с теми же 40 единицами работы имеет столько точек параллельного отказа, сколько у вас реальных зависимостей — обычно от 3 до 5 в большинстве рабочих процессов — и задержку, ограниченную вашим самым медленным слоем, а не общим количеством шагов.

Это не просто ускорение. Это разница между рабочим процессом, который занимает 5 минут, и тем, который занимает 15 секунд, выполняя ту же самую работу.

Модель никогда не была узким местом. Линия, которую вы нарисовали, была.

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

Спасибо за чтение.

Переделать в YouMind

Превратите одну вирусную статью в полноценный рабочий процесс создания контента

Собирайте источники, расшифровывайте паттерны, создавайте активы, пишите черновики и публикуйте контент из одного рабочего пространства ИИ.

Исследовать YouMind
Для авторов

Превратите ваш Markdown в аккуратную статью для 𝕏

Когда вы публикуете длинные тексты, изображения, таблицы и блоки кода, форматирование в 𝕏 становится мучением. YouMind превращает полный черновик в Markdown в чистую статью, готовую к публикации в 𝕏.

Попробовать Markdown для 𝕏

Другие паттерны для анализа

Недавние виральные статьи

Смотреть другие виральные статьи