3,583 papers
arXiv:2610.32597 73 23 окт. 2026 г. FREE

Ремонт по упавшим проверкам: сначала просим починить код «вслепую», потом показываем, какие проверки упали

КЛЮЧЕВАЯ СУТЬ
Обнаружено: когда модели дают только код и просят найти баг, она не ищет, а угадывает. Место находит верно, а выражение подставляет не то. Патч выглядит правдоподобно, проверки продолжают падать. Метод позволяет чинить сразу несколько багов в большом блоке кода (200–300 строк), даже если не знаешь, где они. Фишка: во втором заходе в тот же чат добавляют список упавших проверок, и модель видит, что именно должно быть правдой. Решает «починено или нет» внешний инструмент, а не слово модели. Результат на одном процессоре: до 98% однострочных и 93% многострочных багов.
Адаптировать под запрос
⚡

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

📋 Дайджест исследования

Ключевая суть

Обнаружено: когда модели дают только код и просят найти баг, она не ищет, а угадывает. Место находит верно, а выражение подставляет не то. Патч выглядит правдоподобно, проверки продолжают падать. Метод позволяет чинить сразу несколько багов в большом блоке кода (200–300 строк), даже если не знаешь, где они. Фишка: во втором заходе в тот же чат добавляют список упавших проверок, и модель видит, что именно должно быть правдой. Решает «починено или нет» внешний инструмент, а не слово модели. Результат на одном процессоре: до 98% однострочных и 93% многострочных багов.

Принцип работы

Процесс из двух заходов. Шаг 1. Даёшь весь блок кода и просишь: «в нём есть баги, почини». Подсказок нет. Внешний инструмент проверяет патч. Если упавших проверок стало меньше, принимаешь часть исправлений. Шаг 2. В том же чате добавляешь список упавших проверок с ожидаемым и фактическим результатом. Модель правит остаток. Снова проверка инструментом: все зелёные — починено. Первый заход дешёвый и закрывает простое, второй добавляет то, чего модели не хватало: требования. Это как задачник. Без ответов в конце ученик гадает, с ответами сверяется и находит, где ошибся.

Почему работает

По одному коду модель не знает, что считать правильным поведением. Она видит строки, но не видит требований. Отсюда патчи, которые выглядят нормально и не работают. Упавшая проверка записывает ожидание прямо: «ждали 290, получили 190». Модель хорошо читает такие структурированные условия. Проверка превращает вопрос «что тут не так?» в вопрос «почему код даёт 190 вместо 290?». Второй вопрос намного проще. Вторая часть: решение «починено» принимает инструмент. Он не поддакивает и не говорит «готово» из вежливости. Честная оговорка. Цифры 98% и 93% получены на одном процессоре, 6 модулях и одной модели. Баги внесла сама LLM. С простым циклом «запусти тесты, покажи ошибку, повтори» метод не сравнивали.

Когда применять

Разработка кода с автоматическими проверками → правки в нескольких местах, тесты упали, а где именно сломано, неясно. Особенно когда первая просьба «просто почини» не помогла. НЕ подходит, если проверок нет или они слабые: второй заход тогда не поможет, останется угадывание. Авторы это увидели сами: проверки, написанные LLM, у них проходили и падали без закономерности. Перенос на обычный код (Python, JS) в статье не проверяли. Это гипотеза, а не доказанный факт.

Мини-рецепт

1. Прогони проверки до правок. Зафиксируй, сколько упало и какие.
2. Дай весь блок, а не строку. Функция или модуль целиком, 100–300 строк. Так не нужно заранее знать, где баг.
3. Первый заход вслепую: В коде есть баги, место и число неизвестны. Найди и верни исправленный блок целиком.
4. Запусти проверки сам. Упавших стало меньше — оставь исправления. Не поверь слову «починил».
5. Второй заход в том же чате. Вставь вывод упавших проверок как есть: ожидали одно, получили другое.
6. Запрети угадывать: Для каждой упавшей проверки назови условие в коде, которое её ломает.
7. Закрой лазейки: Тесты не меняй, правь только код. Иначе модель может подогнать тест под код.
8. Повтори проверку. Если часть упала снова, дай новый список и иди ещё раз.

Примеры

[ПЛОХО] : Почини функцию calculate_delivery, там где-то баг
[ХОРОШО] : Выше функция calculate_delivery целиком, около 120 строк. После твоей правки упали тесты: test_free_delivery_over_5000 (ждали 0, получили 350), test_moscow_weight_3kg (ждали 290, получили 190), test_spb_with_discount_code (ждали 412.5, получили 450). Не угадывай: для каждого теста назови условие в коде, которое его ломает. Если одна правка закрывает несколько тестов, скажи об этом. Верни функцию целиком. Тесты не меняй. После ответа запусти тесты сам. Упали снова — вставь новый список в тот же чат.
Источник: Automated Multi-Line Bug Repair Using Model Checker Aided LLMs: A Case Study on RISC-V Processors
ArXiv ID: 2610.32597 | Сгенерировано: 2026-10-26 15:10

Проблемы LLM

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

Методы

МетодСуть
Два захода: сначала вслепую, потом с упавшими проверкамиЧто делать: Шаг 1. Дай весь блок кода (функцию или модуль, 100–300 строк, не одну строку) и скажи: «Тут есть баги, почини». Запусти тесты сам. Шаг 2, в том же чате. Если что-то падает, вставь список упавших проверок с ожидаемым и фактическим результатом. Попроси объяснить причину по каждой проверке и вернуть блок целиком. Повторяй с новым списком, пока не пройдёт всё. Почему работает: Первый заход дешёвый и закрывает простые баги. Упавшая проверка записывает ожидание точно и привязана к конкретному поведению. Из неё легко увидеть, где код расходится с ожиданием. Целый блок кода избавляет от необходимости заранее знать место бага. Решает внешний инструмент: «Починено» — это когда тесты зелёные, а не когда модель написала «готово». Модель может поддакивать, тесты — нет. Если правок несколько: принимай правку, после которой упавших проверок стало меньше. Остаток отдавай на второй заход. Когда работает: есть набор надёжных тестов и можно быстро их запускать. Когда нет: тестов мало или они слабые. Тогда у второго захода нет нового сигнала, и модель снова угадывает. Метод проверен на узком случае и не сравнивался с обычным циклом «запусти тесты → покажи ошибку → повтори»
📖 Простыми словами

Automated Multi-Line Bug RepairUsingModelChecker AidedLLMs: A Case Study on RISC-V Processors

arXiv: 2610.32597

LLM не умеет чинить код вслепую по простой причине: она не знает, как этот код должен работать. Когда ты бросаешь ей сломанные строки со словами "почини", модель начинает угадывать логику и выдаёт правдоподобный мусор — синтаксис чистый, но логика врёт. Без чётких рамок нейросеть просто фантазирует в меру контекста. Чтобы она не лажала, ей нужен внешний оракул, который моментально бьёт по рукам за расхождение с реальными требованиями.

Это как отправить слепого сантехника чинить трубы в темноте, а потом удивляться потопу. Формально гайки закручены, но вода хлещет из пяти новых щелей — мастер просто не видел схему разводки. Авторы статьи придумали не давать модели блуждать на ощупь. Они добавили автоматический чекер, который после первого же косяка тычет нейросеть носом в карту протечек, чтобы та перестала трогать то, что не ломалось.

Метод бьёт задачу в два раунда: слепой фикс и дожим через ошибки. Сначала сеть выдаёт правку с нуля, а внешний верификатор JasperGold гоняет её через жёсткие математические условия. Если патч сломался, контекст не сбрасывают: в этот же диалог заливают список упавших ассертов. Видя, где конкретно не сошлись концы с концами, модель перестаёт гадать на кофейной гуще и точечно переписывает проблемные куски.

Тестировали схему на процессорах RISC-V и аппаратном коде, но принцип абсолютно универсален. Тебе не нужен космический верификатор микросхем — замени его на банальную пачку unit-тестов и линтеров в обычном CI/CD. Механика идеально ложится на Python, Go или веб-разработку. Перестань умолять нейросеть «сделать красиво» в один заход — заставь её работать против логов собственных падений.

Суть простая: LLM без жёсткого оракула бесполезна на сложных багах. Хватит ждать магии от одного промпта — собирай конвейер из генератора и тупого, злого валидатора. Двухшаговый цикл с обратной связью превращает генератор галлюцинаций во вменяемого ассистента. Кто научится скармливать ошибки тестов обратно в контекст, спасёт тонну часов, а остальные продолжат разгребать кривые патчи руками.

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

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

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