Проєктування стійких графів AI-агентів: повторні спроби, альтернативні рішення та GraphRAG
Дізнайтеся, як створювати робочі процеси AI-агентів, стійких до збоїв, за допомогою чітко визначених сценаріїв виникнення помилок, логіки повторних спроб, LangGraph та випадків, коли GraphRAG перевершує звичайний RAG чи цикли агентів.
Коли трапляються збої: планування альтернативних шляхів
Продовжуючи попередню дискусію, уявімо, що на цьому етапі агент з фінансових досліджень став значно більш складним у своїй роботі.
Згадаймо приклад запитання, яке може поставити менеджер портфеля — наприклад, чому ціна певної акції впала після оприлюднення звіту про прибутки та які ризики вимагають уваги у майбутньому. Ця система може розібрати таке запитання, отримати дані з кількох джерел, провести аналіз результатів, сформулювати відповідь, перевірити її та, за потреби, надіслати на перегляд людині — по суті, це модель з участю людини.
Однак є один аспект, який ми поки що не розглянули: що відбувається, коли якийсь крок у цьому процесі зламується?
Уявімо, що система доходить до відділу, відповідального за ринкові дані.
Він надсилає запит щодо змін цін та обсягу торгівлі, але постачальник даних не відповідає.
У такій ситуації просто перейти до кроку Analyze, ніби нічого не сталося, неможливо.
Водночас повне припинення всієї процедури зазвичай є занадто радикальним рішенням, адже системи промислового рівня потребують певної форми запасного режиму функціонування.
Саме тому невдача має розглядатися як окремий гілка у діаграмі, а не як щось другорядне.
Початковий, простий алгоритм виглядає так:
Search Market Data
↓
Analyze
Ми можемо перетворити його на щось подібне до цього:
Search Market Data
/ \
↓ ↓
Success Failure
↓ ↓
Analyze Retry (how to handle this!?)
За такою структурою діаграма має чітку інструкцію щодо дій у разі невдачі запиту.
Керування логікою повторних спроб
Якщо повторна спроба вдасться, робочий процес просто продовжується як зазвичай.
Якщо це знову зазнає невдачі, можливо, буде доцільніше перейти на інший джерело даних або передати справу на перевірку людиною, замість того щоб постійно надсилати однакові запити.
Ось більш детальна версія цього розгалуження:
Search Market Data
/ \
↓ ↓
Success Failure
↓ ↓
Analyze Retry
↓
┌──────┴──────┐
↓ ↓
Success Failure
↓ ↓
Analyze Alternative
Source
Тут важливо не кількість спроб повторення — а те, що обробка невдач вбудована у дизайн графу з самого початку. Як показано на діаграмі, різні види невдач можуть призвести до різних шляхів.
Припустимо, API з ринковими даними просто вичерпує час очікування. Повторна спроба є доцільною, оскільки проблема, ймовірно, тимчасова.
Але якщо запит проходить успішно, але просто не повертає нічого корисного за відповідний період часу, повторення цього самого запиту нічого не дасть.
У такому випадку кращим рішенням буде звернутися до альтернативного, схваленого джерела даних.
Якщо й це не дає результату, ситуацію, ймовірно, варто передати на розгляд людини-редактора. Саме такі деталі визначають різницю між нестабільним та надійним процесом виконання завдань.
Функція маршрутизації, яка це забезпечує, може виглядати так:
def route_after_market_search(state):
if state["market_data"]:
return "analyze"
if state["retry_count"] < 2:
return "retry"
return "human_review"
Ці умови встановлюють чіткі межі для алгоритму — повторна спроба дозволена, але не нескінченно.
Той самий принцип застосовується до всіх етапів процесу, адже може трапитися багато проблем по дорозі:
- Етап отримання даних може зазнати невдачі
- Запит до LLM може зазнати невдачі
- Певне джерело інформації може бути тимчасово недоступним
- Сформована відповідь може не пройти перевірку на коректність
Замість того, щоб огорнути всю програму одним величезним обробником помилок, можна окремо для кожного вузла вирішувати, що робити саме у момент виникнення проблеми.
Це одна з причин, чому моделювання робочого процесу у вигляді графа є привабливим. Коли трапляється збій, вам не доводиться ставити розпливчасте запитання на кшталт „Чому агент зазнав невдачі?“
Натомість ви можете простежити саме той шлях, яким пройшов процес виконання, та точно визначити, де сталася проблема:
Understand
↓
Search Filings ✓
↓
Search Earnings ✓
↓
Search Market Data ✗
↓
Retry ✓
↓
Analyze
↓
Write
↓
Check
Це дає вам конкретний об’єкт для аналізу замість „чорної скриньки“.
Звісно, у міру збільшення графа керування всім цим вручну починає вимагати значних зусиль — і це цілком обґрунтована проблема.
У такій ситуації доводиться мати справу з логікою виконання, керуванням станом, умовним маршрутизуванням, обробкою повторних спроб, зберіганням даних та способом перевірки того, що насправді відбулося під час певного запуску.
Саме в таких ситуаціях фреймворк допомагає уникнути необхідності заново створювати ту саму систему оркестрації для кожного проекту.
Саме цю прогалину призначений заповнити LangGraph.
LangGraph
За наявності такої платформи ваш робочий процес може бути розділений на окремі дослідницькі завдання, після чого результати можна об’єднати, спробувати ще раз виконати невдалі кроки, зупинитися для участі людини та відстежувати стан під час переходу виконання з однієї стадії на іншу.
Звісно, для створення цієї схеми та її фактичного запуску все одно потрібна робота.
Ви можете самостійно організувати весь процес координації, але це означатиме необхідність підтримки великої кількості інфраструктури, яка існуватиме поруч із основною логікою штучного інтелекту.
LangGraph розроблений саме для обробки цього шару.
LangGraph — це платформа, створена для будови робочих процесів агентів, які мають стан та базуються на графах. Замість того, щоб розглядати агента як окремий цикл, який постійно запитує модель мови, що робити далі, ви чітко визначаєте вузли, переходи між ними, спільний стан та загальний потік виконання.
Якщо повернутися до дослідницького агента NVIDIA, про який йшлося раніше, його структуру можна намалювати приблизно так:
Question
↓
Understand
↓
┌──────────┼──────────┐
↓ ↓ ↓
Filings Earnings Market
↓ ↓ ↓
└──────────┼──────────┘
↓
Analyze
↓
Write
↓
Check
↙ ↓ ↘
Search Rewrite Human
↓ ↓ Review
└───────┴───────┘
↓
Send
Варто зазначити, що структура графа та справжня логіка застосунку можуть існувати в одному й тому ж кодовому базисі.
Спрощена реалізація LangGraph цього ж процесу може виглядати так:
from langgraph.graph import StateGraph, END
builder = StateGraph(ResearchState)
builder.add_node("understand", understand)
builder.add_node("search_filings", search_filings)
builder.add_node("search_earnings", search_earnings)
builder.add_node("search_market", search_market)
builder.add_node("analyze", analyze)
builder.add_node("write", write)
builder.add_node("check", check)
builder.set_entry_point("understand")
builder.add_edge("understand", "search_filings")
builder.add_edge("understand", "search_earnings")
builder.add_edge("understand", "search_market")
builder.add_edge("analyze", "write")
builder.add_edge("write", "check")
Наведений вище фрагмент є навмисно мінімальним, щоб ви могли зосередитися на основній концепції — поєднанні вузлів, ребер та понять стану, представлених раніше в цій серії.
- Кожен вузол обробляє одну одиницю роботи
- Граф визначає, як ці одиниці пов’язані між собою
- Стан — це те, що передає інформацію від одного вузла до іншого
Це насправді все. Ця концепція набагато простіша для розуміння, ніж спроба вмістити все в один величезний запит до агента.
Ви можете подивитися на сам граф та зрозуміти, яку функцію має виконувати робочий процес, ще до того, як почнете детально вивчати реалізацію кожного окремого вузла.
Припустимо, ви хочете додати крок людського схвалення перед тим, як надіслати остаточну відповідь — вам доведеться безпосередньо змінювати структуру робочого процесу:
Check
↓
Human Review
↓
Send
Немає потреби ховати такі рішення десь у запиті. Сама структура робить їх зрозумілими та полегшує їх дотримання вашою командою.
Чому обирати LangGraph замість звичайного циклу агента?
Традиційний цикл агента зазвичай має таку структуру:
Think
↓
Choose Tool
↓
Use Tool
↓
Think Again
↓
Choose Tool
↓
...
У цій конфігурації модель має значну свободу у вирішенні того, що робити далі. Ця гнучкість справді корисна, коли завдання за своєю природою є відкритим.
Але процес фінансових досліджень, описаний тут, включає кілька моментів прийняття рішень, які ви, ймовірно, захочете контролювати більш суворо. Саме це є ключовим аспектом проблеми.
Не кожен процес вимагає використання циклу агента.
Розгляньмо кілька прикладів:
- Можливо, системі потрібно зібрати певні докази перед тим, як їй дозволять надати відповідь.
- Ви можете бажати, щоб ринкові дані та звіти отримувалися окремо один від одного.
- Можливо, потрібен крок перевірки перед тим, як щось буде надіслано людині-рецензенту.
- Ви можете хотіти, щоб процес автоматично зупинявся після певної кількості спроб.
Це не ті варіанти, які обов’язково слід залишати на розсуд моделі під час кожного запуску. У межах циклу немає способу гарантувати, що модель буде робити однаковий виклик щоразу.
Граф дозволяє безпосередньо вбудувати ці обмеження у структуру робочого процесу. Модель все ще може міркувати в кожному окремому вузлі, але навколишня система визначає, куди їй дозволено рухатися далі.
Це ключова відмінність, яку потрібно пам’ятати. Мета не в тому, щоб позбавити агента здатності до міркувань — а в тому, щоб свідомо вирішити, де саме мають знаходитися ці міркування, а де краще підходить детерміністичне керування.
У міру того, як ви продовжуєте створювати робочі процеси, що працюють із структурованими фінансовими даними, виникає нове питання.
Наразі наш агент отримує документи та цифри з різних джерел. Але що відбувається, коли базова інформація містить зв’язки, які справді мають значення?
- Компанії наймають керівників
- Ці керівники часто входять до рад директорів компаній
- Одна компанія може придбати іншу
До цього моменту ми розглядали кожен елемент даних як окремий. Проте зв’язки, показані вище, важко представити, якщо ваша база знань — це лише низка окремих документів.
Це приводить нас до ще однієї ключової концепції: GraphRAG.
GraphRAG
Досі ми використовували графи переважно для керування способом поведінки агента. Але графи можуть виконувати ще одну функцію:
організація самих знань.
У нашому прикладі традиційна конфігурація RAG могла б збирати документи, в яких йдеться про прибутки NVIDIA, прогнози розвитку, показники доходів, маржі та реакцію ринку.
Цей підхід добре працює, коли відповідь знаходиться переважно в кількох релевантних документах. Але фінансові питання не завжди є настільки обмеженими.
Значуща відповідь часто залежить від з’єднання інформації, розкиданої по кількох окремих документах.
Уявіть собі ситуацію, коли потрібно зрозуміти не лише те, що повідомила NVIDIA, а й те, як різні частини цього звіту взаємопов’язані (це саме та ситуація, з якою ми маємо справу).
Саме тут і стає корисним граф знань.
Замість того, щоб зберігати знання лише у вигляді фрагментів тексту, ми можемо моделювати важливі ентитети та зв’язки між ними:
NVIDIA ──→ produces ──→ GPUs
│
├──→ reports ──→ Earnings
│
├──→ depends on ──→ Suppliers
│
├──→ competes with ──→ AMD
│
└──→ operates in ──→ AI Infrastructure
Тепер граф фіксує зв’язки, які ніколи не стали б очевидними при читанні будь-якого окремого документа.
RAG порівняно з GraphRAG
Стандартний RAG зазвичай працює шляхом отримання відповідних уривків та подачі їх моделі як контексту. Ось спрощений огляд цього процесу:
Question
↓
Retrieve relevant chunks
↓
LLM
↓
Answer
GraphRAG додає додатковий рівень. Система може використовувати зв’язки між елементами, щоб визначити, яка інформація насправді має значення:
Question
↓
Identify entities
↓
Traverse relationships
↓
Retrieve relevant information
↓
LLM
↓
Answer
Для нашого агента з фінансових досліджень це стає корисним кожного разу, коли питання вимагає поєднання кількох елементів чи документів одночасно.
Припустимо, менеджер портфеля запитує: які ризики можуть виникнути для NVIDIA, якщо попит на інфраструктуру ШІ знизиться?
Щоб дати належну відповідь, може знадобитися пов’язати NVIDIA з її продуктами, клієнтами, постачальниками, конкурентами, загальними умовами ринку та ризиками, які вона вже вказувала у попередніх звітах.
Граф надає системі пошуку структурований шлях для дослідження всіх цих зв’язків.
NVIDIA
/ | \
/ | \
Products Suppliers Competitors
| | |
↓ ↓ ↓
AI GPUs Supply Risk AMD
|
↓
AI Infrastructure
|
↓
Demand
Звідти модель може аналізувати все, що було отримано з цих пов’язаних ентитетів.
Це не означає, що GraphRAG завжди кращий за звичайний RAG. Додаткова структура виявляється корисною саме тоді, коли зв’язки між фрагментами інформації є ключовими для поставленого запитання.
Якщо відповідь знаходиться без проблем у одному звіті про дохід, ймовірно, достатньо звичайного процесу пошуку.
Якщо для відповіді на запитання потрібно об’єднати інформацію, розкидану між багатьма ентитетами та джерелами, схема на основі графа стає значно привабливішою.
Є ще одна важлива різниця, яку варто пам’ятати: ваш граф робочого процесу та ваш граф знань — це дві абсолютно різні речі.
Граф робочого процесу відповідає на запитання, що агент повинен зробити далі. Граф знань відповідає на запитання, що як пов’язано між собою в даних, з якими ви працюєте.
У нашій системі обидва можуть існувати поруч один з одним:
WORKFLOW GRAPH:
Question
↓
Retrieve
↓
Analyze
↓
Write
↓
Check
Тоді як на нижчому рівні шар пошуку працює з:
KNOWLEDGE GRAPH:
NVIDIA
├── Products
├── Suppliers
├── Competitors
├── Executives
├── Filings
└── Industry
Зверніть увагу на розподіл обов’язків: одна структура керує виконанням, тоді як інша організовує знання та взаємозв’язки між ними.
Як тільки ці два підходи починають підсилювати один одного, агент з фінансових досліджень стає значно потужнішим.
- Робочий процес визначає як проводяться дослідження.
- Граф знань визначає які частини інформації пов’язані між собою.
Звісно, це піднімає додаткове запитання: якщо графи забезпечують такий рівень контролю, чи слід кожен робочий процес будувати у вигляді графа?
Не обов’язково.
У багатьох випадках для вирішення проблеми достатньо простого циклу агента.
Тож замість того, щоб за замовчуванням перетворювати кожен робочий процес ШІ на граф, варто безпосередньо порівняти обидва підходи та з’ясувати, коли додана складність роботи з графами справді приносить користь.
Варто пам’ятати, що графи надають більше контролю, але цей контроль супроводжується додатковою роботою: тепер ви самі повинні розробляти та підтримувати цю структуру.
Якщо базове завдання справді просте, його обгортання у граф може насправді ускладнити розуміння системи, не принесши значних переваг у взамін.
Повернімося до прикладу агента фінансових досліджень. Припустимо, користувач запитує щось на кшталт: Узагальніть останній звіт про фінансові результати NVIDIA.
Це конкретний, самодостатній запит.
Його можна обробити шляхом отримання відповідного звіту та передачі його моделі для створення узагальнення:
Question
↓
Retrieve Report
↓
Summarize
↓
Answer
Тут немає складної логіки чи розгалужень. Звичайний підхід RAG або простий цикл агента чудово впораються з цим.
Тепер порівняйте це з більш широким запитом, коли користувач хоче зрозуміти, що спричинило падіння ціни акцій після оприлюднення звіту, хоче порівняти цей результат із прогнозами аналітиків, хоче отримати список ризиків, які варто стежити у майбутньому, та хоче підтвердити отримані висновки перед тим, як вони будуть включені до звіту про портфель.
Це зовсім інший тип проблеми.
Ця версія передбачає кілька видів досліджень, використовує дані з різних джерел, потребує підтвердження, може вимагати кількох спроб та включає етап людського перегляду.
Тепер процес роботи виглядає приблизно так:
Question
↓
Understand
↓
┌──────────┼──────────┐
↓ ↓ ↓
Filings Earnings Market
↓ ↓ ↓
└──────────┼──────────┘
↓
Analyze
↓
Write
↓
Check
↙ ↓ ↘
Search Rewrite Human
↓ ↓ Review
└───────┴──────┘
↓
Send
На цьому рівні складності чітке описання процесу роботи починає приносити користь.
То коли достатньо циклу агента?
Цикл агента зазвичай є правильним рішенням, коли модель отримує певну свободу у виборі інструменту для подальших дій.
Наприклад:
Question
↓
LLM decides what to do
↓
Tool
↓
LLM decides what to do next
↓
Tool
↓
Answer
Коли завдання є дослідницьким, а ви не можете заздалегідь передбачити кількість кроків, така гнучкість є справді цінною.
Агент може вирішити, що йому потрібно перевірити відомості про доходи, потім взяти певний показник та знайти додатковий контекст. Вам не обов’язково заздалегідь пропланувати кожну можливу схему дій.
Коли граф починає бути зрозумілішим?
Граф стає корисним тоді, коли робочий процес має правила, які справді мають значення.
Для системи фінансових досліджень ці правила можуть виглядати так:
Retrieve evidence
↓
Run analysis
↓
Generate draft
↓
Verify claims
↓
Human review
↓
Publish
Це обмеження на рівні робочого процесу, і граф дозволяє вам кодувати їх безпосередньо, замість того щоб сподіватися, що модель сама їх визначить.
Компроміс
Граф надає вам контроль, але це також означає необхідність керування складнішою архітектурою.
Тепер вам потрібно ретельно обміркувати:
- як структуровано стан
- логіку маршрутизації
- що відбувається, коли щось зламується
- поведінку під час повторних спроб
- стабільність зберігання даних
Жоден з цих елементів не є за своєю суттю поганим — це просто означає, що граф має обґрунтувати додаткові витрати, які він створює.
Для дослідницького агента NVIDIA не має сенсу з самого початку будувати весь граф лише тому, що графи є цікавими.
Натомість додаткову структуру слід вводити лише тоді, коли це дійсно необхідно у рамках робочого процесу:
- Почніть з простого.
- Додавайте розгалуження тоді, коли вони справді потрібні.
- Додавайте паралельну обробку тоді, коли завдання можуть справді виконуватися незалежно одне від одного.
- Додавайте контрольні точки тоді, коли робочий процес потребує паузи або відновлення після перерви.
- Додайте крок людського перегляду тоді, коли значимість ситуації виправдовує додаткові зусилля.
- Введіть GraphRAG тоді, коли взаємозв’язки всередині самих знань починають мати значення.
Таким чином, граф існує тому, що це вимагає сама проблема, а не тому, що він доступний.
Заключні міркування
Це, ймовірно, головний урок, який можна засвоїти, працюючи над таким дизайном.
Граф існує не для того, щоб система ШІ виглядала складною. Він створений для того, щоб полегшити розуміння та керування робочим процесом.
Агент для фінансових досліджень, розроблений на основі цих обговорень, тепер може розділяти завдання на підрозділи, перезапускатися, зупинятися, використовувати людського рецензента та навіть спиратися на зв’язки між елементами знань, коли це доцільно.
Проте все це не означає, що кожній системі потрібен граф. Іноді достатньо простого конвеєра RAG. Іноді цикл агента покриває все, що вимагає проблема.
Справжня навичка — це здатність визначити момент, коли проблема стає настільки складною, що граф вартий інвестицій.