TL;DR
Метод из статьи работает в два захода. Сначала модели дают сломанный код и просят его починить, без подсказок. Каждый патч проверяет внешний инструмент (в статье это формальный верификатор JasperGold). Если не всё починилось, во втором заходе в тот же чат добавляют список упавших проверок (ассертов, то есть автоматических условий «здесь должно быть так-то»). Модель получает новый контекст и чинит остальное.
Главная находка: модель в первом заходе часто угадывает. Она предлагает «возможные ошибки», а патч выглядит правдоподобно, но не работает. В примере из статьи модель нашла нужное место (индекс смещения), но подставила неверное выражение, и проверки продолжали падать. Причина простая: по одному коду модель не знает, что именно должно быть правдой. Упавшая проверка показывает это прямо, и после неё модель попадала в нужное исправление.
Суть метода в трёх вещах. Дай модели не одну строку, а весь блок кода (200–300 строк). Дай список упавших проверок. Принимай патч только после проверки внешним инструментом, а не после слов модели «готово». На выбранном процессоре метод чинил до 98% однострочных и 93% многострочных багов.
Схема метода
ШАГ 0: Прогнать проверки на сломанном коде → список упавших (инструмент)
ШАГ 1: Код + «в нём есть баги, почини» → патч → проверка инструментом
└ если упавших проверок стало меньше — принимаем часть исправлений
ШАГ 2: Тот же чат: + список упавших проверок → новый патч → проверка инструментом
└ все проверки зелёные → «починено»; нет → «не починено»
Шаги выполняются как отдельные запросы в одном чате. Контекст сохраняется.
Пример применения
Домен в статье: микропроцессор (язык SystemVerilog). Нужен инструмент с формальной проверкой, а таким инструментом читатель обычно не владеет. Принцип «упавшие проверки + внешний оракул» переносится на обычный код с тестами, поэтому пример взят оттуда.
Задача: Вы делаете интернет-магазин на Python. После правок в расчёте стоимости доставки по России (по весу, по городу, по скидке за заказ от 5 000 ₽) из 18 тестов упало 4. Что именно сломали, непонятно: правили в трёх местах за вечер.
Промпт (шаг 2, после того как первая попытка «просто почини» не прошла):
Ты — старший Python-разработчик с опытом поддержки интернет-магазинов.
Выше в чате — функция calculate_delivery() целиком (около 120 строк).
В ней несколько багов, их место мне неизвестно.
После твоей первой правки упали эти тесты:
1. test_free_delivery_over_5000
AssertionError: expected 0, got 350
2. test_moscow_weight_3kg
AssertionError: expected 290, got 190
3. test_spb_with_discount_code
AssertionError: expected 412.5, got 450
4. test_remote_region_surcharge
AssertionError: expected 780, got 780.0 (тип не совпал)
Что нужно:
- Не угадывай. Для каждого упавшего теста объясни, какое условие
в коде его ломает.
- Предложи патч для всей функции, а не для одной строки.
- Если одно исправление закрывает сразу несколько тестов, скажи об этом.
- Не меняй тесты. Меняй только код функции.
Результат: Модель разберёт каждый упавший тест, укажет подозрительные условия и вернёт исправленную функцию целиком. Вероятно, она сгруппирует тесты по общей причине. После этого вы сами запускаете тесты. Если часть упала снова, вы повторяете шаг с новым списком упавших.
Почему это работает
Слабость. Когда модели говорят «найди баг» и дают только код, ей приходится угадывать, что считать правильным поведением. Она видит строки, но не знает требований. Отсюда правдоподобные, но неверные патчи.
Сильная сторона. Модель хорошо читает структурированные условия. Падающая проверка записывает ожидание в виде формулы или теста и привязана к конкретному поведению. Из неё легко вывести, где код расходится с ожиданием.
Как метод это использует. Первый заход дёшев и иногда сразу закрывает простые баги. Второй заход добавляет то, чего модели не хватало. Внешний инструмент в конце решает вопрос «починено или нет», а не сама модель. Он не ошибается и не поддакивает.
Рычаги управления: - Размер блока кода. Давай весь блок или функцию, не одну строку. Так не нужно заранее знать, где баг. - Список упавших проверок. Чем точнее и полнее, тем лучше локализация. Если проверок мало, модель снова угадывает. - Критерий принятия патча. «Упавших стало меньше» подходит для многострочных багов. Тогда частичный прогресс сохраняется, а остаток уходит на второй заход. - Роль. Авторы задавали модели роль эксперта с 25-летним опытом. Влияние роли они не измеряли. Это ставка, а не доказанный рычаг.
Шаблон промпта
Шаг 1 (без подсказок):
Ты — {роль_эксперта}.
Ниже {тип_кода}: {название_модуля}. В нём есть баги. Место и число багов неизвестны.
{код_целиком}
Найди баги и предложи исправленную версию всего блока.
Шаг 2 (в том же чате, если проверки всё ещё падают):
После твоей правки упали эти проверки:
{список_упавших_проверок_с_ожидаемым_и_фактическим}
Не угадывай. Для каждой упавшей проверки назови условие в коде, которое её ломает.
Предложи исправленную версию всего блока. {что_нельзя_менять}.
Что подставлять:
- {роль_эксперта} — специализация под ваш стек, например «старший Python-разработчик».
- {код_целиком} — весь блок, 100–300 строк. Не одна строка.
- {список_упавших_проверок_с_ожидаемым_и_фактическим} — вывод тестов или проверок «как есть».
- {что_нельзя_менять} — например, «тесты не трогай».
После каждого шага запускай проверки сам и не верь заявлению модели «починил».
Ограничения
⚠️ Нужен надёжный проверяющий: метод держится на внешнем инструменте, который говорит «верно / неверно». В статье это коммерческий верификатор JasperGold. Без тестов или других проверок остаётся только первый заход, то есть угадывание.
⚠️ Плохие проверки ломают метод: авторы не смогли воспроизвести работу предшественников, потому что ассерты, написанные LLM, у них «проходили или падали без закономерности». Для эксперимента они взяли только вручную написанные проверки высокого качества. Если проверок мало или они слабые, второй заход не поможет.
⚠️ Узкая проверка: один процессор, 6 модулей, одна модель, баги внесла сама LLM (мутации). Реальные баги разработчика устроены иначе. Перенос на обычный код (Python, JS) в статье не проверяли.
⚠️ Роль без проверки: авторы поставили модели роль «эксперт с 25 годами опыта», но влияние роли не измеряли. Нельзя считать её частью работающего метода.
⚠️ Нет сравнения с простыми альтернативами: авторы не сравнивали свой метод с обычным циклом «запусти тесты → покажи ошибку → повтори», который уже есть в код-агентах.
Как исследовали
Исследователи взяли открытый RISC-V процессор BRISC-V и выбрали 6 его модулей с кэшем и шиной (по 171–381 строк). У каждого были проверки на 35–76 условий, покрытие 89–100%. Затем сломали код десятью типами правок: поменяли & на |, == на !=, + на −, инвертировали условие if (hit) → if (!hit), сдвинули вложенный else. Баги вносила сама LLM в отдельной сессии, чтобы она не «помнила» подвох при починке.
Дальше шла проверка по стадиям. Стадия 1 — аналог предыдущей работы: просто «почини». Стадия 2 — то же плюс упавшие проверки. На таблицах видно: в каждом модуле заметная часть багов чинится только на стадии 2, и по данным примерно половина закрытых багов приходится на неё. Дальше усложняли: вносили 2, 3 и 4 бага одновременно, потом 8 типов сразу в двух модулях. Итог: до 98% однострочных и 93% многострочных багов.
Любопытная деталь. В примере со смещением индекса модель на стадии 1 нашла нужное место, но подставила неверный индекс. Только после упавших ассертов она выдала правильное выражение. Вывод для практики: упавшая проверка нужна даже тогда, когда модель уже «примерно знает», где баг.
Другая деталь: в предыдущих работах модели заранее давали строку с багом. Здесь дали блок в 200–300 строк, и метод всё равно сработал. Реальный разработчик обычно тоже знает «где-то тут», а не «в строке 47».
Адаптации и экстраполяции
🔧 Техника: критерий «упавших стало меньше» → пошаговое принятие правок
Для нескольких багов не требуй «всё зелёное сразу». Авторы засчитывали патч, если число упавших проверок уменьшилось, и оставшееся чинили на стадии 2. В инструкции агенту это выглядит так:
После каждой правки запускай тесты. Если упавших стало меньше — оставляй правку и переходи к оставшимся. Если стало больше или столько же — откати.
Экстраполяция в файл инструкций агента (CLAUDE.md / AGENTS.md). Это перенос принципа, авторы такого не делали:
## Правила починки багов
1. Сначала запусти тесты и сохрани список упавших.
2. Не предлагай правку «по догадке». Для каждого упавшего теста
назови условие в коде, которое его ломает.
3. После правки перезапусти тесты. «Починено» = все тесты зелёные.
4. Если упавших стало меньше, оставь правку и продолжай с остатком.
5. Не меняй тесты, чтобы они прошли.
Ресурсы
- Automated Multi-Line Bug Repair Using Model Checker Aided LLMs: A Case Study on RISC-V Processors
- Авторы: Debleena Das, Chandan Kumar Jha, Muhammad Hassan, Rolf Drechsler, Ansuman Banerjee, Subhra K. Das, Amlan Chakrabarti
- Организации: Indian Statistical Institute (Индия), University of Bremen (Германия), DFKI GmbH, University of Calcutta, Thales India
- Использованное: открытый процессор BRISC-V, верификатор JasperGold, предыдущая работа [26] (стадия 1 в сравнении), AssertSolver, HDLdebugger
