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

@0xWast3
АНГЛІЙСЬКА1 день тому · 22 лип. 2026 р.
146K
151
19
13
376

Коротко

Технічний огляд графової інженерії для AI-агентів, що демонструє, як виявляти реальні залежності та використовувати паралельне виконання для масштабування робочих процесів.

Усі, хто будує багатоагентні системи у 2026 році, досі пишуть прямими лініями. Крок перший, потім крок другий, потім крок третій — кожен чекає на попередній. Ось чому це повільно, і як це виправити.

wast3 - inline image

Проблема, яку ніхто не перевіряє

Ви побудували багатокрокового агента. Він працює. Але він повільний.

Ви думаєте, що вузьке місце — це модель. Але це не так.

Вузьке місце — це форма, яку ви намалювали. Ланцюжок — крок 1 чекає на крок 2, крок 2 чекає на крок 3 — змушує послідовне виконання, навіть якщо половина цих кроків не мають один до одного жодного відношення.

«Підсумуй цей документ, потім перевір погоду» — це дві незалежні задачі, які прикидаються одним робочим процесом. Завданню про погоду не потрібен підсумок. Воно ніколи його й не потребувало. Але якщо ви записали це як ланцюжок, воно все одно чекає.

Ось це марне очікування, помножене на десятки кроків, — саме там зникає більшість вашого часу виконання.

Розділ 1 - Цикли проти графів

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

text
1спробувати щось → перевірити результат → скоригувати → спробувати знову

Це і є атом. Один агент, один показник, цикл доти, доки не зійдеться.

Цикли мають відомий режим відмови: вони оптимізують саме те, що ви вимірюєте, і нічого іншого. Бот підтримки, налаштований швидко закривати заявки, закриватиме заявки швидко — поки задоволеність тихо падає. Цикл не бачить того, що за межами його власного показника. Це Закон Гудхарта у вашій архітектурі агентів.

Граф вирішує це за задумом. Замість одного циклу, що женеться за одним числом, ви будуєте мережу циклів, які спостерігають і виправляють один одного. Вихідні дані Вузла А живлять Вузол Б. Вузол В працює незалежно і перевіряє обох. Жоден окремий показник не керує всією системою — це робить структура.

wast3 - inline image

Для систем агентів це означає один конкретний зсув: перестаньте писати одного агента, який робить все від початку до кінця. Спочатку спроектуйте форму роботи — що має відбутися перед чим, що може виконуватися одночасно, що насправді має чекати.

Розділ 2 - Вузли, ребра та тест, який їх розділяє

Граф має рівно два компоненти:

Вузол — одна одиниця роботи. Один агент, одне завдання, один вхід, один вихід.

Ребро — справжня залежність. Вхідні дані Вузла Б потребують вихідних даних Вузла А.

Помилка, якої припускаються майже всі: сприймати «а потім» як ребро за замовчуванням.

text
1«Прочитай цю кодову базу, а потім напиши список змін»
2«Отримай сторінку ціноутворення, а потім підсумуй характеристики конкурентів»

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

Чи справді наступний крок читає вихідні дані попереднього кроку?

Так → справжнє ребро. Зберігайте послідовний порядок.

Ні → не ребро. Очікування марне. Виконуйте їх паралельно.

Якщо жодні дані не перетинають межу між двома завданнями, вони незалежні — і кожна незалежна пара, яку ви виконуєте послідовно, — це час виконання, який ви просто викидаєте.

Ось тест, застосований у коді:

python
1from dataclasses import dataclass
2
3@dataclass
4class TaskNode:
5 id: str
6 prompt: str
7 depends_on: list[str] # Ідентифікатори вузлів, які цей насправді потребує
8
9def has_real_edge(node_a: TaskNode, node_b: TaskNode) -> bool:
10 """
11 Основний тест графічної інженерії:
12 чи дійсно prompt вузла 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- обробка помилок не витікає stack traces
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 - Де графи насправді ламаються

Графічна інженерія зазнає невдачі у трьох передбачуваних місцях. Знайте їх, перш ніж натрапите на них.

Колапс контексту. Розгалужте 1 000 вузлів і спробуйте передати всі 1 000 вихідних даних в один крок зведення — ви перевищите будь-яке контекстне вікно ще до початку синтезу.

Виправлення: шароване згортання. Групуйте вузли в партії по 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 # Фінальне зведення працює з підсумками, а не з 1 000 необроблених результатів
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 Оркестратор
2 |
3 +--------+-------+-------+--------+
4 v v v v v
5 Вузол 1 Вузол 2 Вузол 3 ... Вузол N
6 (паралельно, без ребер між жодним з них)
7 | | | |
8 +--------+-------+-------+-------+
9 v
10 Підсумок партії <- шарове згортання
11 (групи по 30)
12 v
13 Фінальний звіт <- єдине справжнє ребро

Єдина робота оркестратора: розкласти завдання на вузли, визначити справжні ребра та відправити на виконання. Він сам не виконує жодної роботи — він малює граф.

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

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

Збирайте джерела, розшифровуйте патерни, створюйте матеріали, пишіть чернетки та поширюйте контент в одному AI-робочому просторі.

Дослідити YouMind
Для авторів

Перетворіть свій Markdown на охайну статтю для 𝕏

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

Спробувати Markdown для 𝕏

Більше патернів для аналізу

Останні віральні статті

Переглянути більше віральних статей