Вы когда-нибудь писали промпт, который работал идеально ровно один раз? А потом модель «забывала» контекст, начинала галлюцинировать или просто зависала в бесконечном цикле «думания»? Я — да, и не раз. Ручной промптинг — это как игра в угадайку с LLM: вы подбираете слова, меняете температуру, добавляете примеры, но система всё равно остаётся хрупкой.
Loop engineering — это подход, который превращает одноразовые промпты в самоподдерживающиеся циклы. Вместо того чтобы каждый раз вручную корректировать запрос, вы строите инфраструктуру вокруг LLM, которая автоматически управляет контекстом, выбирает инструменты, проверяет результаты и возвращается к планированию, если что-то пошло не так.
Методологию популяризировали Anthropic (внутренние исследования по ReAct-агентам) и Addy Osmani (инженер из Google, который собрал пять базовых примитивов для loop engineering). В этой статье я покажу, как собрать такую систему из пяти кирпичиков, и сравню два главных инструмента для её воплощения — Claude Code и Codex.
💡 Если вы только знакомитесь с архитектурой AI-агентов, советую сначала прочитать нашу статью «Production AI агент: разбор промптов Anthropic, context engineering и чек-лист из 13 пунктов» — там заложена база для понимания loop engineering.
Проблема: почему ручной промптинг не масштабируется
Представьте, что вы пишете агента для обработки техподдержки. Пользователь пишет: «У меня не работает вход в панель администратора». Агент должен:
- Проверить статус сервера (API вызов)
- Найти последние логи (поиск по файлам)
- Сбросить сессию пользователя (ещё один API)
- Ответить пользователю
В single-shot подходе вы кладёте все инструкции в один гигантский system prompt. И вот что происходит:
- Потеря контекста — модель «забывает» первые шаги к концу диалога.
- Галлюцинации — LLM придумывает, что API вернул ошибку, хотя на самом деле всё ок.
- Отсутствие повторных попыток — если первый вызов упал с timeout, агент не знает, что делать.
Я сам долго бился с этим, пока не наткнулся на концепцию loop engineering. Она переворачивает игру: вы перестаёте надеяться на «магию» промпта и строите железобетонный цикл, который гарантирует стабильность.
Что такое Loop Engineering? (и при чём тут ReAct)
Loop engineering — это инженерная дисциплина, которая описывает, как спроектировать самоподдерживающийся цикл вокруг LLM. В отличие от ReAct (Reasoning + Acting), который предлагает только базовый паттерн «думай → действуй → наблюдай», loop engineering добавляет:
- Управление памятью (что помнить, а что выбросить)
- Планирование шагов (декомпозиция задачи)
- Валидацию результатов (проверка, что ответ корректен)
- Механизмы восстановления после ошибок
Это как раз то, о чём мы говорили в статье «Agent Loop: почему ваш корпоративный AI-агент не доживет до второго тикета» — там я разбирал, почему single tool call убивает надёжность. Loop engineering даёт вам набор готовых блоков, чтобы этого избежать.
Пять базовых блоков (по методологии Anthropic и Addy Osmani)
Эти пять примитивов — не догма, а каркас. Вы можете расширять их, но основа остаётся неизменной. Я буду показывать примеры на Python — вы сможете адаптировать под любой фреймворк.
Вместо статичного промпта вы собираете его из кусочков: текущая задача, история диалога, доступные инструменты. Пример:
def build_primer(task: str, tools: list[str], memory: str) -> str:
return f"""Ты — инженер поддержки. Доступны инструменты: {', '.join(tools)}.
История: {memory}
Задача: {task}
Твой план действий:"""Звучит банально? А теперь представьте, что вы динамически подключаете только те инструменты, которые нужны для текущего запроса — это резко снижает количество галлюцинаций.
LLM сама не должна решать, какой инструмент вызвать — это делает оркестратор. Он проверяет, доступен ли инструмент, не превышен ли лимит вызовов, и форматирует ответ для модели.
class ToolOrchestrator:
def __init__(self):
self.tools = {
"search_logs": self.search_logs,
"reset_session": self.reset_session
}
def call(self, tool_name: str, params: dict):
if tool_name not in self.tools:
return {"error": f"Tool {tool_name} not found"}
return self.tools[tool_name](**params)LLM имеют жесткий лимит контекста (например, 200k токенов у Claude 4). Context Window Manager автоматически обрезает старые сообщения, сохраняя только ключевые факты. Реализация:
class ContextWindow:
MAX_TOKENS = 100000
def __init__(self):
self.messages = []
self.total_tokens = 0
def add(self, message: str, tokens: int):
while self.total_tokens + tokens > self.MAX_TOKENS and self.messages:
removed = self.messages.pop(0)
self.total_tokens -= removed['tokens']
self.messages.append({'content': message, 'tokens': tokens})
self.total_tokens += tokensLLM иногда выдают невалидный JSON или пропускают обязательные поля. Валидатор перехватывает такие ответы и просит модель исправить, прежде чем передать дальше. Пример:
def validate_json(output: str) -> dict | None:
try:
data = json.loads(output)
if 'action' not in data:
return None
return data
except json.JSONDecodeError:
return NoneСамый частый баг — агент зацикливается: вызывает один и тот же инструмент, получает ту же ошибку, снова вызывает. Iteration Guard ставит жёсткий лимит шагов и вводит backoff при повторяющихся ошибках.
class IterationGuard:
def __init__(self, max_steps=10):
self.max_steps = max_steps
self.step = 0
def can_continue(self) -> bool:
return self.step < self.max_steps
def increment(self):
self.step += 1Собираем всё вместе: простой loop-агент
Давайте склеим эти блоки в работающий пример. Агент будет обрабатывать запросы техподдержки, вызывать инструменты и собирать ответ.
class LoopAgent:
def __init__(self, model_client):
self.primer = PromptPrimer()
self.orchestrator = ToolOrchestrator()
self.context = ContextWindow()
self.validator = OutputValidator()
self.guard = IterationGuard(max_steps=5)
self.client = model_client
def run(self, user_input: str):
self.context.add(user_input, count_tokens(user_input))
while self.guard.can_continue():
prompt = self.primer.build(
task=user_input,
tools=list(self.orchestrator.tools.keys()),
memory=self.context.get_summary()
)
response = self.client.complete(prompt)
validated = self.validator.validate(response)
if not validated:
self.context.add("Ответ невалиден, повтори", 10)
self.guard.increment()
continue
result = self.orchestrator.call(**validated)
self.context.add(str(result), count_tokens(str(result)))
if self.is_final(result):
return result
self.guard.increment()
return {"error": "Max steps reached"}Обратите внимание: мы не надеемся, что модель сама догадается перезапросить инструмент — это делает цикл. Валидатор не даёт проскочить мусору. Iteration Guard обрезает бесконечные попытки.
Сравнение инструментов: Claude Code vs Codex (2026)
К середине 2026 года два главных инструмента для loop engineering — Claude Code (от Anthropic) и Codex (от OpenAI) — обросли функционалом, который напрямую реализует описанные примитивы. Вот как они соотносятся:
| Примитив | Claude Code | Codex |
|---|---|---|
| Prompt Primer | Автоматическое формирование system prompt под задачу; поддерживает MCP (Model Context Protocol) | Динамические шаблоны через Codex CLI; контекстные плагины |
| Tool Orchestrator | Встроенный планировщик инструментов; поддержка MCP-серверов | Оркестратор через Codex Agent SDK; вызовы функций |
| Context Window Manager | Автоматическая ротация контекста (до 200K токенов); «эпизодическая память» | Управление контекстом через ChatML; ручная настройка лимитов |
| Output Validator | Встроенная валидация JSON и схем; повторные запросы при ошибке | Кастомные валидаторы через Python-код |
| Iteration Guard | Жёсткий лимит шагов (настраивается); backoff при повторных ошибках | Максимальное число вызовов; fallback-сценарии |
Мой личный опыт: Claude Code на 25 июня 2026 года ощущается более «готовым» для loop engineering — он уже содержит все примитивы «из коробки», особенно за счёт MCP. Codex же требует больше ручного кодирования, но даёт гибкость. Если вам нужно быстрое прототипирование — берите Claude Code. Если вы строите кастомную платформу — Codex.
⚠️ Важно: Не путайте loop engineering с простым чейнингом промптов. Разница — в наличии обратной связи: loop engineering обязательно включает проверку результата и возможность повторного планирования. Без этого вы получите дорогой, но всё ещё хрупкий пайплайн.
5 типичных ошибок при внедрении loop engineering
За полгода работы с такими системами я набил кучу шишек. Вот что реально болит:
- Слишком большой primer. Если вы кладёте в system prompt всё подряд, модель начинает игнорировать половину. Правило: primer должен помещаться в один экран (не больше 2000 токенов).
- Отсутствие таймаутов. LLM иногда «зависает» на генерации. Без таймаута агент может ждать ответа минутами. Ставьте timeout на каждый вызов — 30 секунд максимум.
- Игнорирование конкуренции за контекст. Когда у вас несколько агентов, каждый со своим Context Window Manager, они могут «перезаписать» друг другу память. Используйте изолированные сессии — как worktree в git.
- Валидация без повторных попыток. Просто выкинуть невалидный ответ — плохо. Лучше вернуть модели сообщение «Твой ответ не прошёл проверку: ожидался JSON с полями action и params. Исправь.» и дать ещё 2-3 шанса.
- Забывчивость Iteration Guard. Если guard не сохраняет состояние между вызовами, агент может входить в один и тот же цикл снова и снова. Сделайте guard персистентным — запишите счётчик в базу или файл.
Как НЕ надо делать: пример антипаттерна
Вот код, который я видел в продакшене одного стартапа (и он работал ровно до первого сбоя):
# Антипаттерн: всё в одном промпте без цикла
def agent(user_input):
prompt = f"Выполни задачу: {user_input}. Доступны инструменты: check_server, get_logs, reset_session. Используй по одному."
response = llm.complete(prompt)
# надеемся, что ответ содержит нужные вызовы
return responseПроблемы: нет проверки, что ответ корректен; нет повторных попыток; нет управления контекстом. Если LLM ошибётся, агент просто вернёт мусор. Сравните с нашим циклом выше — разница колоссальная.
Будущее loop engineering: от циклов к оркестрации агентов
Loop engineering — это фундамент. Следующий шаг — агентные оркестраторы, которые управляют несколькими loop-агентами, каждый со своей специализацией. По сути, это суб-агенты, объединённые в иерархию. Уже сейчас Anthropic экспериментирует с multi-agent loop системами, а MCP позволяет разным агентам обмениваться инструментами и памятью.
Мой прогноз: к концу 2026 года стандартный корпоративный AI-агент будет собираться из 5-10 таких блоков, как из конструктора. Loop engineering станет таким же обязательным навыком, как умение писать Dockerfile или настраивать CI/CD. Если вы хотите оставаться в профессии — осваивайте эти примитивы уже сейчас.