3,583 papers
arXiv:2603.08520 72 9 мар. 2026 г. FREE

SCAFFOLD-CEGIS: явные якоря против тихого забывания требований при итеративной работе с LLM

КЛЮЧЕВАЯ СУТЬ
Когда LLM итеративно улучшает что-то за несколько ходов — код, текст, план — она постепенно забывает ранние ограничения. Каждый новый запрос "перетягивает" внимание модели, и старые требования тихо выпадают. Авторы назвали это iterative refinement paradox — парадокс итеративного уточнения: функционально лучше, но по критически важным параметрам хуже.
Адаптировать под запрос

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.


Проблемы LLM

ПроблемаСутьКак обойти
Ранние требования тихо исчезают при итерацияхКаждый новый запрос сдвигает фокус модели. Она оптимизирует под текущую задачу. Старые ограничения не удерживаются — они не «забыты», они просто весят меньше, чем конкретная новая задача. К пятой итерации написанное в начале «сохрани тон» больше не работает. Это не ошибка — это то, как устроена генерация токеновДавай не пожелания, а явные якоря. Конкретные элементы, которые нельзя трогать. С маркером проверки. После каждой итерации проси модель явно верифицировать каждый якорь: «сохранён или нарушен»
Проверки ловят новые ошибки, но не замечают пропажи старого«Проверь, нет ли ошибок» — неправильный вопрос. Инструменты и сама модель замечают, когда появляется что-то плохое. Они не замечают, когда исчезает что-то хорошее. Удалил валидацию? Нет нового паттерна угрозы — нет сигнала. Это скрытая деградация. Добавление промежуточных проверок без явных якорей создаёт ложное ощущение контроляМеняй вопрос: вместо «есть ли ошибки» — спрашивай «X, Y, Z всё ещё на месте?» Правильный вопрос направлен на сохранность, а не на появление нового плохого

Методы

МетодСуть
Якорный промпт — удержание обязательных элементов через итерацииПеред каждой итерацией явно задай список элементов, которые нельзя менять. Каждый якорь — с конкретным маркером проверки. После итерации проси модель явно верифицировать каждый пункт. Шаблон: ЯКОРЯ: — {что нельзя трогать}: {как проверить, что оно на месте}. Конфликт задачи с якорем — не решаем молча, спрашиваем приоритет. Почему работает: якорь — это бинарная проверка, не пожелание. Либо элемент есть, либо нет. Модель может проверить это явно. Пожелание конкурирует с задачей и проигрывает. Якорь — контрольная точка, у него нет конкурентов. Когда применять: любая итеративная работа от 3+ ходов. Не нужен: один запрос, одна итерация
Накопительная база нарушений — передача ошибок в следующую итерациюЕсли модель нарушила якорь — добавь в следующий промпт явное правило: «В прошлый раз ты убрал X. Не делай этого». Блок ОПЫТ ПРОШЛЫХ ИТЕРАЦИЙ: в начале промпта. Почему работает: каждая итерация начинается без памяти о прошлых. Явный список прошлых нарушений делает их частью текущего контекста. Модель не «помнит» — она видит явный запрет

Тезисы

ТезисКомментарий
Бинарный маркер держится лучше общей инструкции«Сохрани разговорный тон» — это пожелание. Одно из многих. На пятой итерации оно весит меньше, чем конкретная задача. «Первый абзац всегда начинается с вопроса к читателю» — это контрольная точка. Либо вопрос есть, либо нет. Чем точнее формулировка, тем сложнее якорю «раствориться» в конкурирующих задачах. Применяй: для любых элементов, которые критично сохранить, формулируй как факт, который можно проверить — не как качество
📖 Простыми словами

SCAFFOLD-CEGIS: Preventing Latent Security Degradation inLLM-Driven Iterative Code Refinement

arXiv: 2603.08520

Когда ты просишь нейронку допилить код или текст в несколько итераций, она ведет себя как золотая рыбка с амнезией. Суть проблемы в том, что каждый новый запрос «улучши вот это» или «добавь вот то» смещает фокус внимания модели. Она так сильно старается угодить твоему последнему капризу, что по пути выбрасывает на помойку базовые ограничения, которые ты задал в самом начале. Это фундаментальный баг архитектуры: модель оптимизирует ответ под текущий контекст, и старые инструкции просто вымываются из памяти, превращаясь в белый шум.

Это как если бы ты делал ремонт в квартире и на каждом этапе звал нового прораба. Первый сделал крепкие стены, второй пришел вешать полки и продолбил эти стены насквозь, а третий решил, что для красоты нужно снести несущую колонну. В итоге функционально всё блестит, но дом вот-вот рухнет тебе на голову. Ты просил «сделать лучше», и модель сделала, но по дороге тихо прирезала безопасность или логику, которую ты выстраивал три хода назад.

Чтобы эта херня не развалилась, авторы придумали SCAFFOLD-CEGIS — систему из четырех внутренних агентов, которые работают как отдел техконтроля. Пока один «улучшатор» пишет код, другие сидят со списком требований и бьют его по рукам, если он пытается выкинуть важную проверку безопасности ради красоты синтаксиса. Метод использует формальную верификацию: он не просто верит модели на слово, а прогоняет результат через жесткие фильтры, проверяя, не превратилось ли «улучшение» в латентную деградацию.

Исследование проводили на коде, но этот парадокс итеративного уточнения — универсальная подстава. Он вылезает везде: от написания постов в Telegram, где к пятой правке исчезает твой авторский стиль и остается сухой официоз, до составления бизнес-планов, где за мелкими деталями теряется главная цель. Если ты работаешь с LLM в долгую, помни: чем больше правок, тем выше шанс, что модель сломает фундамент ради покраски забора.

Короче, не надейся, что нейронка сама удержит в голове все твои «нельзя» и «обязательно». Либо используй жесткие фреймворки вроде этого SCAFFOLD, либо каждый раз копипасти базовые правила в новый промпт. Иначе на выходе получишь красивую обертку, внутри которой полный провал по безопасности. В мире AI-разработки это сейчас главный риск: код работает, тесты проходят, но дыра в защите размером с кулак уже встроена в систему.

Работа с исследованием

Адаптируйте исследование под ваши задачи или создайте готовый промпт на основе техник из исследования.

0 / 2000
~0.5-2 N-токенов ~10-30с
~0.3-1 N-токенов ~5-15с