Amiga
Оглавление курса · урок 12 из 24

Модуль 3 · Датчики и ограничения · урок 12 из 24

Петли обратной связи

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

Направляющие и датчики

Самая полезная на сегодня классификация — у Биргитты Бёкелер в статье Harness engineering for coding agent users. Агент в ней — это модель плюс обвязка (harness), а внешняя обвязка, которую строит команда, преследует две цели: повысить шанс верного результата с первой попытки и поймать как можно больше проблем до того, как код увидит человек.

Инструменты делятся по двум осям.

Когда действуют. Направляющие (guides, feedforward) работают до действия: соглашения в AGENTS.md, навыки, инструкции по запуску. Датчики (sensors, feedback) — после: тесты, линтеры, ревью. Одни направляющие дают правила, которые никто не проверяет. Одни датчики заставляют агента повторять одни и те же ошибки и чинить их по факту.

Как устроены. Детерминированные (computational) — тесты, типы, линтеры, структурный анализ: быстрые, дешёвые, надёжные. Вероятностные (inferential) — ревью агентом, LLM в роли судьи: медленнее и дороже, зато понимают смысл.

Детерминированные Вероятностные
Направляющие шаблоны и генераторы кода, codemod-рецепты AGENTS.md, навыки, примеры в docs/
Датчики PHPUnit, PHPStan, структурные тесты, Playwright /review, отдельный агент-ревьюер, оценщик по чек-листу

Примеры в таблице — наши, для PHP-проекта агентства; у Бёкелер примеры другие, но сетка та же. Полезное упражнение — разложить по этой таблице всё, что уже есть в вашем репозитории. Обычно выясняется, что левый нижний угол заполнен, а левый верхний пуст: генераторов, которые сразу делают правильный каркас компонента, почти ни у кого нет.

Петли разной скорости

Бёкелер формулирует принцип «keep quality left»: дешёвые проверки — как можно раньше, дорогие — позже, плюс непрерывные датчики вне жизненного цикла изменения. Для агентного проекта получается пять уровней:

  1. Внутри хода — хук после каждой правки файла: форматер, линтер изменённого файла. Секунды.
  2. Перед завершением хода — быстрые тесты затронутого модуля. Десятки секунд.
  3. Перед коммитом или пушем — pre-commit/pre-push хуки Git. В статье упоминается практика Stripe: pre-push хуки запускают релевантные линтеры по эвристике.
  4. В CI — полный набор: backend-тесты, сборка фронта, e2e на Playwright, затем дорогие проверки вроде мутационного тестирования.
  5. Непрерывно — мёртвый код, дрейф зависимостей, качество покрытия, SLO. Это тема урока об энтропии.

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

Внутриходовая петля в Codex

С мая 2026 хуки в Codex вышли из беты; общее устройство — в уроке о хуках. Для петли обратной связи важны два события.

PostToolUse срабатывает после вызова инструмента. Если обработчик вернёт "decision": "block" с полем reason, Codex заменит результат инструмента этим текстом — правка уже применена, но агент сразу видит, что с ней не так. Правки файлов ловятся матчером apply_patch|Edit|Write.

Stop срабатывает, когда агент собирается закончить ход. Ответ "decision": "block" с reason не отклоняет ход, а создаёт новое продолжение с этим текстом в качестве промпта. Поле stop_hook_active во входных данных показывает, что ход уже продлевался, — по нему защищаются от бесконечного цикла.

json · .codex/hooks.json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "apply_patch|Edit|Write",
        "hooks": [
          { "type": "command", "command": "python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/lint_changed.py\"", "timeout": 60 }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          { "type": "command", "command": "python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/fast_tests.py\"", "timeout": 300 }
        ]
      }
    ]
  }
}
python · .codex/hooks/fast_tests.py
import json
import subprocess
import sys

event = json.load(sys.stdin)
if event.get("stop_hook_active"):
    sys.exit(0)  # уже продлевали ход: не зацикливаемся, остальное поймает CI

# Хук запускается в рабочей папке сессии, а она может быть вложенной
root = subprocess.run(
    ["git", "rev-parse", "--show-toplevel"], capture_output=True, text=True
).stdout.strip()
changed = subprocess.run(
    ["git", "diff", "--name-only", "HEAD"], capture_output=True, text=True, cwd=root
).stdout.split()
if not any(path.endswith(".php") for path in changed):
    sys.exit(0)

run = subprocess.run(
    ["vendor/bin/phpunit", "--testsuite", "fast", "--no-progress"],
    capture_output=True, text=True, cwd=root,
)
if run.returncode != 0:
    tail = "\n".join(run.stdout.strip().splitlines()[-40:])
    print(json.dumps({
        "decision": "block",
        "reason": "Быстрые тесты упали. Исправьте код, не меняя тесты, и прогоните "
                  "vendor/bin/phpunit --testsuite fast ещё раз.\n" + tail,
    }))

Команды хуков выполняются в рабочей папке сессии, поэтому пути строятся от корня git, как советует документация. Хуки из проектного .codex/ работают только в доверенных проектах и только после того, как вы подтвердили их через /hooks; доверие привязано к содержимому определения. Формат полей проверяйте по документации хуков — он ещё меняется.

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

Противодавление и рулевая петля

Хантли называет механические проверки противодавлением (backpressure): тесты, типы и статический анализ должны отвергать плохой вывод так быстро, чтобы «колесо крутилось». Для языков без строгой типизации он советует обязательно подключать статический анализатор — для PHP это PHPStan или Psalm на максимальном уровне, который выдерживает проект.

Над петлями агента есть ещё одна — человеческая. Бёкелер называет её рулевой (steering loop): если проблема повторяется, команда усиливает направляющую или датчик, чтобы она стала маловероятной или невозможной. У OpenAI та же мысль звучит как вопрос, который инженер задаёт при каждом провале: какой возможности не хватает агенту и как сделать её понятной и обязательной. Цепочка повторяется: замечание в ревью → правило в AGENTS.md → проверка в коде, когда текста оказалось мало.

Вероятностные датчики

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

В Codex это /review — он запускает отдельного ревьюера, который не меняет рабочее дерево, — или свой субагент с инструкцией «только читать и искать ошибки». Механическое — линт, форматирование — документация советует оставить CI, а ревьюеру дать 2–3 правила с последствиями и безопасным путём.

Открытые вопросы

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

Попробуйте сами

10–15 мин на рабочем месте
  1. Нарисуйте таблицу 2×2 из урока для своего репозитория и впишите всё, что есть. Отметьте пустую клетку, которую дешевле всего заполнить.
  2. Добавьте в проект PostToolUse-хук, который запускает линтер только по изменённому файлу и возвращает decision: block с инструкцией. Подтвердите его через /hooks и дайте агенту задачу, где он почти наверняка нарушит правило.
  3. Замерьте, сколько времени проходит от правки до сигнала об ошибке на каждом из пяти уровней в вашем проекте. Самый медленный полезный сигнал — первый кандидат на перенос влево.

Коротко

  • Направляющие действуют до шага агента, датчики — после; нужны и те и другие.
  • Детерминированные проверки дешёвые и надёжные, вероятностные понимают смысл — у каждых своё место.
  • Чем раньше сигнал, тем дешевле исправление: хук через секунды лучше CI через двадцать минут.
  • В Codex внутриходовая петля строится на хуках PostToolUse и Stop с decision: block и защитой от зацикливания.
  • Повторяющаяся проблема — повод усилить направляющую или датчик, а не поправить результат вручную.
Отметка хранится только в вашем браузере
Хотите связаться с владельцем
компании напрямую?
Дмитрий Тарасов
Дмитрий Тарасов
СЕО

НАПИСАТЬ

Написать в MAX