TL;DR
Когда LLM итеративно улучшает что-то за несколько ходов — код, текст, план — она постепенно забывает ранние ограничения. Каждый новый запрос "перетягивает" внимание модели, и старые требования тихо выпадают. Авторы назвали это iterative refinement paradox — парадокс итеративного уточнения: функционально лучше, но по критически важным параметрам хуже.
Главная находка: мягкие инструкции не держатся. Написать в промпте "сохраняй безопасность" или "не теряй тон" — недостаточно. Модель кивает и всё равно срезает. Хуже того: добавление промежуточных проверок без явных якорей (авторы проверяли статический анализ кода — SAST) увеличивает деградацию: система получает ложную уверенность, что всё под контролем, хотя структурные потери продолжаются невидимо.
SCAFFOLD-CEGIS решает это через явные якоря — список конкретных элементов, которые запрещено трогать, — плюс четырёхслойную проверку после каждой итерации и накопление опыта из отказов. Если новая версия нарушает якорь, итерация отклоняется с объяснением: агент-ревьюер извлекает урок и передаёт его следующей попытке.
Схема метода
Работает как конвейер из четырёх агентов внутри одной итерации:
ДО ИТЕРАЦИИ
SecurityArchitectAgent: сканирует текущую версию →
выдаёт набор якорей Φ (что нельзя трогать)
ИТЕРАЦИЯ
ImplementerAgent: получает (задача + якоря + опыт прошлых ошибок) →
генерирует новую версию P'
ПРОВЕРКА (4 слоя последовательно)
GatekeeperAgent →
Слой 1: тесты проходят? → PASS/RETRY
Слой 2: уязвимостей не стало больше? → PASS/RETRY
Слой 3: изменений не слишком много? → PASS/RETRY
Слой 4: все якоря на месте? → PASS/REJECT
ЕСЛИ ОТКАЗ
AssimilatorAgent: извлекает урок из провала →
добавляет правило в базу знаний K →
ImplementerAgent получает обновлённый K на следующей итерации
Все шаги выполняются в замкнутом цикле для каждой итерации. В оригинале это автоматизированная система. Принцип применим вручную в чате.
Пример применения
Задача: Ты пишешь серию постов для Telegram-канала предпринимателя. Работаешь с Claude несколько сессий: дорабатываешь тексты по обратной связи, добавляешь примеры, сокращаешь. К пятой итерации замечаешь: живой разговорный тон исчез, исчезли личные истории, появилась канцелярщина. Claude "улучшал" — и постепенно убил голос автора.
Промпт с якорями:
Задача этой итерации: {что нужно изменить — например, сократить на 30% и добавить конкретный пример}
ЯКОРЯ — сохранить обязательно:
— Голос: разговорный, как будто человек говорит вслух, не пишет.
Маркер: короткие предложения, вопросы к читателю, "я", "мы".
— Структура: личная история → проблема → решение → вывод.
Маркер: первый абзац всегда про конкретный случай из жизни автора.
— Тон: честный, без пафоса.
Маркер: нет слов "уникальный", "эксклюзивный", "высококачественный".
Текущая версия текста:
{вставить текст}
После правки — проверь каждый якорь и напиши: сохранён / нарушен.
Если видишь конфликт между задачей и якорем — спроси, не решай сам.
Результат: Модель выдаст исправленный текст и блок верификации якорей: по каждому пункту — сохранён или нарушен с пояснением. Если в задаче есть конфликт с якорем (например, сократить на 30%, но история в первом абзаце займёт больше места) — модель спросит приоритет.
Почему это работает
Слабость LLM при итерациях — каждый новый запрос сдвигает "фокус" генерации. Модель не ведёт внутренний список того, что нельзя менять. Она оптимизирует под текущий запрос и не замечает, что срезала то, что было важно три хода назад. Это не ошибка — это то, как устроена генерация следующего токена.
Мягкие инструкции не работают потому что "помни про безопасность" — это не ограничение, это пожелание. Модель интерпретирует его как один из многих факторов и балансирует его с новыми задачами. К пятой итерации пожелание весит меньше, чем конкретная задача "сделай текст короче". Явный якорь — не пожелание, а контрольная точка: либо элемент присутствует, либо нет. Это бинарная проверка, которую легко сделать самой модели.
Почему авторы не обошлись простой проверкой (SAST) — и это ключевой инсайт. Статические инструменты ловят появление нового плохого. Они не замечают исчезновение старого хорошего. Удалил валидацию? Нет новой уязвимости по паттерну — нет сигнала. Тихая деградация (latent security degradation — скрытое ухудшение безопасности) невидима для поверхностных проверок. Для чата это значит: "проверь, нет ли ошибок" — неправильный вопрос. Правильный вопрос: "убедись, что X, Y, Z всё ещё на месте".
Рычаги управления:
- Строгость якорей. hard ("обязательно") vs soft ("желательно") — для важных вещей используй жёсткую формулировку: "это должно присутствовать, иначе отклони версию"
- Детализация якоря. Чем точнее маркер ("первое предложение содержит вопрос к читателю" vs "разговорный тон"), тем надёжнее проверка
- Накопительная база ошибок. Если модель нарушила якорь — добавь в следующий промпт: "В прошлый раз ты убрал X. Не делай этого."
- Блок верификации. Можно убрать "проверь якоря" — ускоряет работу, но теряешь прозрачность
Шаблон промпта
Задача итерации: {что нужно сделать с текущей версией}
ЯКОРЯ (не менять):
— {якорь_1}: {конкретный маркер проверки — как понять, что сохранён}
— {якорь_2}: {конкретный маркер проверки}
— {якорь_3}: {конкретный маркер проверки}
ОПЫТ ПРОШЛЫХ ИТЕРАЦИЙ (если есть):
— {что нарушалось раньше и правило-запрет}
Текущая версия:
{текст / план / структура}
После выполнения — верифицируй каждый якорь:
сохранён / нарушен + объяснение.
При конфликте задачи с якорем — спрашивай приоритет.
Плейсхолдеры:
- {задача итерации} — конкретно: "сократи на треть", "добавь блок с примером", "сделай финал сильнее"
- {якорь} — что нельзя терять: тон, структура, конкретный блок, ключевой аргумент
- {маркер} — как проверить его наличие: цитата, формат, слово-триггер
- {опыт прошлых итераций} — что LLM уже нарушала раньше; в первой итерации пусто
🚀 Быстрый старт — вставь в чат:
Вот шаблон якорного промпта для итеративной работы.
Адаптируй под мою задачу и задай вопросы, чтобы заполнить плейсхолдеры.
[вставить шаблон выше]
LLM спросит: что именно ты итерируешь, какую задачу выполняешь сейчас и что критически нельзя потерять — потому что без этого якоря не будут конкретными и не удержатся при следующих итерациях.
Ограничения
⚠️ Только для итеративной работы: Якоря не нужны, если задача выполняется за один запрос. Метод решает проблему нескольких ходов, не одиночного промпта.
⚠️ Якорь работает настолько, насколько точен маркер: Расплывчатый якорь ("сохрани профессиональный тон") держится хуже конкретного ("каждый абзац начинается с утверждения, не с вопроса"). Вся сила — в точности формулировки.
⚠️ Растущий список якорей замедляет работу: Слишком много якорей — и модель начинает жертвовать качеством самой задачи ради их соблюдения. Авторы ограничивают приоритетами: CRITICAL → HIGH → MEDIUM → LOW.
⚠️ Скрытую деградацию не поймать без явной проверки: Если ты не просишь модель верифицировать якоря явно, она может тихо нарушить их и не сказать — особенно на поздних итерациях.
Как исследовали
Идея была простой: взять 96 цепочек итераций с GPT-4o, дать каждой 10 раундов уточнения — и посмотреть, становится ли код безопаснее или нет. Результат оказался неожиданным: почти в каждом втором случае уязвимостей стало больше, чем было в исходнике. Причём даже когда в промпте явно просили "улучши безопасность" — деградация сохранялась в 28.6% цепочек.
Дальше исследователи добавили SAST (статический анализ безопасности — автоматические инструменты поиска уязвимостей) как "фильтр" после каждой итерации. Логика казалась железной: если нашлась уязвимость — отклоняем. Но скрытая деградация выросла с 12.5% до 20.8%. SAST не видит удалённую валидацию — он видит только появившиеся паттерны опасного кода. Удалил защиту? Чисто.
Затем проверили SCAFFOLD-CEGIS на 288 цепочках (3 модели × 2 языка × 4 стратегии итерации × 24 задачи). Скрытая деградация упала с 20.8% до 2.1%. Абляция (отключение компонентов по одному) показала, что без семантических якорей результат почти не улучшается, без четырёхслойной проверки тоже. Работает только всё вместе. Самое интересное: failure assimilation (накопление уроков из отказов) дало заметный вклад именно на поздних итерациях, когда модель уже "знала" типичные ошибки задачи.
Адаптации и экстраполяции
1. Техника: именованные якоря с весом → управление компромиссами
Вместо просто списка запретов — добавь приоритет, как у авторов:
🔧 Добавь уровни приоритета к якорям → модель знает, что важнее при конфликте
ЯКОРЯ:
[КРИТИЧНО] Личная история в начале — без неё не принимай версию
[ВЫСОКО] Не более 3 абзацев
[СРЕДНЕ] Заканчивается на вопрос к читателю
[ЖЕЛАТЕЛЬНО] Есть конкретная цифра или дата
При конфликте соблюдай приоритет сверху вниз.
Когда задача (например, "сократи") конфликтует с якорем — модель знает что пожертвовать первым.
2. Экстраполяция: накопительная база ошибок как отдельный документ
Авторы ведут knowledge base (базу знаний из прошлых провалов) автоматически. В чате это можно делать вручную: завести отдельный документ с правилами, которые сформировались из нарушений.
БАЗА ОШИБОК (обновляется после каждой итерации):
— Итерация 2: убрал блок с числами → правило: конкретные цифры обязательны
— Итерация 4: стал официальным → правило: проверяй первый абзац на разговорность
— Итерация 5: пропал призыв к действию → правило: последнее предложение = действие
Перед следующей итерацией вставляй актуальную базу в промпт.
Это и есть failure assimilation вручную. Работает для любого долгосрочного проекта с LLM: статья, стратегия, продукт.
Ресурсы
Yi Chen, Yun Bian, Haiquan Wang, Shihao Li, Zhe Cui Chengdu Institute of Computer Application, Chinese Academy of Sciences; University of Chinese Academy of Sciences
Методологическая основа: CEGIS (Counterexample-Guided Inductive Synthesis) — классический подход из формальной верификации программ. Инструменты проверки: Bandit (Python SAST), SpotBugs + FindSecBugs (Java SAST). Модели: GPT-4o, Claude Sonnet, Gemini Pro.
