Інженерія циклів: створення циклів агентів за допомогою верифікаторів та правил зупинки.
Практичний посібник зі створення чотирьох ієрархічних циклів агентів: основи ReAct, інструменти оцінювання за рубриками, механізми маршрутизації LangGraph, контракти циклу, тригери подій, алгоритми підйому по схилу та заходи запобігання збоям.
Мислення, що стоїть за всім цим, легко пояснити. Перестаньте керувати ШІ по одній інструкції та розробіть цикл, у якому воно працюватиме. Основна ідея полягає у тому, що саме верифікатор, а не модель, обмежує те, у що можна довіряти, а уява має бути спрямована на чотири вкладені один у одного цикли. Ось як це побудувати: елементи циклу, код для кожного шару, способи його збою та правила зупинки, які не дозволять йому споживати ваш бюджет. У кінцевому підсумку ви дізнаєтесь достатньо, щоб цикл готував запит про зміни під час вашого сну.
Приклади коду відповідають задокументованим API, ідентифікатори моделей є замінниками, а будь-який фрагмент, який є лише псевдокодом, позначений у коментарі. Протягом усього тексту наведений один приклад — звичайний початковий варіант у цій галузі: цикл програмування, який відтворює несправний тест, виправляє його, змушує хтось інший, крім самого агента, перевірити це виправлення та створює проект запиту про зміни.
П’ять складових циклу
Який би фреймворк ви не використовували, ефективний цикл завжди складається з п’яти елементів. Якщо пропустити один з них, цикл почне хитатися, зупинятися або тривати нескінченно.
- Тригер. Те, що запускає цикл – чи то повідомлення від користувача, запланований інтервал, webhook чи новий рядок у таблиці.
- Ціль, яку може перевірити машина. Фраза „Зробити тести успішними“ підходить, а „Покращити код“ – ні. Якщо програмне забезпечення не може визначити, чи досягнуто мети, цикл також не зможе цього зробити.
- Інструменти, які надають реальну інформацію. Агент мусить діяти у реальному світі та бачити результат, виконуючи код, читаючи stderr або викликаючи API.
- Оптимізований, керований стан. Зберігайте ціль, тимчасову пам’ять та записи про все, що вже було спробовано. Надмірний обсяг даних є причиною уповільнення циклу, його блукань та виходу за межі контекстного вікна.
Плануйте три варіанти виходу, а не два. Успіх: перевірка пройшла, тож можна продовжувати. Невдача: закінчився бюджет або ліміт ітерацій, тож потрібно зупинитися та підсумувати те, що залишилося. Передача: агент натрапив на рішення, яке має приймати лише людина, тож ситуація піднімається на вищий рівень. Частиною проектування хорошого ланцюга є визначення тих викликів, які він не повинен виконувати сам.
Ланцюг 1: ланцюг агента
У центрі знаходиться цикл, який вже використовують усі агенти — шаблон ReAct 2022: думати, діяти шляхом виклику інструменту, спостерігати за результатом та повторювати до завершення. У 2026 році він був спеціально спроєктований та більше не керується вручну. У своїй найпростішій формі це один виклик функції:
from langchain.agents import create_agent
def run_tests() -> str:
"""Run the project's test suite and return the raw output."""
…
agent = create_agent(
model="anthropic:claude-opus-5",
tools=[run_tests],
system_prompt="You are a careful Python engineer. Fix failing tests.",
)
# create_agent returns a graph that calls tools in a loop, repeating
# until the model replies with no tool calls. The loop runs on .invoke()
У цьому короткому фрагменті коду прихований цикл, і ви повинні мати змогу його уявити. Нижче наведена та сама структура керування у вигляді псевдокоду без будь-якої фреймворк-системи. Зауважте, що кожен вихід має обмеження:
# PSEUDOCODE - shows the control structure a harness implements.
# The helper names below are yours to supply, not a real library API.
def run_loop(goal):
state = init_state(goal) # goal + scratchpad + attempt log
for step in range(MAX_STEPS): # hard cap: never loop forever
thought = model.reason(state) # ReAct: reason…
action = model.choose_action(state) # …then pick a tool call
result = tools.execute(action) # touch the real environment
state = update(state, thought, action, result)
state = compact(state) # keep context under budget
if verifier.passes(state): # deterministic check = reward
return success(state)
if no_progress(state) or budget.exhausted():
return escalate_to_human(state) # third exit: hand-off
return escalate_to_human(state)
Серед усіх форм тут запам’ятайте саме цю. Решта є її удосконаленнями.
Цикл 2: додавання верифікатора
Простий агент сам вирішує, коли закінчити роботу, і саме довіра до цього призводить до хибного враження про успіх. Тому агента оточують механізми оцінювання, які перевіряють його роботу за певними критеріями. Якщо робота не відповідає стандартам, надсилається критика назад, і цикл продовжується до досягнення максимально допустимої кількості спроб. Механізм верифікації знаходиться у пакеті deepagents.
from deepagents import RubricMiddleware, create_deep_agent
from langchain.messages import HumanMessage
from langgraph.checkpoint.memory import InMemorySaver
RUBRIC = """
- All tests pass in run_tests
- No test is skipped or deleted to force a pass
"""
agent = create_deep_agent(
model="anthropic:claude-opus-5",
system_prompt="You are a careful Python engineer.",
middleware=[
RubricMiddleware(
model="anthropic:claude-haiku-4–5", # a cheap grader is fine
system_prompt="Grade against the rubric. Be strict.",
max_iterations=5, # the stop rule (default is 3)
),
],
checkpointer=InMemorySaver(),
)
# The rubric is passed at invoke time - not to the constructor.
result = agent.invoke(
{
"messages": [HumanMessage("Make the failing tests pass.")],
"rubric": RUBRIC,
},
config={"configurable": {"thread_id": "fix-tests-session"}},
)
Ось як це працює. Щоразу, коли агент майже закінчує роботу, окремий підагент-оцінювач читає транскрипт за допомогою критеріїв оцінювання. Рішення needs_revision повертає зворотний зв’язок у розмову у вигляді HumanMessage, і агент продовжує роботу. Єдині можливі результати — satisfied, failed, max_iterations_reached та grader_error, тому цикл закривається та завжди завершується. Якщо оцінювачу потрібно виконати власні перевірки, надайте йому інструменти у вигляді екземплярів BaseTool.
Існує два типи верифікаторів, і правильний вибір — це основа професіоналізму.
- Детерміністичні: виконують тести, перевіряють схему та підтверджують оцінку. Вони дешеві, швидкі та неможливо обдурити їх, тому спочатку варто скористатися саме ними.
Створіть граф
Коли завдання стає складнішим за просте, чіткий граф кращий за прихований цикл: вузли, ребра та місце прийняття рішення про зупинку є повністю видимими. Дослідницький агент може бути представлений трьома вузлами, причому кожне рішення про зупинку приймається маршрутизатором:
from typing import Literal, TypedDict
from pydantic import BaseModel, Field
from langgraph.graph import END, StateGraph
class ResearchState(TypedDict):
question: str
draft: str
verdict: str
feedback: str
iterations: int
class Verdict(BaseModel):
status: str = Field(description='"verified" or "needs_work"')
feedback: str = Field(description="claims lacking support, if any")
def decide(state: ResearchState) -> Literal["research", "__end__"]:
if state["verdict"] == "verified": # success exit
return "__end__"
if state["iterations"] >= MAX_ITERATIONS: # surrender exit
return "__end__"
return "research" # else: loop again with the feedback
builder = StateGraph(ResearchState)
builder.add_node("research", research_node) # generator
builder.add_node("verify", verify_node) # verifier
builder.add_edge("research", "verify")
builder.add_conditional_edges(
"verify", decide, {"research": "research", "__end__": END}
)
builder.set_entry_point("research")
graph = builder.compile()
У цьому коді немає жодних складних інструкцій. Розумність полягає у структурі: один вузол генерує дані, інший їх перевіряє, а маршрутизатор перетворює результат на подальшу спробу з зворотним зв’язком або на зупинку процесу. LangGraph розглядає сигнали __end__ та END як одне й те саме.
Контракт циклу
Саме тут зміна підходу стає конкретною. Замість написання інструкцій ви формулюєте специфікацію „завершення“, тобто функцію винагороди та правило зупинки. Саме цей документ ви переглядаєте, порівнюєте та комітуєте:
Мета: створити зелену схему CI на гілці payments-refactor. Це означає, що всі тести пройшли, і жоден з них не було проігноровано чи видалено для обману. Кроки: прочитати тест, який не пройшов, виправити ймовірну причину та запустити все знову. Правило щодо записів: вести журнал усіх спроб, щоб нічого не повторювалося. Процес зупиняється при отриманні статусу «зелений» шляхом створення проєкту PR, після шести спроб — шляхом узагальнення залишків завдань, або коли робота стосується логіки автентифікації чи оплат — шляхом передачі її іншій особі.
Жодної інструкції не надсилалося до моделі. Були записані лише мета, правила перевірки, правило щодо записів та три способи завершення роботи, і цей набір правил є основою для проектування циклів.
Цикли 3 та 4: поступове розширення
Вже один добре спроєктований цикл допомагає. Користь зростає, коли навколо нього створюються додаткові цикли, кожен з яких працює з меншою швидкістю. Цикли 1 та 2 виконують правильну роботу, а цикли 3 та 4 роблять її безперервною та самовдосконалюваною.
Цикл 3: події
Зовнішня подія перетворює ваш цикл з інструменту, який ви викликаєте, на сервіс, який працює самостійно. Це також природне місце для людського схвалення перед тим, як щось буде відправлено:
# Loop 3: an event turns the loop into a service
from pydantic import BaseModel
class CIEvent(BaseModel):
branch: str
@app.post("/webhook/ci-failed")
def on_ci_failure(event: CIEvent):
if not event.branch.startswith("fix/"): # cheap triage first
return {"skipped": True}
result = agent.invoke(
{
"messages": [HumanMessage(
f"Fix the failing test on {event.branch}.")],
"rubric": TEST_GREEN_RUBRIC,
},
config={"configurable": {"thread_id": event.branch}},
)
open_draft_pr(result) # a human approves the merge, not the loop
return {"opened_pr": True}
Цикл 4: підйом на пагорб
Найзовнішніший цикл є найповільнішим та працює безпосередньо над самим циклом. Кожен запуск залишає слід. Агент аналізу читає ці сліди, виявляє постійно повторювані проблеми та пропонує зміни до інструментарію: запиту, інструментів, критеріїв оцінки, які переглядають люди. Уявіть собі стрілку повернення – замість того, щоб повертатися лише на початок, вона проникає у внутрішній цикл та змінює його. Система покращує саму себе.
Одна застереження: зовнішні цикли множать все, що знаходиться всередині них. Додавайте їх лише тоді, коли внутрішній верифікатор є надійним, адже четвертий цикл навколо слабкого верифікатора лише автоматизує масштабоване створення некоректних даних.
Чому це вважається інженерією
Захисні механізми можуть здаватися зайвими формальностями. Вони вже не здаються такими, як тільки ви бачите агента як контролер з замкнутим циклом зворотного зв’язку — матрицю, яка відповідає точка за точкою. Ціллю є значення налаштування, агент виступає контролером, а інструменти та середовище складають об’єкт керування. Перевірник функціонує як датчик, а його вердикт „потрібна корекція“ є сигналом помилки, який запускає наступну корекцію. Завершена задача означає збіжність. Контролер керується різницею між значенням налаштування та показниками датчика, незалежно від того, чи є об’єктом керування реактивний двигун чи набір тестів.
Та сама лексика описує два способи припинення циклу. Він може коливатися, нескінченно повторюючи один і той самий крок, або відхилятися від мети під час поступової втрати ресурсів. Механізми контролю — це просто умови стабільності, які тримають його в межах, а найважливішим правилом є те, що система мусить гарантувати завершення, і агенту не можна довіряти це завдання.
День із усіма чотирма циклами
Подивіться, як чотири цикли працюють протягом ранку. О 09:14 зазнає невдачі тест payments-refactor, і запускається webhook — це цикл 3, причому ніхто нічого не вводить. Протягом наступних семи хвилин агент читає повідомлення про помилку, вносить корективи, запускає тест знову, читає нове повідомлення про помилку та знову вносить корективи, ведучи журнал спроб (цикл 1). Після кожного раунду детермінований оцінювач запускає весь набір тестів та перевіряє, що нічого не було пропущено для штучного отримання позитивного результату (цикл 2). Четвертий раунд завершується з позитивним результатом.
О 09:22 цикл завершується правильно – з проектом змін, який показує, що саме змінилося та чому. Його мусить схвалити людина, оскільки зміни стосуються оплат. Протягом ночі механізм виявлення проблем помічає, що це вже третя помилка з різницею часових поясів цього тижня, і створює нову перевірку за правилами, яка потрапляє на ваше розглядання (цикл 4). Завтрашній процес буде ефективнішим, ніж сьогоднішній.
Ви проспали більшу частину цього процесу. Вранці є проект змін та рішення, яке потрібно прийняти, але немає клавіатури для швидкого введення.
Коли цикли йдуть не так
Цикли посилюють сигнал, і це посилення відбувається у обох напрямках. Кожен спосіб збою впливає на цикл у певній точці та має стандартний захист; існує одна основна ідея, яка повторюється: те, що генерує сигнал, не повинно водночас оцінювати його якість. Найдешевший спосіб захисту — запустити верифікатор на вхідних даних, про які відомо, що вони коректні, та на даних, про які відомо, що вони некоректні, перш ніж залишати цикл без контролю. Переконайтеся, що він відхиляє некоректні дані, адже верифікатор без тестування є лише думкою, супроводжуваною певними припущеннями.
Коли не варто створювати цикл
Поспішне використання циклів для обробки всього є самостійним способом збою. У таких ситуаціях краще залишити все у вигляді одного виклику:
- Достатньо одного проходження, як у випадку зі стисненням даних, перекладом чи їх очищеною обробкою. Цикли лише збільшують витрати та затримки.
- Не можна перевірити жодну мету. Без способу перевірки статусу „завершено“ немає сигналу про помилку, що призводить до безкінечного використання ресурсів.
Інженерія ланцюгів означає не лише знання того, як їх створювати, а й розуміння того, які проблеми потребують використання ланцюгів.
Створюйте їх так, ніби збираєтесь залишатися на цій посаді
Ось інструменти: анатомія, ланцюг агентів, верифікатор, граф, контракт, зовнішні ланцюги та каталог помилок. Озбройте ланцюг потужним верифікатором, жорсткою зупинкою та обмеженнями, яких він не може перевищити. Додайте людські контрольні точки там, де ризики справжні, і пам’ятайте, що те, що ланцюг знаходить рішення, не означає, що ви його розумієте. Потім дозвольте йому працювати, як це робить той, хто планує залишатися інженером, а не просто людиною, яка його запускає.
Наступний рівень
Є одне питання, яке варто поставити перед тим, як залишити цикл без нагляду: наскільки слабким може бути верифікатор, щоб все одно показувати зелений статус? Для відповіді на це було створено показник ефективності. Він фіксує випадки маніпуляцій із нагородами та оцінює налаштування контрольних точок за кількістю маніпуляцій, які вони дозволяють пройти. Контрольна точка, яка ігнорує власний звіт агента та перезапускає набір тестів — це детерміністична перевірка, запропонована раніше як перший варіант — не зупинила жодної з восьми маніпуляцій. Перезапуск набору тестів лише підтверджує, що умови отримання нагороди були дотримані, і саме цього й досягається за допомогою маніпуляцій із нагородами.
Отже, якщо верифікатор обмежує систему, наступною необхідною навичкою є очевидна: проектування, версіонування та вдосконалення самих перевірок. Люди називають це інженерією оцінки — завданням встановлення стандартів, які має подолати кожен цикл. Один верифікатор працює в межах одного циклу. Інженерія оцінки охоплює багато таких циклів через набори даних та критерії оцінки, які показують, чи покращується система в цілому чи погіршується.
Зміцнення кожного етапу перевірки схоже на драбину, а її кінцева точка залишається непередбачуваною. Найкращою перевіркою виявляється зовсім не складний код, а лише кілька тверджень, які агент ніколи не мав можливості побачити. Тож обмеження у верифікації знаходиться в досить складному положенні. Воно залежить менше від якості побудови кожного етапу та більше від якості даних, які тримаються окремо, та від того, чи удається запобігти їхньому проникненню назад у цикл.