Главная / Статьи

Инженерия циклов для ИИ-агентов: пять составляющих, четыре формы и способ создания в LangGraph.

Инженерия циклов для ИИ-агентов: пять частей, четыре распространённых формата, исследовательский агент с функцией проверки и повторной попытки в LangGraph, защита от сбоев и критерии, когда не следует использовать циклы.

Издатель: REACTAPP.TOP15 мин чтения3382 слов

Источники: Loop Engineering with Agents

Каждый ИИ-агент уже работает в цикле, и почти никто специально не проектирует этот цикл. Именно эта разница отделяет агента, который тихо выполняет задачу, от того, который за одну ночь тратит всё бюджетное финансирование, будучи уверенным в своем прогрессе. Существует специальное направление, направленное на преодоление этой проблемы — инжиниринг циклов.

Структурно всё довольно просто. На каждом этапе агент размышляет о том, что делать, выполняет действие, такое как вызов инструмента или поиск, анализирует полученные результаты и снова размышляет. Этот цикл рассуждений, действий и наблюдений лежит в основе таких инструментов, как Claude Code и Cursor. Некоторое время самым востребованным навыком считался инжиниринг промптов — максимально точное формулирование запросов. Появление моделей, способных действовать, искать информацию и читать собственные результаты, породило более серьезный вопрос: что определяет следующее действие агента и что заставляет его остановиться?

Инженерия циклов — это привычка намеренно отвечать на поставленные вопросы. Дизайнер определяет цель, критерии проверки и точку остановки, затем создаёт компактную систему, которая один раз формулирует задачу и позволяет агенту продолжать итерации до завершения работы. Ответственность смещается от пошагового указания агенту действий к формированию решений, необходимых для выполнения этих указаний.

Это сильная идея, но именно здесь начинаются сложности. Некачественные циклы тратят ресурсы бесконечно, никогда не заканчиваются или убеждают себя в том, что они движутся вперёд. Хорошие циклы экономичны, останавливаются в подходящий момент и дают надёжный результат. Умнее сформулированный запрос не сокращает эту разницу; лучший цикл — да.

В приведённых ниже примерах используется LangGraph, поскольку он позволяет легко увидеть структуру цикла, но ничто здесь не связано с конкретной платформой. Те же принципы применимы и к другим фреймворкам агентов или к ручно написанному коду. Фреймворки меняются, но концепции остаются прежними.

Пять составляющих цикла агента

Прежде чем решить, когда цикл является целесообразным, полезно знать, из чего он состоит. Почти каждый цикл агента имеет пять составляющих.

  • Триггер. Некое событие запускает процесс, например, ввод слова «go» человеком, запуск планировщика, поступление тикета или открытие pull request. Без триггера агент находится в состоянии покоя.
  • Цель с возможностью проверки. Цикл должен знать, как выглядит завершение, желательно в форме, которую может подтвердить машина. Улучшение приложения приводит к бесконечной работе: необходимо пройти все тесты или вернуть ответ, в котором все утверждения сопровождаются источниками, обеспечивая настоящую «финишную черту».
  • Инструменты. Агент должен иметь возможность действовать и одновременно наблюдать за результатом — запускать код, читать ошибки, искать информацию в Интернете и анализировать результаты. Если среда никогда не отвечает, агент может только догадываться.
  • Состояние. Это текущая картина выполнения задачи: количество сделанных попыток, полученные результаты, сколько раундов уже пройдено. Это самая сложная часть проектирования циклов, поскольку чрезмерно большое количество данных о состоянии маскирует полезные сигналы под шум.
  • Правила остановки. Они определяют, как заканчивается цикл, и существует три варианта. Успех означает достижение цели. Сдача на месте означает исчерпание лимита попыток. Передача ответственности означает, что цикл столкнулся с чем-то рискованным или неясным, и вместо угадывания задача передаётся другому человеку.

Вся остальная часть обсуждения, касающаяся того, когда следует использовать цикл, когда — нет и как это делать, сводится к этим пяти принципам.

Когда цикл оправдан

Цикл становится необходимым, когда одного прохождения по модели недостаточно, и задача действительно требует от агента попыток, проверок и повторных попыток. На это указывают четыре сигнала.

  • Результаты можно проверить. Это имеет наибольшее значение. Когда исход можно автоматически проверить — по результатам тестов, наличию реальных источников в ответе, корректности JSON-данных, — цикл может использовать эту проверку для поиска правильного решения. Проверка выполняет роль руля управления, а цикл без неё лишь тратит средства.
  • Первая попытка часто бывает неверной, но её можно исправить. Код, черновики исследований и очистка неструктурированных данных улучшаются с каждым повторением. Агент создаёт что-то, замечает недостатки и их устраняет.
  • Никто не знает, сколько шагов потребуется. Проблема одного типа сегодня может требовать двух шагов, а завтра — семи. Фиксированная процедура не может адаптироваться таким образом, в то время как цикл, продолжающийся до достижения цели, может.
  • Никто не наблюдает. Обработка заявок в ночное время или повторные попытки работы с нестабильной интеграцией до её успешного запуска требуют системы, которая сама выбирает следующее действие и не ждёт указаний.
  • Хорошим примером является исследовательский агент, который проверяет собственные выводы. Он составляет ответ, проверяет, подтверждаются ли каждые утверждения источниками, и возвращается к тем слабым местам для дальнейшего анализа. Он продолжает этот цикл до тех пор, пока ответ не станет достаточно убедительным или не будет достигнут лимит. Все четыре сигнала присутствуют, и именно такой агент реализован далее.

    Типичные формы циклов

    Большинство агентных циклов представляют собой вариации нескольких основных форм. Их распознавание помогает определить, какую форму требует проблема, прежде чем что-либо соединять вместе.

    Генерация и проверка, иногда называемая отражением. На первом этапе создаётся результат, а на втором он анализируется, причём этот цикл повторяется до тех пор, пока проверка не пройдёт. Сигнал управления имеет бинарную форму: проверка либо одобряет результат, либо указывает на ошибки. Этот метод подходит для ситуаций, когда возможно проверить корректность, например для кода, который должен пройти тесты, или для исследований, утверждения которых требуют подтверждения. Именно такая структура формируется позже.

       +-----------+      +-----------+
    -->| Generate  |----->|  Verify   |----- pass -----> [ done ]
       +-----------+      +-----+-----+
            ^                   |
            +------- fail ------+
    

    Используйте этот подход, когда существует объективный тест на корректность, и агент должен продолжать вносить исправления до тех пор, пока тест не пройдёт. Классическим примером является агент для написания SQL-запросов, который выполняет свой запрос и продолжает циклиться, пока инструкция не будет выполнена и не вернёт разумные результаты.

    Оценщик и оптимизатор, также называемые генератором и счётчиком оценок. Счётчик оценок присваивает балл каждой попытке вместо простого «да» или «нет», а цикл направлен на достижение максимального балла, а не только на получение правильного результата. Этот подход полезен, когда нет чёткого критерия успешности или неудачи, но всё ещё можно оценить степень качества, например при настройке запросов, улучшении текстов рекламы или сортировке результатов.

       +-----------+      +-----------+
    -->| Generate  |----->|  Score    |--- good enough --> [ done ]
       +-----------+      +-----+-----+
            ^                   |
            +-- improve --------+
                (use the score)
    

    Выбирайте тот вариант, у которого качество можно оценить по шкале и при этом присвоить ему числовой показатель. Разработка слогана продукта с оценкой четкости и выразительности, а также последующая доработка лучшего варианта иллюстрируют эту идею.

    Планируйте, выполняйте, перепланируйте. Планировщик определяет этапы, а исполнители их выполняют; когда на каком-либо этапе возникают неожиданности, процесс возвращается к планировщику для его корректировки. Этот цикл охватывает весь план, а не только один результат, поэтому он подходит для работ с открытым исходом и множеством этапов, таких как исследования или разработка программного обеспечения.

       +-----------+      +-----------+
    -->|   Plan    |----->|  Execute  |-- all steps done --> [ done ]
       +-----------+      +-----+-----+
            ^                   |
            +-- replan ---------+
                (hit a surprise)
    

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

    Запланированный цикл или цикл мониторинга. Вместо поэтапного выполнения задачи в течение одной сессии этот вариант активируется по таймеру или при наступлении определенного события для наблюдения и реагирования, например, для сортировки новых заявок, поиска сбоев в сборке или повторной попытки выполнения ненадежной задачи. Он охватывает промежуток времени и не ограничивается одной задачей.

       +-----------+     +-----------+     +-----------+
    -->|   Wait    |---->|   Check   |---->|    Act    |---+
       | (timer /  |     +-----------+     +-----------+   |
       |  trigger) |                                       |
       +-----------+ <-------------------------------------+
            (no fixed end — keeps watching over time)
    

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

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

    Создание цикла с помощью LangGraph

    Агент, который создаётся, — это исследователь, который не доверяет своему первоначальному варианту ответа. При поступлении вопроса он собирает информацию, пишет ответ, а затем проверяет каждое утверждение на соответствие реальным источникам. Утверждения, не имеющие подтверждения, возвращаются для дальнейшего исследования. Цикл продолжается до тех пор, пока ответ не станет полностью достоверным, или пока не будет достигнут лимит попыток; в этом случае агент возвращает свою лучшую версию ответа и отмечает то, что всё ещё неясно. Короче говоря, он сначала отвечает, а затем убеждает себя в правильности ответа, прежде чем передать его.

    Такое поведение самопроверки и есть цикл генерации и верификации, благодаря которому формируется качественный первоначальный вариант ответа.

    LangGraph хорошо подходит для этой цели, поскольку описывает агента как граф. Узлы представляют собой элементы, выполняющие работу, а рёбра — стрелки, определяющие последующие действия. Рёбра могут указывать назад, что позволяет существование циклов. Простая линейная цепь не может повторяться, но граф может.

    У исследователя три задачи, следовательно, три узла. Первые два разделяют работу между создателем и проверщиком, исполнителем и критиком, что является распространённой схемой в циклах.

                        +------------------+
      START ----------> |     Research     | <-------------+
                        | (draft / revise) |               |
                        +--------+---------+               |
                                 |                         |
                                 v                         | needs work
                        +------------------+               | (+ feedback)
                        |      Verify      |               |
                        |  (check claims)  |               |
                        +--------+---------+               |
                                 |                         |
                                 v                         |
                           +-----------+   needs work      |
                           |  Decide   |-------------------+
                           | (router)  |
                           +-----+-----+
                                 | verified / out of tries
                                 v
                              [ END ]
    
    1. Исследование — сбор материалов и подготовка проекта ответа.
    2. Проверка — анализ проекта и проверка того, подтверждены ли все утверждения.
    3. Решение — небольшой маршрутизатор, который читает вердикт и определяет дальнейшие действия: завершить работу или вернуться и изучить слабые места.

    Пример работает под Python 3.12. Требуются три пакета:

    pip install langgraph==1.2.6 langchain-openai==1.3.3 pydantic==2.13.4
    
    • langgraph — это движок графов и циклов, включающий StateGraph, START и END.
    • langchain-openai оборачивает чат-модель OpenAI в объект ChatOpenAI.
    • pydantic определяет структурированный результат, который возвращает проверщик.

    Прежде чем запустить программу, в среде также должен находиться ключ API OpenAI:

    export OPENAI_API_KEY="your-key-here"
    
    from typing import TypedDict, Literal
    from langgraph.graph import StateGraph, START, END
    from langchain_openai import ChatOpenAI
    from pydantic import BaseModel, Field
    
    # A model client on OpenAI's Responses API, with the built-in web-search tool
    # bound on — so the model can search the web itself, no extra package needed.
    # "gpt-5" is a reasoning model; swap it for any current model you have access to.
    llm = ChatOpenAI(model="gpt-5", use_responses_api=True)
    searcher = llm.bind_tools([{"type": "web_search"}])
    
    MAX_ITERATIONS = 3         # a stop rule, decided up front
    
    # STATE — the shared memory passed between every node
    class ResearchState(TypedDict):
        question: str          # what we're answering
        draft: str             # the current best answer
        verdict: str           # "verified" or "needs_work"
        feedback: str          # what the verifier said to fix
        iterations: int        # how many times we've looped
    
    # The verifier returns a typed result, so the router gets a clean
    # "verified" / "needs_work" to branch on instead of parsing prose.
    class Verdict(BaseModel):
        status: str = Field(description='"verified" or "needs_work"')
        feedback: str = Field(description="claims lacking support, if any")
    
    # NODE 1 — the maker: search the web, then draft (or revise) the answer.
    def research(state: ResearchState) -> dict:
        prompt = "Search the web, then answer the question. Back every claim with a source.\n"
        if state.get("feedback"):
            prompt += f"A reviewer flagged these gaps — fix them:\n{state['feedback']}\n"
        prompt += f"\nQuestion: {state['question']}"
        draft = searcher.invoke(prompt).text
        return {"draft": draft, "iterations": state["iterations"] + 1}
    
    # NODE 2 — the checker: search for evidence, then critique the draft.
    def verify(state: ResearchState) -> dict:
        evidence = searcher.invoke(
            f"Search the web for evidence to fact-check claims about: {state['question']}"
        ).text
        checker = llm.with_structured_output(Verdict)
        result = checker.invoke(
            "You are a fact-checker. Using the evidence below, reply 'verified' "
            "only if every claim in the answer is supported; otherwise 'needs_work' "
            "and list the unsupported claims as feedback.\n\n"
            f"Evidence:\n{evidence}\n\nAnswer:\n{state['draft']}"
        )
        return {"verdict": result.status, "feedback": result.feedback}
    
    # ROUTER — the heart of the loop. Reads the verdict, picks the next step.
    def decide(state: ResearchState) -> Literal["research", "__end__"]:
        if state["verdict"] == "verified":
            return "__end__"                      # success: goal met
        if state["iterations"] >= MAX_ITERATIONS:
            return "__end__"                      # surrender: out of tries
        return "research"                         # loop back and fix the gaps
    
    # WIRE IT UP
    graph = StateGraph(ResearchState)
    graph.add_node("research", research)
    graph.add_node("verify", verify)
    
    graph.add_edge(START, "research")            # trigger
    graph.add_edge("research", "verify")         # always verify a fresh draft
    graph.add_conditional_edges("verify", decide, {
        "research": "research",                   # the backward arrow = the loop
        "__end__": END,
    })
    
    agent = graph.compile()
    
    result = agent.invoke({
        "question": "What were the main causes of the 2008 financial crisis?",
        "draft": "", "verdict": "", "feedback": "", "iterations": 0,
    })
    print(result["draft"])
    

    Выделяются два важных момента. Во-первых, оба узла подключаются к интернету с помощью встроенного инструмента OpenAI web_search, добавленного с использованием bind_tools. Узел research выполняет поиск перед составлением текста, чтобы его утверждения основывались на реальных результатах. Узел verify снова выполняет поиск, чтобы проверить черновик на основе свежих данных, а не на основе памяти модели, и именно этот второй поиск предоставляет целевой сигнал для дальнейшей обработки. Во-вторых, узел verify использует функцию with_structured_output, которая обязывает формировать структурированный результат в виде типизированного verdict и feedback вместо простого текста, что позволяет маршрутизатору надежно разветвлять работу без необходимости парсинга свободного текста.

    Пять компонентов цикла однозначно соответствуют элементам кода:

    • Триггер: вызов функции invoke(...) с вопросом запускает процесс.
    • Цель для проверки: правила verify должны иметь статус verified или needs_work.
    • Инструменты: оба узла используют встроенный поиск в интернете, функцию research для написания текста и функцию verify для его проверки.
    • Состояние: словарь ResearchState отвечает за перемещение черновика, отзывов и количества итераций между узлами.
    • Правила остановки: маршрутизатор decide прекращает работу при успешном завершении или при достижении значения MAX_ITERATIONS.

    Последний пункт имеет решающее значение, поскольку именно в маршрутизаторе реализуется логика циклов. Одна строка — «остановиться при проверке», «остановиться после трех попыток», в противном случае — вернуться назад — позволяет отличить агента, который надежно улучшает свой ответ, от того, который бесконечно тратит ресурсы.

    В примере предусмотрены два варианта завершения. В реальных циклах обработки часто добавляется третий вариант — передача задачи человеку. Столкнувшись с рискованной или неоднозначной ситуацией, агенту лучше не делать догадок и не просто замолчать, а остановиться и передать всю собранную информацию для дальнейшей обработки. В маршрутизаторе это просто ещё один ветвление: когда уровень уверенности низок или действие чувствительно, маршрут escalate прерывает цикл и показывает черновик, оставшиеся вопросы и предпринятые попытки. Умение определить, когда не стоит принимать решение, является частью хорошего проектирования циклов.

    Возможные сбои и средства их предотвращения

    Как только цикл начинает работать автономно, появляется небольшой список предсказуемых сбоев, для каждого из которых существует стандартный механизм защиты.

    • Бесконечный цикл. Агент никогда не считает, что выполнил свою задачу, и продолжает действовать до тех пор, пока что-то не сломается или деньги не исчезнут. Ограничение количества итераций представляет собой жесткий лимит, такой как MAX_ITERATIONS выше, — способ выхода, который не зависит от собственного мнения агента.
    • Сжигание токенов. С каждой итерацией пересылается всё больший объем контекста, и затраты растут незаметно. Чтобы снизить нагрузку на память, сохраняйте только то, что необходимо для следующего шага: текущую версию работы и конкретные замечания, но никогда полную историю действий.
    • Воображаемый прогресс. Агент заявляет о успехе, которого на самом деле не достиг, например, утверждает, что проблема решена, хотя этого никогда не происходило. Не позволяйте ему оценивать собственную работу по критериям, имеющим реальное значение. Отдельный шаг проверки с объективным тестом, тестами, которые действительно выполняются, или источниками, которые действительно существуют, гарантирует, что завершенное действительно считается завершенным.
  • Повторение одной и той же ошибки. Цикл снова и снова выполняет ту же неудачную операцию и сталкивается с тем же сбоем. Необходимо передавать информацию о предыдущей ошибке в следующую попытку, чтобы изменить подход; именно поэтому функция research получает feedback от верификатора.
  • Действия без отчетности. При длительных запусках становится сложно понять, что произошло и почему. Необходимо фиксировать каждый шаг: что видел агент, какие решения принимал и что делал. Наблюдаемость перестает быть опциональной, как только цикл воздействует на что-то важное, и существуют такие инструменты, как LangSmith, для отслеживания таких запусков.
  • Полная автономия с самого начала. Цикл, действующий без надзора с первого дня, еще не заслужил доверия. Необходимо постепенно вводить автономию: сначала режим только с отчетами, в котором указывается, что агент собирается сделать, затем варианты изменений с участием человека, утверждающего их, и, наконец, работа без участия человека; каждый этап должен быть завершен до перехода к следующему.
  • Когда не стоит использовать цикл

    Циклы — мощный инструмент, поэтому их легко применять чрезмерно. В таких ситуациях лучше использовать что-то проще.

    • Достаточно одного прохождения. Краткое изложение документа, перевод текста, ответ на фактический вопрос и классификация электронного письма — это задачи, которые можно выполнить за один раз. Использование цикла только увеличивает затраты, задержки и риски сбоев. Если подходит простая последовательность действий, используйте её.
    • Успех невозможно определить. Когда цель субъективна или нечетка, или её может оценить только человек, у цикла нет ориентира, поэтому он может закончиться произвольно или бесконечно продолжаться. Цель, которую невозможно проверить, делает алгоритм игровым автоматом, а не циклом.
  • Ошибки могут привести к большим затратам или к постоянным последствиям. Цикл, который при каждой итерации отправляет электронные письма, переводит деньги или удаляет данные, может быстро нанести серьезный ущерб. Держите человека в процессе утверждения или не используйте цикл для выполнения последующих действий.
  • Скорость и затраты имеют приоритет над автономией. Каждая итерация означает дополнительные вызовы, ресурсы и время. В функциях с высоким объемом работы, низкой прибылью или чувствительными к задержкам предсказуемый одиночный вызов часто лучше, чем изощренный, но дорогой цикл.
  • Ориентир: если условия успеха и условия прекращения работы невозможно сформулировать письменно, цикл еще не готов к реализации.

    Чек-лист перед использованием цикла

    Инженерия циклов изменяет способ получения результата. Написание безупречного запроса имеет меньшее значение, чем проектирование системы, которая управляет агентом, то есть его триггером, целью, инструментами, состоянием и правилами остановки. Тем не менее цикл — это лишь один из инструментов, а не стандартное решение. Сначала стоит задать пять вопросов:

    1. Можно ли автоматически проверить успех? Если нет, пропустите цикл, поскольку у него не будет ориентира для управления.
    2. Улучшается ли задача при повторении? Если достаточно одной попытки, держите всё простым.
    3. Что именно означает завершение работы? Запишите условие успеха до начала программирования.
    4. Когда он должен остановиться? Установите строгий лимит, чтобы цикл не мог работать бесконечно.
    5. Могут ли действия безопасно повторяться? Если итерация может причинить реальный ущерб, добавьте человеческий контрольный пункт или не используйте цикл на этом этапе.

    Если на все пять вопросов дать честные ответы, результатом может стать надежный цикл, а не просто красивая видимость. Лучше всего подходит скромный первый проект: один этап исследования и проверки, описанный выше, при этом правила остановки должны быть четко определены еще до того, как что-либо начнет развиваться.

    Последний момент: цикл делает не только то, что ускоряет работу. Он усиливает любые решения, принятые при его создании, повторяя как хорошие, так и плохие решения с скоростью машины. Следовательно, цель не в том, чтобы создать цикл и забыть о нем. Необходимо сохранять достаточно близкий контроль, чтобы понимать, что делает цикл после того, как он начнет работать самостоятельно, чтобы его создатель оставался его инженером, а не просто человеком, нажавшим кнопку запуска.

    Связанная литература

    • Harness, Loop and Graph: Three Nested Layers of a Coding-Agent System — Симптомы сбоя указывают на слой, который необходимо исправить. Как взаимодействуют элементы harness, loop и graph, где полезен многопроцессный подход, чего не могут гарантировать адверсарные проверки, и чек-лист для диагностики.
    • Loop Engineering: Four Nested Loops for Self-Improving AI Agents — Как четыре вложенных контрольных цикла (ReAct, retry, queue, hill climbing) вместе с механизмом оценки, индикатором бюджета и проверкой на изменения делают агента надежным, на примере процесса оценки страховых случаев.
  • Практические заметки: Уязвимость sys.exit(0): как ИИ-агенты имитируют успех — Пошаговое руководство по использованию Практических заметок: Уязвимость sys.exit(0): как ИИ-агенты имитируют успех, включающее шаблоны контрактов, проверок и готовые фрагменты кода для команд, внедряющих эту практику.
  • Практические заметки: Создание платформы ИИ с множеством агентов — Часть 5: Восприятие — Пошаговое руководство по использованию Практических заметок: Создание платформы ИИ с множеством агентов — Часть 5: Восприятие, включающее шаблоны контрактов, проверок и готовые фрагменты кода для команд, внедряющих эту практику.
  • Практические заметки: Инженерия цикла агентов: полный блог о переходе от разработки к внедрению ИИ в производство — Подробное руководство по использованию Практических заметок: Инженерия цикла агентов: полный блог о переходе от разработки к внедрению ИИ в производство: контракты, проверки и готовые блоки кода для команд, внедряющих эту модель.