Files
prompts.chat/src/content/book/ru/14a-loop-engineering.mdx
T
Fatih Kadir Akın f9bfb652f5 loop engineering
2026-07-17 12:30:58 +03:00

406 lines
34 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Контекстная инженерия определяет, **что видит модель**. Инженерия циклов определяет, **что система сделает дальше**.
Вместо того чтобы человек раз за разом читал ответ и писал следующий промпт, цикл превращает эту доводку в спроектированную систему. Она ставит перед AI цель, даёт ему действовать, наблюдает за реальной обратной связью, оценивает результат и либо адаптируется, либо останавливается.
<Callout type="info" title="Короткое определение">
Инженерия циклов — это практика проектирования цикла обратной связи вокруг AI-системы: цели, действий, наблюдений, оценки, состояния, защитных ограничений и правил остановки, которые ведут работу к проверяемому результату.
</Callout>
## От хорошего промпта к хорошему циклу
Промпт может дать сильную первую попытку. Цикл нужен, когда число шагов заранее неизвестно, среда может меняться или первую попытку нужно сверить с доказательствами.
<Compare
before={{
label: "Одиночный промпт",
content: "Спросить → Сгенерировать → Вернуть\n\nМодель выдаёт ответ. Человек решает, сработало ли, и пишет следующий промпт."
}}
after={{
label: "Спроектированный цикл",
content: "Постановка → Действие → Наблюдение → Оценка → Адаптация\n ↑______________________↓\n\nСистема собирает доказательства, фиксирует состояние и продолжает работу, только пока очередной проход приносит пользу."
}}
/>
Эта идея опирается на более ранние агентные паттерны. [Статья о ReAct](https://arxiv.org/abs/2210.03629) показала ценность чередования действий с наблюдениями из внешней среды. [Паттерн «оценщик-оптимизатор»](https://www.anthropic.com/engineering/building-effective-agents) от Anthropic добавляет отдельный шаг обратной связи, а [практическое руководство по созданию агентов](https://openai.com/business/guides-and-resources/a-practical-guide-to-building-ai-agents/) от OpenAI описывает работу агента как цикл, управляемый условиями выхода. Более новый термин — **инженерия циклов** — сосредотачивает внимание на осознанном проектировании всего этого цикла.
## Пять ходов
<InfoGrid items={[
{ label: "1. Постановка", description: "Превратите замысел в цель, ограничения, критерии успеха и бюджет.", color: "blue" },
{ label: "2. Действие", description: "Выберите одно ограниченное действие: поиск, правка, вычисление, вызов инструмента или вопрос человеку.", color: "amber" },
{ label: "3. Наблюдение", description: "Соберите то, что произошло на самом деле: вывод тестов, ответы API, ссылки на источники или отзывы пользователей.", color: "cyan" },
{ label: "4. Оценка", description: "Сравните доказательства с явными критериями — а не с уверенностью модели.", color: "purple" },
{ label: "5. Адаптация", description: "Обновите состояние, скорректируйте план, безопасно повторите попытку, передайте задачу человеку или остановитесь.", color: "green" },
]} />
Цикл — это не стрелки. Инженерия живёт в **контрактах между стрелками**: что считается действием, каким наблюдениям можно доверять, кто их оценивает, какое состояние сохраняется и в какой именно момент выполнение заканчивается.
<LoopEngineeringLab content={{
eyebrow: "Управление циклом / интерактивный симулятор",
title: "Пройдите рабочий цикл обратной связи по шагам",
description: "Выберите задачу и продвигайтесь по одному сигналу за раз. Обратите внимание: прогресс складывается из доказательств внешней среды и явной оценки — а не из вопросов к модели, считает ли она работу завершённой.",
chooseScenarioLabel: "Выберите цикл",
goalLabel: "Цель",
stopRuleLabel: "Правило остановки",
evidenceLabel: "Доверенные доказательства",
iterationLabel: "Итерация",
progressLabel: "Подтверждённый прогресс",
openIssuesLabel: "Открытые проблемы",
currentSignalLabel: "Текущий сигнал",
advanceLabel: "Продвинуться на шаг",
nextIterationLabel: "Начать следующую итерацию",
resetLabel: "Сбросить цикл",
completeLabel: "Цель подтверждена",
completeDescription: "Критерии успеха выполнены, доказательства зафиксированы, и цикл останавливается вместо того, чтобы тратить ещё одну итерацию.",
stages: [
{ id: "frame", label: "Постановка", verb: "Перечитать контракт" },
{ id: "act", label: "Действие", verb: "Сделать один ограниченный ход" },
{ id: "observe", label: "Наблюдение", verb: "Прочитать внешнюю обратную связь" },
{ id: "evaluate", label: "Оценка", verb: "Применить рубрику" },
{ id: "adapt", label: "Адаптация", verb: "Скорректировать следующий ход" },
],
scenarios: [
{
id: "code",
label: "Починить баг в оформлении заказа",
goal: "Исправить итоговые суммы заказа, не изменив корректное поведение скидок.",
stopRule: "Целевой регрессионный тест проходит, весь набор тестов оформления заказа проходит, линтер не выдаёт замечаний — либо три попытки исчерпаны, и цикл передаёт задачу человеку.",
evidence: "Шаги воспроизведения, вывод тестов, дифф кода и финальный прогон регрессионных тестов.",
cycles: [
{
action: "Воспроизвести сумму из баг-репорта и добавить падающий тест для налога в сочетании с процентной скидкой.",
observation: "Тест падает с расхождением в один цент только тогда, когда налог округляется до применения скидки.",
evaluation: "Баг воспроизведён с детерминированным сигналом, но его источник ещё не устранён.",
adaptation: "Изучить границу округления и менять только путь расчёта итоговой суммы заказа.",
progress: 34,
openIssues: 2,
},
{
action: "Перенести округление на финальную денежную границу и запустить целевые тесты оформления заказа.",
observation: "Регрессионный тест проходит, но один интеграционный тест купонов теперь падает на скидке с фиксированной суммой.",
evaluation: "Первый симптом устранён, но правка слишком широкая. Правило остановки не выполнено.",
adaptation: "Сузить патч и добавить кейс, разделяющий округление налога и округление купона.",
progress: 71,
openIssues: 1,
},
{
action: "Применить точечное исправление расчёта, затем запустить регрессионный тест, весь набор тестов оформления заказа и линтер.",
observation: "Все проверки проходят. Дифф затрагивает одну расчётную функцию и новый регрессионный тест.",
evaluation: "У каждого критерия успеха есть независимое подтверждение, и ни один лимит бюджета не превышен.",
adaptation: "Остановиться, сохранить вывод тестов и передать компактный дифф на ревью человеку.",
progress: 100,
openIssues: 0,
},
],
},
{
id: "research",
label: "Проверить утверждение из исследований",
goal: "Оценить утверждение, что удалённая работа всегда повышает продуктивность команды.",
stopRule: "Взвешенный вывод подкреплён минимум тремя заслуживающими доверия источниками, а разногласия и ограничения явно указаны.",
evidence: "Прямые ссылки на источники, даты публикаций, методы исследований, размеры выборок и цитируемые показатели.",
cycles: [
{
action: "Найти свежие данные и проследить самую растиражированную статистику продуктивности до её первоисточника.",
observation: "Большинство статей повторяют опрос одного вендора, не давая ссылок на его анкету и исходную выборку.",
evaluation: "Эти данные популярны, но недостаточно сильны, чтобы подтвердить абсолютное утверждение.",
adaptation: "Отдать приоритет рецензируемым исследованиям и открытым датасетам; искать в том числе противоположные результаты.",
progress: 28,
openIssues: 3,
},
{
action: "Сравнить два рецензируемых исследования с национальным датасетом по рынку труда.",
observation: "Результаты зависят от типа задач, метода измерения и того, идёт ли речь о полностью удалённой или гибридной работе.",
evaluation: "Данные противоречат слову «всегда». Условный вывод становится обоснованным.",
adaptation: "Проверить, различают ли исследования объём результатов, отработанные часы и субъективно воспринимаемую продуктивность.",
progress: 68,
openIssues: 1,
},
{
action: "Составить таблицу доказательств и сверить каждое утверждение с первоисточником.",
observation: "Источники говорят о смешанных эффектах и выделяют автономию, координацию и тип задач как ключевые переменные.",
evaluation: "Вывод подтверждён, неопределённость показана, порог по числу источников достигнут.",
adaptation: "Остановиться на выводе с оговорками и сохранить таблицу доказательств для проверки.",
progress: 100,
openIssues: 0,
},
],
},
{
id: "writing",
label: "Отшлифовать письмо о запуске",
goal: "Написать лаконичное письмо о запуске, которое объясняет пользу и приносит клики на демо от целевой аудитории.",
stopRule: "Письмо проходит рубрику тона, укладывается в 140 слов, содержит один чёткий призыв к действию и выдерживает проверку фактов.",
evidence: "Число слов, баллы по рубрике, проверка ссылок, факты о продукте из брифа и заметки рецензента.",
cycles: [
{
action: "Написать черновик по продуктовому брифу и оценить его по рубрике аудитории и тона.",
observation: "В черновике 204 слова, он начинается с перечисления функций и содержит два конкурирующих призыва к действию.",
evaluation: "Факты точны, но критерии иерархии и длины не выполнены.",
adaptation: "Начать с результата для клиента, убрать второй призыв к действию и сократить детали реализации.",
progress: 41,
openIssues: 3,
},
{
action: "Переписать начало и сжать основную часть в одну связку «проблема — польза — доказательство».",
observation: "В письме 126 слов и один призыв к действию, но фраза-доказательство преувеличивает результат бета-теста.",
evaluation: "Структура проходит. Точность фактов всё ещё не дотягивает до рубрики.",
adaptation: "Заменить общее утверждение измеренным результатом бета-теста и запросить финальную проверку фактов.",
progress: 79,
openIssues: 1,
},
{
action: "Вставить проверенную метрику, провалидировать ссылку и ещё раз прогнать полную рубрику.",
observation: "В письме 132 слова, ссылка открывается, факты совпадают с брифом, и каждый пункт рубрики выполнен.",
evaluation: "Артефакт соответствует заданной планке качества, и доказательства можно проверить.",
adaptation: "Остановиться и отправить утверждённую версию владельцу кампании.",
progress: 100,
openIssues: 0,
},
],
},
],
}} />
## Сначала напишите контракт цикла
Прежде чем выбирать модель или фреймворк, напишите небольшой контракт. Если эти поля расплывчаты, цикл превратит неоднозначность в повторяющиеся расходы.
```yaml
goal: "Какое наблюдаемое состояние должно стать истинным?"
inputs: "Что запускает цикл?"
state: "Какие факты и попытки сохраняются между итерациями?"
actions: "Какими инструментами может пользоваться система и с какими правами?"
observations: "Какие внешние сигналы возвращаются после этих действий?"
evaluator: "Какая рубрика или детерминированные проверки оценивают результат?"
success: "Какие доказательства подтверждают, что цель достигнута?"
failure: "Какие условия требуют восстановления или помощи человека?"
budget: "Максимум ходов, времени, токенов, денег или побочных эффектов"
```
<Callout type="warning" title="Цикл без выхода — это готовый сценарий отказа">
Всегда определяйте три выхода: **успех**, когда доказательства подтверждают достижение цели; **неудача**, когда восстановление уже не имеет смысла; и **исчерпание бюджета**, когда цикл достигает допустимого предела затрат или риска.
</Callout>
## Наблюдения должны приходить из внешнего мира
Слова модели «это выглядит правильно» — слабое доказательство. Полезное наблюдение порождается чем-то за пределами того ответа, который оценивается.
<table>
<thead>
<tr>
<th>Задача</th>
<th>Слабое наблюдение</th>
<th>Сильное наблюдение</th>
</tr>
</thead>
<tbody>
<tr>
<td>Исправление кода</td>
<td>«Исправление должно сработать».</td>
<td>Исходный сбой воспроизведён, затем проходят регрессионный тест и весь набор тестов.</td>
</tr>
<tr>
<td>Исследование</td>
<td>«Несколько источников согласны».</td>
<td>Утверждения ссылаются на первоисточники; даты, методы и разногласия зафиксированы.</td>
</tr>
<tr>
<td>Извлечение данных</td>
<td>«JSON вроде бы валидный».</td>
<td>Валидация по схеме проходит, а выборочные записи совпадают с источником.</td>
</tr>
<tr>
<td>Контент</td>
<td>«Текст кажется понятным».</td>
<td>Он проходит именованную рубрику, проверку фактов, проверку ссылок и тестирование на аудитории.</td>
</tr>
<tr>
<td>Операции</td>
<td>«Запрос выполнен успешно».</td>
<td>Внешняя система возвращает ожидаемое состояние, и существует запись в журнале аудита.</td>
</tr>
</tbody>
</table>
Именно поэтому важны инструменты: тесты, браузеры, базы данных, валидаторы и ревью человеком превращают внутреннюю догадку в наблюдаемый результат.
## Разделите исполнителя и проверяющего
Для задач с низким риском одна модель может и писать черновик, и проверять сама себя. Для важной работы используйте проверяющего с другой ролью и ограниченными полномочиями.
<InfoGrid columns={2} items={[
{ label: "Исполнитель", description: "Предлагает изменение, вызывает инструменты действий и объясняет, какие доказательства нужно собрать.", color: "amber" },
{ label: "Проверяющий", description: "Получает цель, артефакт и доказательства; применяет рубрику; не может втихую переписать работу, которую оценивает.", color: "green" },
]} />
Проверяющим не обязательно должен быть другой AI. Предпочитайте самый детерминированный из доступных оценщиков:
1. **Точные проверки** — типы, схемы, ограничения, права доступа, хеши
2. **Исполняемые проверки** — тесты, линтеры, симуляции, валидация ссылок
3. **Проверки по рубрике** — независимая модель или человек, работающие по именованным критериям
4. **Проверки по результату** — реальное поведение пользователей или продакшен-метрики во времени
<Callout type="tip" title="Уверенность — это не доказательство">
Оценка уверенности, сгенерированная той же моделью, которая создала артефакт, — это всё ещё вывод модели. Считайте её подсказкой для маршрутизации, а не доказательством.
</Callout>
## Состояние — позвоночник цикла
Контекст — это то, что модель видит **на текущем ходу**. Состояние — это компактная запись, которая позволяет следующему ходу продолжить работу, ничего не повторяя и не забывая.
<Checklist title="Полезное состояние цикла" items={[
{ text: "Текущая цель и критерии приёмки" },
{ text: "Уже предпринятые действия и их наблюдаемые результаты" },
{ text: "Созданные артефакты с версиями или стабильными ссылками" },
{ text: "Вердикты оценщика и нерешённые проблемы" },
{ text: "Израсходованный бюджет и всё ещё доступные права" },
{ text: "Причина продолжить, остановиться или передать задачу человеку" },
]} />
Храните сжатые решения и доказательства, а не внутреннюю цепочку рассуждений модели. Хорошее состояние — маленькое, прозрачное для проверки и безопасное для возобновления работы.
## Типичные формы циклов
### Цикл исправления
`воспроизвести → внести одно изменение → запустить проверки → диагностировать → повторить или остановиться`
Лучше всего подходит для кода, конфигурации, чистки данных и любых задач с исполняемой обратной связью.
### Цикл «оценщик-оптимизатор»
`сгенерировать → оценить по рубрике → вернуть адресную обратную связь → доработать`
Лучше всего подходит для текстов, перевода, критики дизайна и результатов, качество которых растёт от внятно сформулированной обратной связи.
### Исследовательский цикл
`искать → изучить источники → найти пробелы или противоречия → искать снова → синтезировать`
Лучше всего, когда полнота заранее неизвестна. Правило остановки должно измерять покрытие доказательствами, а не число результатов поиска.
### Цикл с одобрением человека
`подготовить → проверить автоматически → сделать паузу перед рискованным действием → человек одобряет или перенаправляет`
Лучше всего подходит для платежей, публикаций, удаления данных, изменения прав доступа, медицинских и юридических решений и других действий с серьёзными последствиями.
## Отказы, которые нужно устранять на этапе проектирования
<table>
<thead>
<tr>
<th>Отказ</th>
<th>Что произошло</th>
<th>Инженерный ответ</th>
</tr>
</thead>
<tbody>
<tr>
<td>Бесконечные повторы</td>
<td>У цикла нет измеримого выхода по успеху или бюджету.</td>
<td>Добавьте явные конечные состояния и жёсткий лимит итераций.</td>
</tr>
<tr>
<td>Самоодобрение</td>
<td>Исполнитель принимает собственный правдоподобный ответ без доказательств.</td>
<td>Используйте детерминированные проверки или независимого проверяющего.</td>
</tr>
<tr>
<td>Снежный ком контекста</td>
<td>Каждая итерация дописывает всё подряд, пока модель не теряет сигнал.</td>
<td>Храните структурированное состояние и пересобирайте только релевантный контекст.</td>
</tr>
<tr>
<td>Метания</td>
<td>Цикл мечется между двумя исправлениями.</td>
<td>Обнаруживайте повторяющиеся состояния и требуйте смены стратегии или передачи задачи человеку.</td>
</tr>
<tr>
<td>Дрейф цели</td>
<td>Локальные улучшения подменяют исходную задачу.</td>
<td>Перечитывайте неизменную цель и критерии приёмки на каждой итерации.</td>
</tr>
<tr>
<td>Небезопасные повторы</td>
<td>Обратимая ошибка становится вредной при многократном повторении.</td>
<td>Ограничьте права, побочные эффекты, частоту, расходы и масштаб возможного ущерба.</td>
</tr>
</tbody>
</table>
## Минимальная реализация
```typescript
let state = initialize(goal, acceptanceCriteria, budget);
while (state.budget.remaining > 0) {
const context = assembleRelevantContext(state);
const proposedAction = await maker.chooseAction(context);
const observation = await tools.executeWithinPolicy(proposedAction);
const verdict = await evaluator.check({ goal, observation, state });
state = recordIteration(state, { proposedAction, observation, verdict });
if (verdict.status === "passed") return complete(state);
if (verdict.status === "unsafe" || verdict.status === "blocked") {
return escalateToHuman(state);
}
state = adaptPlan(state, verdict.feedback);
}
return stopWithBudgetReport(state);
```
Код — самая простая часть. Сложные вопросы — это вопросы предметной области: какой тест доказывает, что баг исчез? Какой источник авторитетен? Какое действие обратимо? Кто вправе одобрить финальный шаг? Эти решения и есть настоящая работа инженерии циклов.
## Практика: спроектируйте цикл
<TryIt
title="Набросайте контракт цикла"
description="Подставьте вместо переменных повторяющуюся задачу из вашей собственной работы. Попросите AI оспорить слабые доказательства и расплывчатые правила остановки."
prompt={`Спроектируйте ограниченный рабочий цикл AI для этой задачи:
ЗАДАЧА: \${task:каждое утро разбирать новые обращения в службу поддержки}
Определите:
1. Наблюдаемую цель
2. Триггер и необходимые входные данные
3. Разрешённые действия и права на инструменты
4. Доверенные наблюдения из внешней среды
5. Оценщика и его рубрику
6. Состояние, сохраняющееся между итерациями
7. Выходы: успех, неудача и исчерпание бюджета
8. Точки одобрения человеком для рискованных действий
9. Формат трассировки, делающий каждую итерацию проверяемой
Затем определите три самых вероятных сценария отказа в своём проекте и доработайте цикл, чтобы их предотвратить.`}
/>
<Quiz
question="Агент правит код, перечитывает дифф и говорит, что баг исправлен. Какой самой важной части цикла здесь не хватает?"
options={[
"Более длинного системного промпта",
"Внешнего наблюдения, оценённого по правилу остановки",
"Второго прохода редактирования",
"Более крупного контекстного окна"
]}
correctIndex={1}
explanation="Агент создал артефакт и осмотрел его, но не собрал независимых доказательств. Воспроизведение сбоя и запуск релевантных тестов дали бы наблюдаемый сигнал, который можно оценить по правилу остановки."
/>
## Дополнительные материалы
- [Loop Engineering — Addy Osmani](https://addyosmani.com/blog/loop-engineering/) — свежая постановка идеи о замене ручных повторных промптов спроектированной системой, а также практические предостережения о верификации и ответственности человека
- [Building Effective Agents — Anthropic](https://www.anthropic.com/engineering/building-effective-agents) — рабочие процессы «оценщик-оптимизатор», обратная связь из среды, условия остановки и рекомендации о том, когда агентная сложность оправдана
- [A Practical Guide to Building Agents — OpenAI](https://openai.com/business/guides-and-resources/a-practical-guide-to-building-ai-agents/) — запуски агентов, условия выхода, инструменты, защитные ограничения и вмешательство человека
- [ReAct: Synergizing Reasoning and Acting in Language Models](https://arxiv.org/abs/2210.03629) — основополагающее исследование о чередовании действий с наблюдениями из внешней среды
## Резюме
<Callout type="tip" title="Проектируйте обратную связь, а не только промпт">
У надёжного цикла есть измеримая цель, ограниченные действия, доверенные наблюдения, явный оценщик, компактное состояние, безопасные выходы и человеческое суждение там, где этого требуют последствия. Модель находится внутри цикла — но ответственность за цикл остаётся на инженере.
</Callout>