Як розділити агента підтримки на вузли intake, knowledge і support
Чому агент підтримки LEPA побудований як граф вузьких спеціалістів, а не одна велика функція, як LangGraph передає роботу через спільний стан і що тут означає «мультиагентність».
На цьому етапі агент підтримки LEPA вже вміє маршрутизувати запит, шукати в документації та пам'ятати гілку розмови. Лишилося подивитися, як організована сама робота. Замість однієї величезної функції, що робить усе, обов'язки розподілені між кількома спеціалістами, а координує їх LangGraph.
Уявіть будівництво будинку
Слово "мультиагентний" звучить як наукова фантастика. Корисніша інша картинка: будмайданчик, де над одним проєктом працюють кілька бригад:
Electrician
Plumber
Painter
Inspector
Різні завдання, різні навички, один будинок. Процес підтримки можна розділити так само:
Someone understands the request
Someone finds the handbook page
Someone writes the reply
Такий поділ виправданий, лише коли завдання справді різні. Зайві прямокутники на схемі в презентації не рахуються.
Граф у цьому проєкті
Скомпільований граф працює так:
START
→ intake
→ classify
→ conditional
├─ ask_clarification → END
└─ knowledge → support → END
Intake, knowledge і support у структурі проєкту називаються агентами, бо кожен має одне чітке завдання. Classify і крок з уточнювальним питанням лежать у теці nodes/: ідея графа та сама, просто теки названі трохи інакше. "Мультиагентність" тут означає спеціалізовані вузли всередині одного скомпільованого StateGraph. Це не окремі розгорнуті сервіси й не агенти, які сперечаються між собою. Назви тек важать менше, ніж розподіл відповідальності.
Що робить кожен спеціаліст
Intake
Intake бере останнє повідомлення користувача і видає user_role:
"I'm a teacher — how do I take attendance?"
↓
user_role = teacher
Він не шукає в документації і не пише фінальну відповідь. Його єдине завдання — підготувати контекст для маршрутизації.
Classify і гілка уточнення
Classify визначає тему і вирішує, чи достатньо даних, щоб іти далі:
"help" → ask for the LEPA area
"How do I enter grades?" → continue to knowledge
Ця розвилка і є оркестрацією: система та сама, змінюється лише наступний спеціаліст.
Knowledge
Knowledge ніколи не спілкується з користувачем. Він лише дістає документи:
query + issue_category
↓
search_knowledge_impl (keyword Markdown search)
↓
retrieved_documents
У тому ж модулі є обгортка @tool з назвою search_knowledge для майбутніх експериментів, але граф викликає саму реалізацію напряму.
Support
Support ніколи не ходить файловою системою. Він читає retrieved_documents і формує final_answer: за замовчуванням із шаблону, а якщо LLM налаштована, вона може цю відповідь дошліфувати.
Як LangGraph тримає порядок
Жодна LLM-менеджер не вирішує довільно, хто говорить наступним. Зв'язки задані явно:
graph.add_edge(START, "intake")
graph.add_edge("intake", "classify")
graph.add_conditional_edges("classify", route_after_classify, {...})
graph.add_edge("knowledge", "support")
Простими словами, LangGraph — це офіціант, а кожен вузол — окремий цех на кухні. Технічно ребра задають шлях за замовчуванням, умовні ребра задають розгалуження, що залежать від стану, а спільний SupportState дає спеціалістам змогу передавати одне одному результати, не викликаючи одне одного напряму. Саме ця властивість найважливіша:
Intake does not call Support.
Knowledge does not call Classify.
They write to state.
The graph decides the next node.
Чому не один агент?
Можна було обійтися однією функцією:
def handle(message):
detect role
classify
maybe clarify
search docs
write answer
Для крихітного демо це спрацює, але в навчальній системі такий підхід ховає шви. Розділений граф спрощує кілька речей:
- Тестувати класифікацію, не зачіпаючи пошук по документах
- Налагоджувати неправильну відповідь окремо від неправильного маршруту
- Згодом замінити один крок, наприклад поставити LLM-класифікатор чи кращий пошук, не переписуючи решту
- Пояснювати систему за простою схемою
Головний виграш мультиагентного підходу тут — ясність.
Чим це не є
Скажімо чесно: ці спеціалісти не окремі розгорнуті сервіси, вони не сперечаються між собою і це не автономні компанії агентів. Це вузькі вузли графа з чіткими контрактами, якими керує LangGraph. Щоб зрозуміти ідею, цього досить, і це чесний опис того, що робить проєкт.
Уся ідея в трьох рядках
Мультиагентна оркестрація в агенті підтримки LEPA зводиться до такого:
Specialize the jobs.
Share state.
Let the graph choose the next job.
Intake, knowledge і support розділені, бо мають різні обов'язки, а LangGraph робить передачу роботи між ними видимою. Далі за темою — human-in-the-loop: справжніх шлюзів схвалення в проєкті поки немає, і це не те саме, що уточнювальні питання.