Что такое «turn» в reins? Изображение: сгенерировано ИИ

Каждый, кто поручал ИИ-агенту большую работу, знает это. Цикл рушится всегда в одной и той же точке: в момент, когда модель сама объявляет «я всё сделала» — хотя на деле работа не закончена.

reins — это фреймворк Quest CLI, который отбирает у ИИ право объявлять завершение и передаёт его машине. Он разбивает список работ на отдельные пункты, как квесты в игре, выдаёт их ИИ по одному, а «закончено ли?» решает не по слову ИИ, а машинной проверкой. И в его сердце лежит маленькая единица под названием turn.

Два слова будут повторяться постоянно, поэтому закрепим их сразу.

  • Gate — проверяющий, который механически инспектирует сдачу и выносит вердикт PASS или FAIL. Не впечатление человека и не самооценка ИИ.
  • Ratchet (храповик) — шестерня, вращающаяся только в одну сторону. Мы используем это слово в значении: пункт, запертый прохождением, больше никогда не открывается.

Эта статья проходит один turn от начала до конца — через всё, что с ним происходит. Turn выглядит маленьким, но в разобранном виде это reins в миниатюре.

Шесть ключевых элементов Reins Engineering

Сожмите инженерию, на которой стоит reins, в одну строку — получится так: инженерия переноса права объявлять завершение от ИИ к детерминированному машинному gate. «Детерминированный» здесь — не сложное слово. Оно означает, что один и тот же вход всегда даёт один и тот же результат. Тест либо проходит, либо падает, и вчерашний вердикт не отличается от сегодняшнего по настроению.

В родословной prompt engineering (выбор слов) → context engineering (подача контекста) → harness engineering (постройка ограды) Reins — это поводья, задающие направление. Эта инженерия собирается из шести элементов.

#ЭлементОдной строкойКаноническая фраза
1Машинный вердикт о завершенииУсловие завершения должно допускать машинный ответ yes/no, и судит машина — ИИ лишён права решать, что он закончил«Завершение выносит gate, а не заявляет модель»
2Детерминированная обратная связьФакты, а не мнения — «где, что должно быть, что было на самом деле» становится сигналом, указывающим на исправление«Дай мнение — будет льстить; дай факт — исправит»
3Направляющий контекст (мануал + примеры)Если обратная связь — сигнал коррекции, то мануал и примеры — сигнал направления; одно не заменяет другое«Узкое место — не интеллект, а контекст»
4Ratchet Pattern (контрактная блокировка)Прошедший пункт неизменяем; оставшаяся работа только сокращается — завершение гарантируется структуройremaining(t+1) ≤ remaining(t)
5Персистентность прогрессаПрогресс живёт вне процесса (на диске) — даже если ИИ умрёт, прогресс останется«Agents are disposable; progress is cumulative.»
6Защита от cheese (доменные gate)Даже машинная проверка обманывается, если смотрит лишь на оболочку — gate должен перепроверять реальные факты своего домена«У gate есть домен»

Ничего страшного, если термины из таблицы пока непривычны. Turn — это минимальная единица, где эти шесть сходятся внутри одного цикла, так что, пройдя один turn до конца, мы встретим все шесть элементов, каждый на своём месте. Набросаем карту заранее: compose, первый шаг turn, собирает направляющий контекст и детерминированную обратную связь; judge выносит машинный вердикт (защита от cheese — это качество проектирования этого gate); record запирает ratchet и персистирует прогресс.

Что такое Reins Turn?

Reins Turn — это минимальная единица исполнения в reins, в которой одна попытка над одним пунктом квеста завершается как генерация → вердикт → запись. Цикл — не что иное, как повторение turn’ов, а прогресс квеста — не что иное, как их накопление. Поэтому определение умещается в одну строку.

Turn N = N-я записанная Attempt. Что не записано, то не turn.

Attempt — это «одна запись об одной попытке». Здесь есть тонкий момент: turn — это не «LLM была вызвана один раз». Условие существования turn — не вызов, а запись. Если LLM вызвали, но результат так и не был записан в ratchet, этого turn не было. И наоборот: результат, сданный человеком вручную, будучи записанным, — это turn. Даже без LLM. Turn’ы считает не модель, а ratchet.

Это единственное определение — корень всех свойств, которые появятся дальше: независимости от драйвера, устойчивости к перезапуску, аудируемости. Пока пусть имена просто промелькнут. Мы встретим каждое снова на его законном месте.

Один turn — это ровно четыре шага

Turn проходит четыре шага по порядку. Шаги носят английские имена, но делают простые вещи — собрать (compose), сгенерировать (generate), рассудить (judge), записать (record).

ШагЧто делаетСвойство
① composeЧитает запись всех предыдущих turn’ов (Log) и собирает промпт для LLMЧистая функция
② generateВызывает LLM один раз и производит результатЕдинственный вероятностный шаг
③ judgeGate выносит вердикт по результату (PASS / REVIEW / FAIL)Детерминирован
④ recordПрименяет вердикт к ratchet и сохраняет на дискЕдинственный необратимый шаг

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

Стоит отметить одно необычное проектное решение. Этот четырёхшаговый каскад не реализован двумя комплектами Go-кода. Он определён в единственном человекочитаемом документе pkg/cli/turn.md (документе TANGEUL), встроенном в бинарник (go:embed) и интерпретируемом во время выполнения. Канонический источник того, «как крутится turn», — не код, а читаемый документ; причина этого выбора вернётся в конце статьи.

① compose — контекст приходит только из Log

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

Промпт, собираемый из Log, состоит из трёх слоёв.

  • Что делать — что должно быть произведено для этого пункта (инструкции по написанию и контекст верификации)
  • Мануал — глобальный системный промпт плюс, если предыдущий turn был FAIL, коучинг по правилу, которое его вызвало (мануал по правилам)
  • Хвост обратной связи — факты предыдущего FAIL. «Где, что должно быть, что было на самом деле»

На языке шести элементов выше: мануал — это направляющий контекст, а хвост обратной связи — детерминированная обратная связь. Оба механически собираются из Log на каждом turn’е.

Есть одно тонкое, но важное правило. Точкой отсчёта для compose служит не последняя Attempt, а последняя Attempt, доведённая до вердикта (judged). Даже если посередине вклинилась ошибка генерации вроде падения сервера LLM, повторная попытка видит не сообщение об инфраструктурной ошибке, а фактологическую обратную связь предыдущего FAIL. Эксплуатационные сбои не загрязняют контекст работы.

② generate — LLM только генерирует

Собранный промпт уходит в бэкенд LLM одним вызовом. Неважно, является ли бэкенд HTTP API (ollama/xai/gemini) или инструментом командной строки (claude/grok/codex/geminicli). В любом случае его роль фиксирована: генератор. Фреймворк не выставляет никакого API, через который LLM можно было бы наделить правом на PASS. Дело не в том, что фреймворк «решил не давать» право судить — его невозможно дать. Так элемент 1 из шести (машинный вердикт о завершении) становится структурой.

Даже выбор бэкенда пересчитывается из Log на каждом turn’е. Пункт, который продолжает падать на модели по умолчанию, отправляется наверх, к более сильной (эскалация), и это решение тоже каждый turn считывается из Log — «есть ли среди правил-причин прошлых FAIL цель эскалации?» Нет никакого где-то оставленного включённым переключателя, никакой локальной переменной внутри цикла. Та же программа, тот же Log — выбирается тот же бэкенд. Свойство вести себя идентично после того, как процесс убили и перезапустили, — устойчивость к перезапуску — достаётся бесплатно.

③ judge — судит только gate

Вердикт по результату выносит gate. Gate — это набор правил обнаружения нарушений. Каждое правило срабатывает (fire), когда находит проблему, за которую отвечает, и оставляет один факт — где (Where), что должно быть (Expected), что было на самом деле (Actual).

Агрегация детерминирована. Если сработало хотя бы одно правило Fail — FAIL. Иначе, если сработало правило Review, — REVIEW (серая зона для проверки человеком). Если не сработало ничего — PASS. Та же сдача, те же правила — всегда тот же вердикт. Здесь нет инспектора, чей ответ меняется каждый раз, когда его спрашивают.

В сложных доменах, где правила переплетаются — где одно нарушение делает другую проверку бессмысленной, — вердикт можно поднять на граф аргументации (toulmin), а саму логику суждения перенести в аудируемый документ (gate.md). Какой бы ни была форма, одно не меняется: судья — машина.

④ record — единственный необратимый шаг

Применить вердикт к ratchet, сохранить на диск и экспортировать завершившиеся пункты. Это единственная точка в turn’е, которую нельзя отменить.

  • PASS / REVIEW / SKIPPED / BLOCKED → блокировка. Ratchet односторонний; назад он не вращается.
  • FAIL → счётчик попыток (Tries) увеличивается на 1, и пункт остаётся TODO. По достижении максимума попыток (по умолчанию 3) он запирается как DONE. «Этот пункт так не решается» — тоже форма завершения; одному застрявшему пункту не позволено вечно держать в заложниках весь цикл.
  • Ошибка генерации → она записывается в Log как Attempt (след того, что произошло, сохраняется), но не расходует попытку. Падение сервера LLM — не вина пункта, а эксплуатационный сбой. Если сбой продолжается, отдельный предохранитель останавливает цикл (остановка после N последовательных сбоев генерации — circuit breaker).

Только с этим шагом появляется Log, который прочитает compose следующего turn’а. record — это завершение turn’а и порождающий следующего turn’а.

Провал — это факт, а не мнение

В каком виде возвращается FAIL — вот ключ к тому, чтобы turn сходился (с каждой повторной попыткой приближался к ответу). Не мнение вроде «качеству немного не хватает», а вот это:

FAIL. root cause = who-anchor-present
  Fact: where=who.anchors expected="source substring" actual="менеджер Иван Петров"

Читается просто. Какое поле (where), что должно быть (expected — строка, реально существующая в источнике), что было на самом деле (actual). Местоположение + ожидаемое значение + фактическое значение. Для LLM это обратная связь, в которой некому льстить — числа и координаты не эмоции. Именно этот структурированный факт ведёт льстивую модель не к спору, а к сходимости.

И ещё один бонус сверху. Текст FAIL, скармливаемый модели, — это в точности тот же рендеринг, что и строка, печатаемая на экран, когда человек запускает команду submit (feedback parity). Обратная связь, которую видит человек, и обратная связь, которую видит модель, никогда не расходятся. Загадки «что же такое отправили ИИ, что он исправил именно так?» структурно не существует.

Три точки входа, один turn

Назовём того, кто крутит turn, драйвером. В reins их три: next, где человек получает промпт напрямую; submit, где человек сдаёт результат; и безлюдный автоматический loop. Но это не три отдельные реализации. Это три точки входа в один и тот же документ turn’а. Ручной режим от автоматического отделяет ровно одно правило внутри документа.

Практическое свойство, которое это даёт: смените драйвер посреди квеста — и промпт останется байт в байт тем же. Вчера крутили автоматический loop, сегодня человек перехватил через next — при том же состоянии Log выходит тот же промпт. Это возможно потому, что контекст приходит только из Log (мы видели это на шаге ①), и это доказанное свойство, а не надежда — golden-тест смены драйвера (driver-swap golden test) верифицирует байтовую идентичность, сравнивая выходы между драйверами.

Проследим один turn от начала до конца

С теорией покончено. Посмотрим на один реальный turn от старта до финиша. Это один пункт квеста по извлечению адресов электронной почты из документов, вторая попытка после того, как предыдущий turn получил FAIL с «не является корректным форматом email».

[Проверка входа в turn]  Пункт — TODO? Попытки остались? → продолжаем
① compose      Находим в Log последнюю judged Attempt → FAIL, причина = email-format
               Мануал = глобальный промпт + коучинг правила email-format
               Промпт = что делать + "FAIL. Fact: where=email
                        expected='valid email format' actual='kim at example'"
② generate     Вызов LLM → {"email":"kim@example.com", ...}
③ judge        Обход правил: email-format проходит, source-lacks-email проходит, freemail проходит
               → ни одно правило Fail не сработало → PASS
④ record       Ratchet запирается (необратимо) → Attempt #2 записана → сохранено → export

Модель, получив факт предыдущего провала («kim at example — не корректный формат email»), исправила ровно это место; gate подтвердил прохождение; ratchet запер. Теперь этот пункт — PASS навсегда. Следующий turn его пропускает, и оставшаяся работа только сокращается. Когда каждый пункт достигает завершённого состояния (PASS, REVIEW или максимум попыток), цикл заканчивается. Не «когда ИИ почувствует, что закончил», а когда оставшихся пунктов станет ноль. Сходимость гарантирована структурой.

Loop Engineering — индустрия дала имя той же проблеме

В июне 2026-го сдвиг в обращении с агентами получил имя. Peter Steinberger написал: «You shouldn’t be prompting coding agents anymore. You should be designing loops that prompt your agents» (больше не промптуйте кодирующих агентов — проектируйте циклы, которые промптуют ваших агентов), а в начале того же месяца Boris Cherny из Anthropic, создатель Claude Code, сказал на одном мероприятии: «I don’t prompt Claude anymore. I have loops running… My job is to write loops» (я больше не промптую Claude. У меня крутятся циклы… Моя работа — писать циклы). Несколько дней спустя Addy Osmani из Google дал течению имя: Loop Engineering — от человека, который промптует агентов, к человеку, который проектирует системы, промптующие агентов.

Этот дискурс рисует единый нарратив перехода. Prompt engineering (выбор слов) → context engineering (выбор показываемой информации) → harness engineering (постройка среды исполнения) → loop engineering (проектирование самого цикла наблюдай-действуй-верифицируй-восстанавливайся). Рычаг сдвигался наружу слой за слоем: от слов к информации, от информации к среде, от среды к циклу.

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

Рекомендация Loop EngineeringСтруктуризация в turn’е reins
Экстернализуйте состояние на диск или доску (модель забывает)Log — не подпорка для памяти, а единственный вход turn’а — compose есть чистая функция от Log
Разделяйте строителя и верификатора (субагенты)Верификатор — не ещё одна LLM, а детерминированный gate — API для выдачи PASS не существует вовсе
Определяйте тестируемые условия завершенияМонотонность ratchet гарантирует сходимость как инвариант — структура, а не условие
Различайте восстановимые сбои и фатальныеВстроено в правила record — FAIL расходует попытку; ошибки генерации — епархия circuit breaker

Сердце различия — дистанция между рекомендацией и структурой. Сама литература по loop engineering признаёт иерархию верификации — LLM-as-judge, доверяющий вердикт ИИ, «can be gamed or can collude with the actor» (может быть обманут или вступить в сговор с исполнителем), поэтому везде, где возможна детерминированная проверка, ставьте детерминированную проверку. Но это остаётся лучшей практикой — рекомендацией, доверенной доброй воле проектировщика. Если субагент-верификатор в конечном счёте тоже LLM, дверь к сговору остаётся открытой. reins закрывает эту дверь дизайном. Судит только gate, и фреймворк не выставляет никакого способа выдать LLM право на PASS.

И там, где loop engineering говорит о цикле целиком, reins превращает один оборот этого цикла в контракт. Чтобы шагнуть на шаг дальше слов Cherny «моя работа — писать циклы», сначала должно быть определено, что цикл делает за один оборот — что вероятностно, что детерминировано, что необратимо. Имя этому определению — turn.

Почему именно эта единица

Затяните turn вот так — и получите три вещи. Имена, промелькнувшие раньше, находят здесь свои места.

  • Аудируемость — ответ на вопрос «чем автоматический loop отличается от ручного next?» — это не работа по сравнению двух кодовых баз, а одно правило в документе. Можно своими глазами убедиться, что путь, способный запереть PASS, в документе ровно один. Вот почему канонический источник turn’а — читаемый документ, а не код.
  • Устойчивость к перезапуску — каждый вход turn’а выводится из Log на диске, поэтому даже если процесс умрёт, тот же Log воспроизведёт тот же turn.
  • Одноразовость агентов — меняйте агентов (LLM, драйверы) — прогресс всё равно накапливается и никогда не откатывается. «Agents are disposable; progress is cumulative.»

Скажем наоборот: система, где turn размыт — где контекст прячется в памяти сессии, модель самообъявляет завершение, а повторные попытки опираются на историю разговора, — теряет все три.

Turn выглядит маленьким. Но как минимальная единица, разделяющая и сериализующая генерацию (вероятность), суждение (детерминизм) и запись (необратимость) внутри одного цикла, — понять turn значит понять весь reins.

Связанные статьи

Дополнительное чтение (внешнее)

Источники

  • Loop Engineering — Addy Osmani — 2026-06. Именование термина и анатомия хорошего цикла (автоматизация, worktree, скиллы, субагенты, отдельные арбитры, экстернализация состояния).
  • What Is Loop Engineering? A Complete Guide from Prompt to Harness Engineering — Tosea.ai — четырёхэтапный переход prompt→context→harness→loop, иерархия верификации с приоритетом детерминизма и риск сговора у LLM-as-judge.
  • Claude Code’s Creators Explain Agent Loops — The Neuron — Boris Cherny и Cat Wu подробно об эксплуатации циклов: /loop и /goal, экстернализация состояния на диск и в Linear, разделение строителей и верификаторов.

История изменений

  • 2026-07-07: Первая редакция