TL;DR
Исследование показывает как работает паттерн "generate-and-check" с автоматическими циклами обратной связи: LLM генерирует решение → система проверяет результат → при ошибках возвращает их обратно в LLM для исправления. Главная находка — первый цикл обратной связи (feedback loop) даёт наибольший прирост к успеху (+24%), а дальнейшие итерации почти не помогают.
LLM часто выдаёт решение с ошибками с первого раза. Без обратной связи успех — 69%. Но когда система возвращает детальные сообщения об ошибках (компилятор, тесты, конкретные различия), модель исправляет проблему и успех подскакивает до 78% уже после одного цикла. Разница между моделями сглаживается при использовании feedback loops — слабая модель с обратной связью догоняет сильную без неё.
Вместо бесконечных итераций исправлений внутри одного диалога, эффективнее делать новые запуски с нуля — каждый новый запрос может "попасть" в другую область решений. Бонус-находка: одинаковая задача, сформулированная по-разному (другие термины, примеры, структура), даёт разные результаты от LLM — это можно использовать для улучшения качества.
Схема метода
Исследовали автоматическую систему, но принцип применим вручную:
ШАГ 1: Сгенерировать решение (код/текст/структуру)
ШАГ 2: Проверить результат (компиляция/тесты/формат)
ШАГ 3: При ошибке → вернуть конкретное описание ошибки в LLM
ШАГ 4: LLM исправляет с учётом ошибки
Критично: После 2-3 безуспешных циклов лучше начать новый диалог, чем продолжать исправления.
Пример применения
Задача: Ты автоматизируешь отчёты для бизнеса — попросил Claude написать Python-скрипт для обработки выгрузки из 1С в Excel. Код упал с ошибкой при запуске.
Промпт (первая попытка):
Напиши Python скрипт который читает CSV-файл с данными из 1С
и создаёт сводную таблицу в Excel с группировкой по менеджерам.
После получения ошибки — промпт с feedback:
Скрипт упал с ошибкой:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xed in position 15
Вот код который ты дал:
[вставить код]
Исправь с учётом этой ошибки.
Результат:
Модель увидит конкретную ошибку и контекст, исправит кодировку (скорее всего предложит encoding='cp1251' для 1С). Одна итерация с детальной ошибкой работает лучше чем три попытки с абстрактным "не работает, исправь".
Если после 2 циклов проблема не ушла — начни новый чат и переформулируй задачу: добавь конкретный пример данных, опиши структуру файла подробнее, используй другие термины.
Почему это работает
LLM генерирует вероятностно и может ошибаться с первого раза. Но модель хорошо умеет исправлять, когда видит конкретный контекст проблемы. Детальное сообщение об ошибке — "UnicodeDecodeError в строке 15" или "ожидал число, получил строку" — даёт точечный фокус для исправления. Вместо абстрактного "что-то не так", модель видит на что смотреть.
Первый feedback loop самый эффективный (+24% к успеху) потому что исправляет очевидные ошибки: синтаксис, типы, забытые импорты. Второй и третий циклы уже борются с более тонкими проблемами (логика, архитектура), где простое исправление не поможет — тут нужен другой подход. Поэтому после 1-2 циклов выгоднее начать заново, чем углубляться в исправления.
Multiple runs эффективнее deep iterations потому что каждый новый запрос может "попасть" в другую область решений. LLM не детерминирована — это как несколько попыток решить задачу с разных сторон вместо упорного продолжения одного неудачного пути. Разнообразие подходов побеждает упорство в одном направлении.
Рычаги управления: - Детальность ошибки — чем конкретнее ("строка 15, переменная X") тем лучше исправление - Число циклов — 1-2 оптимально по цене/качеству, дальше убывающая отдача - Момент рестарта — если 2 цикла не помогли, начни новый чат с переформулировкой
Шаблон промпта
Базовый feedback loop:
[Сгенерированное решение получено ранее]
При проверке получил ошибку:
{конкретный_текст_ошибки}
Контекст: {где_именно_произошло}
Исправь код учитывая эту ошибку.
Structured feedback (сильнее):
Проблема: {что_именно_не_работает}
Ожидал: {какой_результат_должен_быть}
Получил: {какой_результат_получился}
Ошибка: {текст_ошибки_если_есть}
Исправь решение.
Где:
- {конкретный_текст_ошибки} — копируй полностью из терминала/IDE/браузера
- {где_именно_произошло} — строка кода, файл, этап выполнения
- Чем детальнее контекст, тем точнее исправление
Правило рестарта: Если 2 цикла не дали результат → новый чат + переформулируй задачу (другие термины, добавь примеры, измени структуру описания).
Ограничения
⚠️ Глубокие проблемы логики: Если ошибка не в синтаксисе или очевидном баге, а в архитектуре решения или неправильном понимании задачи, feedback loops помогают слабо. После 2-3 безуспешных циклов лучше начать диалог заново с другой формулировкой.
⚠️ Нужна автоматическая проверка: Принцип максимально работает когда есть чёткий критерий (компилятор, тесты, формальный формат, математическая проверка). Для субъективных задач ("улучши стиль текста", "сделай дизайн красивее") feedback менее эффективен — нет однозначной "ошибки".
⚠️ Стоимость растёт: Каждый цикл = новый запрос = токены. Исследование показало что 1-2 feedback loop оптимальны по соотношению цена/результат. Больше 3-4 циклов — убывающая отдача, проще начать заново.
⚠️ Застревание в локальном минимуме: Если LLM пошла по неправильному пути решения, исправления в том же диалоге могут усугублять проблему. Модель "привязана" к предыдущему контексту. Новый чат = чистый лист, шанс на другой подход.
Как исследовали
Команда из Bosch Research и университета Магдебурга собрала 50 C-файлов (30 из automotive embedded кода, 10 из open-source библиотек, 10 из соревнований по программированию) и прогнала через систему автоматического перевода на Rust. Система работала так: LLM переводит C → Rust → компилятор rustc проверяет → differential fuzzer тестирует эквивалентность поведения → при ошибках возвращает их LLM.
Для каждого файла делали 20 запусков с разным числом feedback loops (от 1 до 5 итераций) и тремя моделями: GPT-3.5 Turbo (старая, мощная), GPT-4o mini (коммерческая, популярная), Phi-4 (новая, открытая). Измеряли pass@5 — успех хотя бы в одном из пяти прогонов.
Главная находка удивила: без feedback успех 69%, с одним циклом — 78% (+9 процентных пунктов!), со вторым — 78%, с третьим — 78%, с четвёртым — 78%, с пятым — 79%. Первый цикл даёт весь прирост, дальше почти ничего. Разница между моделями без feedback — до 9%, но с feedback почти исчезает — слабая модель с обратной связью работает как сильная без неё.
Что удивило с perturbations: изменения кода которые не меняют поведение (переименования переменных, другие комментарии, форматирование, замена for на while) влияют на результат LLM. Один и тот же алгоритм, записанный по-разному, даёт разный процент успеха. Это значит: если задача не решается — переформулируй её, используй другие термины, структуру, примеры.
Инсайт для практики: не трать 5 запросов на исправления в одном чате. Лучше 1 feedback loop + 2-3 новых диалога с разными формулировками. И всегда возвращай детальные ошибки обратно в модель — это даёт 24% буст с первой же итерации.
Ресурсы
Martin Weiss, Jesko Hecking-Harbusch, Jochen Quante, Matthias Woehrle — "Feedback Loops and Code Perturbations in LLM-based Software Engineering: A Case Study on a C-to-Rust Translation System"
Otto von Guericke University Magdeburg, Bosch Research (Renningen, Germany)
Связанные работы из исследования: - c2rust — классический rule-based транслятор - libFuzzer (LLVM) — инструмент для fuzzing - SWE-Bench, SWE-Lancer — бенчмарки для code generation
