Головна / Статті / Як розділити агента підтримки на вузли intake, knowledge і support

Як розділити агента підтримки на вузли intake, knowledge і support

Чому агент підтримки LEPA побудований як граф вузьких спеціалістів, а не одна велика функція, як LangGraph передає роботу через спільний стан і що тут означає «мультиагентність».

792 слів

На цьому етапі агент підтримки 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: справжніх шлюзів схвалення в проєкті поки немає, і це не те саме, що уточнювальні питання.