Галоўная / Артыкулы

Створыце маршрутаўчык з калькольнікаю агентаў за дапамогою LangGraph і агента-надзірніка.

Як разліцаваць аднаго перанасытанага агента на спецыялістаў з камандавальнікам у LangGraph, выкарыстоўваючы готавыя дапаможнікі і ручны StateGraph, а таксама прыметы дзеяння і падазры ў цікле.

Выдавец: REACTAPP.TOP9 хв чытання2122 слоў

Крыніцы: Build a Multi-Agent Router with LangGraph in 30 Minutes

Як толькі агента разам з рэальным продуктом, ён быстра пачынае выканаць занадта много задач. Калі прабаваць паказваць аднаго агента для адказвання на запыткі клёянтаў, назірання за замовленнямі і выплатаў грошаў, ён будзе сярэднім у всіх трох аспектах. Яго інструкцыі прыводзяць да 2000-словага клубка правілаў на кшталт „калі корыстувач запытае пра X, трэба зрабіць Y, але якшо таксама і пра Z, тады...“. Рашэнням ня ў тым, каб стварыць хутчэйшага агента; трэба больш, меньшых агентоў плюс аднаго керавальніка, які распрацоўвае запыткі между ўсімі. Гэта, па-вялікаму, найбольш распространены ў настоўчы час патэрн выкарыстання агентных AI, і працоўная версія такога рашэння помешчаецца ў короткай програме LangGraph.

Проблемы з адным велікім агентам

Спадзяйце, што вы ствараеце асістэнта, які адпавядае на загальныя запытанні, выконвае арыметычныя расчытанні і шукае актуальную інфармацыю ў Інтэрнэце. Пахаманы падход — адна ейніца, адны вялікі запыт і всі засобы прыўязаны да яго. Калі колькісць засобаў і інструкцый зростае, мадэль становіцца непакойная ў выборы засобу, а яе логіка становіцца менш чыстай. Адлагоджэнне ператвараецца на кошмар, таму што немагчыма з’ясавіць, чаму ён выбраў неправільны засоб, калі усё знаходзіцца ў аднам запытанні.

Рашэнне — раздзеліць абавясанні: адна ейніца для матэматыкі, адная для даследжэнняў, і керавальнік, які ёсць проста маршрутарам і вяршыць выбіранне таго спецыяліста, які будзе займацца кожной часткаю запытання.

Шаблон керавальніка

Уявіць собі центр обслуговувань кліентыв. Ві тэлефонуеце з пітанням, але неспрамовуюцца безпосерэдно до експерта. Спочатку слухаецьфоністка, вірышуе, чы потрэбуеце ві бюрокофтынг, тэхнічноі підтрымкі чы продажыв, і перэдае вас. Сам фонд ніколі не відповідае на запітання. Яго едыне задачы — обраты, хто мае відповісты.

Візуально гэта віглядае так:

                    ┌─────────────┐
                    │    User     │
                    │   Request   │
                    └──────┬──────┘
                           │
                           ▼
                   ┌───────────────┐
                   │   Supervisor  │
                   │  (routes task)│
                   └───────┬───────┘
                    ┌──────┴──────┐
                    ▼             ▼
             ┌────────────┐ ┌────────────┐
             │  Research  │ │    Math    │
             │   Agent    │ │   Agent    │
             └──────┬─────┘ └──────┬─────┘
                    │              │
                    └──────┬───────┘
                           ▼
                   ┌───────────────┐
                   │   Supervisor  │
                   │ (final answer)│
                   └───────────────┘

Надзірнік берэ задачы, перадае яго правам спецыялісту, апроцэсуе рэзультат і тады вырашае, чы роўна ўжо раз праадрасаваць задачы чы даць корыстніку фінальную адпаведзь.

Рэкамендаваны спосаб стварэння, па кроках

Тое, што варта ведаць пры напісанні коду: каманда LangChain зараз радзіць ствараць патэрн надзірніка безпосерэдна з выклікання інструментаў, а не толькі на базе старэй бібліятэкі-памагчыцы langgraph-supervisor, таму што выклікання інструментаў дае большую контроль над канструюванням кантэкста. Ёсць швыдкая ужо створаная версія, а пасля — ручная, ўбачлівае, што відбываецца пад час експлуатацыі.

Крок 1: інсталюйце пакеты

pip install langgraph langchain-openai langgraph-supervisor

Шаг 2: стварэнне спецыялістаў

Пачніце з імпорту:

from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent

Першы спецыяліст займаецца матэматыкай, а яе інструментамі ўсьмо два маленькія функцыі. Спачатку выконуецца аднаўленне:

# Specialist 1: handles math
def add(a: float, b: float) -> float:
    """Add two numbers together."""
    return a + b

Потым умножэнне:

def multiply(a: float, b: float) -> float:
    """Multiply two numbers together."""
    return a * b

Загульціюйце іх у агента ReAct з іменем і заповедзю, якая обмежвае яго ролю:

math_agent = create_react_agent(
    model="openai:gpt-4o",
    tools=[add, multiply],
    name="math_expert",
    prompt="You are a math specialist. Solve numeric problems precisely."
)

Другі спецыялісты здзейснююць даследаванні. Аднам з іхніх інструментаў ёсць функцыя пошуку, якая паказана тут:

# Specialist 2: handles research
def web_search(query: str) -> str:
    """Search the web for current information."""
    # In production, replace this with a real search API call
    return f"Search results for '{query}': [your real search integration here]"

Таксама загуліце гэта ў агента:

research_agent = create_react_agent(
    model="openai:gpt-4o",
    tools=[web_search],
    name="research_expert",
    prompt="You are a research specialist. Find accurate, current information."
)

Кожны агент мае роўна адну задачу і толькі тыя засобы, якія яе выкананню неабходны, таму немае плутання і некальканая інструкцыя. У прыкладах выкарыстоўваныя мадэлі OpenAI, хоць такі безкоштовны альтэрнатыўны варыянт, як Groq або OpenRouter, таксама падойдзе.

Шаг 3: стварэнне супервізора

Імпортуйце дапаможнік:

from langgraph_supervisor import create_supervisor

Tады дадзець дваякіх спецаў, модэль і падказваць як канфыяклівыя, калі вжываць кожны з яўных:

workflow = create_supervisor(
    [research_agent, math_agent],
    model=ChatOpenAI(model="gpt-4o"),
    prompt=(
        "You are a team supervisor managing a research expert and a math expert. "
        "For questions requiring current information or web lookups, use research_expert. "
        "For anything involving calculation, use math_expert. "
        "Route each request to exactly the right specialist."
    )
)

Скомпілюйце рабочы працэс у запускаемыя прыкладніцу:

app = workflow.compile()

Шаг 4: запуск

Адрасуйце задачу з матэматыкі:

result = app.invoke({
    "messages": [
        {"role": "user", "content": "What's 1,847 multiplied by 293?"}
    ]
})

Івадзецькі словы:

print(result["messages"][-1].content)

Гэта тое, што адзначаецца ўнутршняя частка прылады:

  1. Надзорнік чытае запіт.
  2. Ён бачыць вырахунак, а не пытанне для даследжэння.
  3. Ён перадае задачу math_expert.
  4. math_expert вырахоўвае адпаведны адказ за дапамогою свайго інструмента multiply.
  5. Надзорнік знову берае кантроль і вяртае адказ.

Для пытанняў даследжэння, такіх як ныякія паказчыкі колькасці працавальнікаў у вялікіх тэхналогічных компаніях, той самы надзорнік перадае ўпрабавку research_expert. Код застаецца ідэнтычным, а зменшыцца толькі рашэнне пра маршрутазаванне, і LLM сама прыме гэта рашэння.

Што на самай працы ўпрабавкі

Што стосуецца гэтай часткі, яна усуняе адчуванне магіі. Супервайзар не працюе праз які-небудзь суперашчытны механізм LangGraph; ён віконвае свае задачы за дапамою вызоваў інструментаў, так сама як і будзь-яй звычайны агент, які вікорыстоўвае інструменты. У тле функцыя create_supervisor стварае інструменты для перадачы задач кожнаму спеціялісту, з такімі назвамі, як transfer_to_research_expert і transfer_to_math_expert. Мадэль супервайзара спрыяе гэтыя інструменты як можлівасці для вызова, не адрознюючы іх ад, напрыклад, запітаў пра пагоду; таму, калі ён вырашывае, што патрэбны дальнейшыя даследжэння, ён проста вызывае функцыю перадачы. Рэзультат ўтымчас цікавы: супервайзар ужо не ўяўляе сабой новую концэпцыю. Гэта проста звычайны цыкл агента, у якім дэякія з інструментаў ёсць іншымі агентамі, а не вызывамі API.

Стварэнне яго вручную

Калі вы хочаце цалковы кантроль над маршрутызацыяй, што рэкамендуецца празь час пераходу да прымэтнага выкарыстоўвання, то гэта ўсноўная версія, створаная на базе неапранутага StateGraph. Пачніце з імпортаў:

from typing import Annotated, Sequence, TypedDict
import operator
from langchain_core.messages import BaseMessage
from langgraph.graph import StateGraph, END

З’явіце спадзейны стан, які храніць спіс паведамленняў і назву наступнага вузла:

class AgentState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], operator.add]
    next: str

Блок керування дывіцца на найновішэ повідомлення:

def supervisor_node(state: AgentState):
    """Decide which specialist should act next."""
    last_message = state["messages"][-1].content

У рэальных умовах рашэнне будзе прынятыя на адказе LLM. Чырвоны ў выпадку тут скарацаны да простых пераглядоў ключоўых слоў, тады логіка направлення застаецца відна:

# In production, this decision comes from an LLM call —
    # simplified here to show the routing logic clearly
    if any(word in last_message.lower() for word in ["calculate", "multiply", "add", "sum"]):
        return {"next": "math_agent"}
    else:
        return {"next": "research_agent"}

Кожны спецыяліст атрымляе вузел, які запускае яго агента, а пасля вяртае кантроль назад супервізору. Спачатку матэматыка:

def math_node(state: AgentState):
    result = math_agent.invoke(state)
    return {"messages": [result], "next": "supervisor"}

Потым — даследжэнне:

def research_node(state: AgentState):
    result = research_agent.invoke(state)
    return {"messages": [result], "next": "supervisor"}

Далей з’ѐднайце граф, зарэгіструаваўшы вузлы:

# Wire the graph together
workflow = StateGraph(AgentState)
workflow.add_node("supervisor", supervisor_node)
workflow.add_node("math_agent", math_node)
workflow.add_node("research_agent", research_node)

Установіце точку запуску:

workflow.set_entry_point("supervisor")

Дадзіце умовныя рэшткі, якія вылічваюцца на адказ адпраўніка:

workflow.add_conditional_edges(
    "supervisor",
    lambda state: state["next"],
    {"math_agent": "math_agent", "research_agent": "research_agent", "end": END}
)

Пасля гэтага адразу падаць кожнага спецыяліста да надзірніка:

workflow.add_edge("math_agent", "supervisor")
workflow.add_edge("research_agent", "supervisor")

І складаць:

app = workflow.compile()

Гэта більш дэталізована версія, але нічого не прыховуецца. Ві можэце бачыты, як працюе сістэма, як прыймаюцца кожні рышэння шчодо маршрутызаціі, а таксама дэ можна додаты власну логіку – напрыклад, функціі журналування, захісні механізмі чы умові завершэння працы.

Вібір структуры даных, які найбільшэ ускладнюе працу з часом

Поперэджэння з практыкі вікорыстання: схема даных ёсць найскладнішою частыною, яку пізнішэ важко змініты. Існуе спокуса ужо на початку помістыты всі можліві поля у одын плоскій словнік, які бі охоплював повідомлення, кантэкст корыстувача і проміжні рэзультаты. Гэта підходыць для сістэм з двома агентамі. Однак пры вікорыстанні восьмі чы дэсяты вузлів, які всі разом чытаюць і запісуюць однаковій спільній стан, гэта стае проблематычнім, оскількі перэвірка тыпів у LangGraph ёсць суворою, а рэдагування перэвантажэного стану вімагае змін у кожному вузлі. Тож необхідно з самого початку рэтэльно сплануваты схему даных, навіць для сістэмі з двома агентамі. Візначце, што саме кожэн агент дыйсно потрэбуе чытаты і запісуваты, а все іншэ залішце поза спільнім станом.

Такая проблема, з якой вы станеце сустрэчыцца

Сістэмы-надзірнікі, якія выходзяць у працю, часта практыкуюць такі патэрн. Уявіце, што надзірнік дава задачэ спецыялісту. Спецыяліст яго выкананае, але надзірнік судзіць, што рэзультат недастатковы, і вяртае яго назад. Спецыяліст вносіць правкі, і новая версія насправды стае ўжо гorsай, чым першая. Надзірнік заўсёды незадоволены і зноў вяртае яго, і калі вы не захавацеся ад гэтага, гэта можа продовжвацца несканчатна.

Рэшэнняя — гэта ліміт колькасці разоў, калі надзірнік вяртае заданне, што можа быць простым лічыльнікам у стане, а таксама чыткай, дэтэрміністычной умовай завершэння. Мненне LLM пра тое, чы рэзультат дастаткова хорашы, не ўсегда являецца надзійным едынственным крытэрыям для завершэння.

Калі не варта яго выкарыстоўваць

Будзьце чыстыя ў пытанні падходжання. Калі задача складаецца з аднаго запрашэння інфармацыі па ўзнакамі, а пасля — з аднаго стварэння адпаведнай адпаведзі, як у звычным фармаце RAG для запытань і адпаведзей, тады наявнасць керуючага агента ёсць зайвай. Дадатковая праця з кераваннем станамі і маршрутызацыяй не прыносіць нічога, калі на самай працэ не трэба прымкнуць жадных рашэнняў па маршрутызацыі. Вжывайце патэрн керуючага агента тады, калі у вас ёсць справжнія, адзінаковыя спецыялісты і рэальны выбор маршруту, а не прыменяйце яго як стандарт.

Падсумак

  • Адзін перанасытаны агент перастае эфектывна, калі складнасць зрастае.
  • Керуючы агент — гэта агент-маршрутызатор, які дэлегуе задачы спецыялістам.
  • create_supervisor — гэта шырока, ужо створаная маршрутная схема.
  • Пад час работы перадачы інформацыі адбываюцца як звычныя вызовы інструментаў.
  • Ручны StateGraph дае повны контроль над маршрутызацыяй.
  • Два урокі з практыкі: з самага пачатку разрабатывайце схему станоў і обмежывайце цыклы перазначэння.