Агент — гэта цыкл while: дзе месца create_agent з LangChain і LangGraph
Агент з выклікам інструментаў у дваццаці радках, чатыры прадакшн-праблемы, у якія ўпіраецца цыкл, і калі пераходзіць ад create_agent у LangChain да графаў стану LangGraph.
Крыніцы: An Agent Is a While Loop
Іспытанне інструментаў прывлекае вялікую увагу, але тыя элементы, якія вырашаюць, калі вызваць інструмент, што робіць з рэзультатам і калі завершыць работу, — гэта цыкл, які абгортае модэль. Людзі называюць гэты цыкл оркестрацыяй, аднак гэта слова дае вражанне, што ўсё горазда больша, чым ёсць на самай працэ. Найпростэйшы спосаб разумець гэта — спачатку паглядзець на весь працэс, а потым выявіць, чаму ён недастатковы для практычнага вікорыстання.
Цэлы агент у апошніх двадцяці рэчыцах
Возьмім працэс вызову інструмента: модэль прасіць аб інструме, ваш код яго выкананы, а рэзультат вяртаецца да модэлі, і абгорнем усё гэта while-цыклам. Спачатку ініціюецца дыялог:
messages = [system_prompt, user_question]
Tад сама петлі:
while True:
reply = model(messages, tools=TOOLS) if not reply.tool_calls:
return reply.text # the model answered; done for call in reply.tool_calls:
result = TOOLS[call.name](**call.args) # your code runs it
messages.append(tool_result(call.id, result))
Гэта справжній агент, а не мульцяшны персонаж. Мадэль выбірае, які інструмент запускаць. Ваш код ўвядзе яго і дадае рэзультат. Гэта повтарываецца, пакуль мадэль не вернёў тэкст у замяну запіта на інструмент.
Калі вам здаецца, што гэта трохі разчараваюча — адтуды і гэтая рэакція. Усё, што запрошвае фрэймворк, — гэта тое, што вы дадаеце пасля таго, як гэты цыкл будзе працаваць у рэжыме продакшну.
Одна выплата, крок за крокам
Уявіце агента для трыажу, якому запытаюць, чаму сінхронізацыя з перавазчыкамі за ночь не вядома з памятакай ERR_4412 пасля выпуску у грудзі. Ён знаходзіць адказ за тры раунд-трыпы, у рамках аднаго цыклу без фрэймворку.
Першы крок. Мадэль яшчэ не адпавядае. Яна выдае запыт search_runbooks("ERR_4412"), і цыкл яго выкананае. Працуе тры рэзультаты, і першы з яных паведамляе, што адказ на адзінак означае заканчылася тэкст канфігурацыі перавазчыка. Гэта дадаецца да прамов.
2-й крок. Пасля прачытання гэтага мадэль запрашоўвае get_release_notes("december"). Вяртаецца адна дасяглівка: інтэрвал паўнасці токена быў скорачаны з 24 гадзін да 12. Дасяглівка зноў дадаецца.
3-й крок. Хранячы оба рэзультаты, мадэль адпавядае у звычайным тэксце без запрашэння якога-лібо інструмента. Сінхронізацыі, якія выкананыю ноччу, трываюць больш чым дванаццац гадзін, таму токен цяпер выгорае ў серэдзіне такой сінхронізацыі. Калі няма запрашэння да выканання, цыкл завершаецца.
Мадэль выбрала інструменты, і цыкл выканаў іх. Спіс паведамленняў падросла на два рэзультаты, і больш нічога не адбылася.
Што ламаецца пасля тыдня ўпрацоўкі
У працэсе выкарыстоўвання часта з’яўляюцца чатыры проблемы, зазвычай у такой парады. Жадна з іх не стосуецца самай мадэлі. Усе стосуюцца срэдавыня выканання, якая ёй адпаведае.
Пачатак занова. На другім кроцы працы сістэма застрэлілася праз повольную працу, і пасля восьмі хвілін кантэйнер павінен быць перэроблены. Адколькі messages зберагаліся толькі ў памяці, яны знікаюць, і праца пачынаецца занова з самага початку. Рашэннем являецца зберэжэння ходу размовы пасля кожнага кроку і продовжэння працы з гэтага зберэжэння.
Апасны інструмент. У іншую ноч, на чэтвёртым кроцы, мадэль вырашае, што правым рашэннем ёсць rollback_release("dec-2025"). Дазволіць модэлі робіць гэта самай у 3 гадзіны ночы — гэта тое, чаго ніхто не хоча. Люп павінен зупініцца, запытаць чалавека, чакаць, можа, аж да ранку, а потым продовжыць працу там, дзе ён зупініўся. Просты while люп не можа чакаць да ранку.
Неправыя рашынкі. На 5-м кроце выбіраецца некаліткі запіт на пошук, а з 6-го па 16-й крокі гэты пошук павтараецца з незначнымі зменамі формулювання, пры чым кожны такі крок плаціцца. Адзірванне на спісе з 16 паведамленняў не пакажае, дзе была памылка. Калі-то дапамагае ліміт колькасці крокаў і запіс следа кожнага крока, які можна перэглядзець занова.
Куды ісці. Памылкі аўтэнтыфікацыі вымагаюць адзінай последовасці крокаў, а памылкі дадзэнняях — іншай; калі два інструменты не пагоджуюцца, справу трэба перадаць чалавеку. Мадэль добра справляецца з выборам інструмента, але не должна імпровізаваць з логікай керування ў кожны раз. Галузі логікі должны быць запісаны, ўбеджаючыся, што яны дзейнаюць аднакова ў кожны раз.
Паглядзіце знову на этыя чатыры элемента. Ніхто не каляе за гэта хутраго чыста модэлю чыраўгу. Усе гэта вынікае з асупрашчанага коду — тыя даныя, якія ён зберагае, калі зупіняецца, якія логі-запісы стварае і хто выбірае шлях. Оркестрацыя — гэта самэйшы асупрашчаны слой, таму цікл з двадцаты ліній можа быць абсалютна правым, але ўсё раве заставацься месца, якое трэба пераканаць.
Ператворыце крокі на рамкі
Знову накрэсліце той жа працэс, пры чым кожны крок будзе выражаны рамкай, з’ѐеднанай стрэлкамі: класыфікацыя, пошук інструкцый, апранаванне прыказаў пасля выласці, запрошэнне пра варыянт выправлення, затверджэнне, а пасля — прыменэнне чыраўгі чыста адпаведна. Калі крокі выражаны рамкамі, з’яўляюцца тры новыя можлівасці.
- Кожная рамка завершаецца запісам стану ў надзвычайна надзейны сховішча, таму пасля перачынкі працэс продовжваецца з апошней завершанай рамкі, а не з пачатку.
- Будзь-якая рамка можа павернуць увесь працэс і чакаць на аднособу столькі, скількі патрэбна, пры чым стан захаваецца безпечна.
Разгалужэння знаходзіцца ў полі класыфікацыі, якое включае шлях аўтэнтыфікацыі, шлях дадзеных і процедуру паднятня проблемы. Вы накрэслілі гэтыя тры стрэлкі. Мадэль все ўсё выбірае інструменты внутрь шляху, але сам шлях належыць вам.
Мадэль не змянілася. Цыкл атрымаў форму, яую можна бачыць, зберагчыць і перарваць.
Што такое LangChain
LangChain — гэта бібліятэка на Python, з адпаведнай версіяй на JavaScript, якая прадае готовыя элементы для застосоўкаў на базе LLM, каб не пісаць адно і тое ж занова ў кожны раз. Важныя тры відэры элементаў.
Кэшаванеры модэляў. Адна інтарфейсная прамоць для разных прадаўцаў. ChatAnthropic, ChatOpenAI і ChatGoogleGenerativeAI усе выканаюць той самы метод .invoke(messages), таму змена прадаўця адбываецца простым выправленнем адзіной лініі коду, а не перапісвам усяго коду запытку.
Інтэграціі. Адаптары для элементаў, якія абрамляюць модэль: хранальнікі вектараў, чытальнікі дакументаў, прыстроі выкарыстоўвання дакументаў, модэлі укладання і калькі соткаў зовнішніх інструментаў. Самэ ў гэтым і крыецца большая частка заўсёды збераганай працы, адтак кожны адаптар іншым чынам заставіўся бы напісаным і падтрымвамым вам.
Цікл агента ў пакеце. З версіі 1.0 у жаўтні 2025 года основным механізам являецца create_agent, які імпортуецца так:
from langchain.agents import create_agent
і выкарыстоўваецца так:
agent = create_agent(
model="anthropic:claude-sonnet-4-6",
tools=[search_runbooks, get_release_notes],
system_prompt="You are the on-call triage assistant.",
)
result = agent.invoke({"messages": [("user", "Why is ERR_4412 failing?")]})
Фактычысь, цікл з ранейшага коду ўжо напісаны. Падтрымваны таксама медыя-роўеры: маленькіе хукі, якія запускаюцца пад час вызову мадэлі або інструменту. Існуючыя варыянты дазволяюць здзейсніць паузу на падтверджэння чалавеком першым запуск інструменту, відфільтраваць персональныя даны і скорачваць довгія розмовы.
Што не включае create_agent, — цэлая структура керування внутрасцю ціклу: без перагляду стану між крокамі, без дзеновай паузы, і як толькі працэс зламаецца, ўсё зупініцца.
Што такое LangGraph
Пад create_agent знаходзіцца LangGraph — іншая бібліятэка вадавальніка. LangChain дае готовы цікл, тады як LangGraph надае елементы для стварэння власнага ціклу, які будзе відпавадаць паказанай вышэй структуры. Вы візначаеце тры рэчы.
Стан. Об’ект, створанный за дапамою клавіатуры, які пераходзіць праз праграму. Для сортавання ён мае на сваім вебе ранейшыя поведамленні, класыфікацыю адзінакоў, запропанаваныя способы выправлення і інфармацыю пра тое, чыі ён быў затверджаны.
Вузлы. Звычныя функціі Python, якія прымоўляюць стан і вяртаюць абнаўленні. classify, search_runbooks, propose_fix і ask_human — гэта проста функціі.
Рэшткі. Парадак выканання. Звычныя рэшткі — гэта фіксаваныя стрэлкі, а умовныя рэшткі — функціі, якія чытаюць стан і выбіраюць наступны вузел, таму ў іх выражаецца разлік межы аўтэнтыфікацыі і дадзенняў.
Імпорт:
from langgraph.graph import StateGraph
І граф, створаны з тых элементаў:
g = StateGraph(TriageState)
g.add_node("classify", classify)
g.add_node("search", search_runbooks)
g.add_node("propose", propose_fix)
g.add_node("approve", ask_human)
g.add_edge("classify", "search")
g.add_conditional_edges("search", route_by_error_type)
g.add_edge("propose", "approve")app = g.compile(checkpointer=PostgresSaver(...))
Адзін рэчык пад канцы ліста несе важар: checkpointer, тое ўзначае месца для зберагчыць стан, якое пасылаецца пад час кампілявання графа. За яго дапамою стан запісваецца пасля кожнага вузла. Возможнасць перазапуску, interrupt() для чакання на певную персону, а таксама вярнення да вузла для павторнага адграфавання всіх дзеянь — усё гэта выходзіць з таго ж аргумента, а не з рукапіснага коду. Вашы вклад — гэта рамкі і стрэлкі.
Такім чынам, контраст такі: LangChain дае цыкл, які немагчыма побачыць знутра. LangGraph прасіць вас самых накрэсліць гэты цыкл, а ў замяну вы можэце яго пераглядаць, зберагчыць, зупініць і павторна адграфаваць. Чатыры вышэўказаныя проблемы — гэта чатыры моменты, калі немагчымасць побачыць, што відбываецца знутра, становіцца непрыемным.
Адна стак, два дзверы
Паколькі create_agent паблікуецца на базе графа LangGraph, выбор между LangChain і LangGraph не ўскладнюецца пытанням выбору фрэймворку. Гэта пытанне пра тое, якія «дзверы» выкарыстоўваць, і гэтыя два рашэння сумішуюцца. Агент, створаны за дапамою create_agent, сам ёсць графам, тое значыць, яго можна размясціць як адзін вузол у большым StateGraph. Большы граф абавярае класыфікацыю, затверджэння і сохраненне даных, тады калі агент усерэдзіні абавярае тыя часткі, дзе мадэль павінна прыміць рашэнне.
Выкарыстоўваюце create_agent, калі сёньня трэба агент, які можа працаваць, і не мае значэння, якія ў яго ўсерэдзіні элементы. Багато агентаў ніколі не патрабуюць чагосьць больш. Пераходзіце да StateGraph, калі неабходна адразу паглядзець на стан працы, чакаць на людзіну, вярнуцца пасля збою або перазапусціць працэс — гэтыя таксама чатыры проблемы, якія былі пераказаны раней.
SDK-яўцы ад Anthropic і OpenAI знаходзяцца па боку этага стака, а не ўнутры яго. Яны запускаюць той самы цыкл, прычастны аднай сямейцы модэляў, і працуюць без дапамогі дадатковых зусіль, калі вы выберазеце аднаго ўпрэднікаваўца. Цена за гэта — можлівасць перанесення.
Парады для каманды
Спачатку напісце двадзяцячлёвы цыкл, нават калі ён будзе відкінут. На гэта пайдзе гадзіна, а пасля стане ясна, што самэў кожны фрэймворк робіць за вас, і гэта ўсё, што можна зробіць для дыбаггінгу.
Перэйдзіце на LangGraph тады, калі першая з тых чатырох проблем справаўна выйдзе, і не раней. Чат-бот, які выкарыстоўвае тры інструменты для адпаведзення, можа обходзіцца без графа. Агент, які павінен працаваць пасля перзапуску, чакаць на затверджэнне або быць перэграўным, не можа гэтага зробіць, а стварэнне стойкай екзекуцыі з нуля — гэта сама по сабе праект.
Команды частаў адразу з выкарыстоўванням графа прабуюць рашыць задачу, яку можна спрацаваць за дапамогою простага цыклу, а пасля вітрачаюць час на выучэнне фрэймворку, хоць гэты час мог бы быць выкорыстаны на саму задачу.