Агент — це цикл While: де LangChain create_agent та LangGraph Fit
Агент для виклику інструментів у двадцяти рядках, чотири проблеми обробки даних під час циклу та коли переходити від LangChain create_agent до LangGraph state graphs.
Джерела: An Agent Is a While Loop
Використання інструментів привертає багато уваги, але та частина, яка визначає, коли викликати інструмент, що робити з результатом та коли припинити, — це цикл навколо моделі. Люди називають цей цикл оркестрацією, що робить його звучання більш значущим, ніж воно є насправді. Найпростіший спосіб це побачити — спочатку розглянути всю структуру, а потім з’ясувати, чому вона недостатня для практичного використання.
Цілий агент приблизно у двадцяти рядках
Візьмемо процес виклику інструменту, де модель запитує про інструмент, ваш код його виконує, а результат повертається до моделі, та обгорнемо цей процес while-циклом. Спочатку ініціюється діалог:
messages = [system_prompt, user_question]
А тепер сам цикл:
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-й кроки цей пошук повторюється з незначними змінами формулювань, причому кожен такий крок оплачується. Споглядання списку з шістнадцятьма повідомленнями не покаже, де виникла помилка. Допомагає обмеження кількості кроків та записування кожного кроку, який можна переглянути знову.
Яким шляхом рухатися. Для помилок автентифікації потрібна одна послідовність кроків, а для помилок даних — інша, і коли два інструменти не погоджуються, справу слід передати людині. Модель добре справляється з вибором інструменту, але не повинна щоразу імпровізувати з логікою керування. Гілки алгоритму слід записувати, щоб вони завжди діяли однаково.
Подивіться ще раз на ці чотири етапи. Ніхто не звинувачує якийсь „розумний“ чи „незграбний“ модель – усе пояснюється навколишнім кодом: що він зберігає, коли зупиняється, що фіксує та хто обирає шлях виконання. Оркестрація – це саме той навколишній шар, через який цикл з двадцяти рядків може бути абсолютно правильним, але все одно потребувати вдосконалення.
Перетворіть кроки на блоки
Намалюйте той самий процес знову, де кожен крок буде представлений у вигляді блока, з’єднаного стрілками: класифікація, пошук інструкцій, отримання приміток до версії, запропонування виправлення, схвалення, а потім застосування чи відповідь. Коли кроки є блоками, з’являються три нові можливості.
- Кожен блок завершується збереженням стану у надійному сховищі, тож після перезапуску процес продовжується з останнього завершеного блока, а не з початку.
- Будь-який блок може призупинити весь процес та чекати на людину стільки, скільки потрібно, при цьому стан безпечно зберігається.
Розгалуження знаходяться у клітинці класифікації: там є шлях автентифікації, шлях обробки даних та процедура ескалації. Ви намалювали ці три стрілки. Модель все ще обирає інструменти в межах певного шляху, але сам шлях належить вам.
Сама модель не змінилась. Цикл набув форми, яку можна побачити, зберегти та перервати.
Що таке 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 у той день, коли почнуть виникати перші з цих чотирьох проблем, і не раніше. Чат-бот, який використовує три інструменти для отримання відповідей, може обійтися без графу. Агент, який має працювати після перезапуску, чекати на схвалення або відтворюватися, — не може, і створення надійної системи виконання з нуля є окремим проектом.
Команди часто відразу починають використовувати графіки для розв’язання проблем, які можна вирішити за допомогою простих циклів, а потім витрачають час на вивчення фреймворку, хоча цей час мав би піти на саме розв’язання проблеми.