3,583 papers
arXiv:2509.16275 72 18 сент. 2025 г. FREE

Итеративная валидация исправлений: внешний верификатор + LLM

КЛЮЧЕВАЯ СУТЬ
LLM часто чинит код так, что синтаксически всё верно, но проблема не решена. Модель переписывает уязвимый участок, но упускает саму суть бага — у неё нет механизма проверки. Метод SecureFixAgent позволяет исправлять код через цикл с объективной проверкой: статический анализатор или тесты ловят промахи мгновенно, результат идёт обратно в LLM, цикл повторяется до устранения проблемы. Фишка: внешний инструмент даёт объективную правду — либо код работает, либо нет. Вместо слепой генерации в один проход — точность с 74% до 88%.
Адаптировать под запрос

Исследователи из George Washington University показали, что связка "внешний детектор → LLM → проверка" поднимает точность исправления кода с 74% до 88%. Механика: статический анализатор находит проблему → LLM исправляет → анализатор проверяет исправление → если проблема осталась, цикл повторяется с уточнённым контекстом. Вместо blind single-pass генерации — контролируемые итерации с объективной проверкой каждого шага.

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

Решение: LLM исправляет, внешний инструмент проверяет, результат проверки идёт обратно в LLM. Цикл повторяется до полного устранения проблемы или достижения лимита итераций (обычно 3-4). Каждая итерация уточняет контекст: "твоё прошлое исправление не сработало, вот что показал анализатор". Модель учится на своих ошибках внутри одной сессии.

🔬

Схема метода

ШАГ 1: Внешний инструмент (linter/тесты/компилятор) находит проблему
 → отчёт с конкретным местом и типом ошибки

ШАГ 2: LLM получает код + отчёт → генерирует исправление + объяснение
 → возвращает патч

ШАГ 3: Применить патч → запустить проверку снова
 → если проблема осталась, вернуться к Шагу 2 с новым контекстом

Цикл повторяется в одной сессии до устранения проблемы или лимита итераций

🚀

Пример применения

⚠️ Ограничение метода: Работает только если есть автоматический верификатор (линтер, тесты, компилятор). Для субъективных задач (креатив, стиль текста) не подходит. Хорош для кода, структурированных данных, формальных правил.

Задача: Скрипт для обработки CSV с клиентами из 1С падает на русских символах. Файл экспортировался в windows-1251, код читает как UTF-8 — всё ломается на первой строке с "ООО Рассвет".

Итерация 1:

# Запустили код → получили ошибку:
# UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf0
```

**Промпт:**
```
Вот код для чтения CSV:

import pandas as pd
df = pd.read_csv('clients.csv')

Получаю ошибку: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf0

Исправь код. Объясни что изменил и почему.

Итерация 2:

# LLM предложил encoding='latin1' → код работает, но русские символы битые
# Запустили → увидели "ООО ÐаÑÑвеÑ"
```

**Промпт:**
```
Твоё исправление с encoding='latin1' запустилось, но русские символы битые:
"ООО ÐаÑÑвеÑ" вместо "ООО Рассвет"

Исходный файл экспортирован из 1С. Исправь снова. Объясни почему прошлое решение не сработало.
```

**Результат:** 
LLM покажет 2-3 раунда исправлений, каждый раз объясняя почему прошлый вариант не сработал. Финальный код будет с правильной кодировкой (`windows-1251`), с обработкой ошибок на случай битых данных. Модель объяснит разницу между UTF-8, latin1 и windows-1251 в контексте российских систем 1С.

---

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

**LLM генерирует решения fast, но не умеет проверять их объективно**. Модель может написать код, который выглядит правильным и даже логически связным — но реально не запустится или не решит проблему. У неё нет компилятора в голове, нет runtime для проверки. Она оперирует паттернами из обучающих данных, не фактами о конкретном окружении.

**Внешние инструменты (линтеры, тесты, компиляторы) дают объективную правду**. Они не додумывают — либо код работает, либо нет. Но они не умеют исправлять — только указывают на ошибки. Это идеальное разделение труда: LLM генерирует варианты, инструмент фильтрует неправильные.

**Итеративный цикл превращает угадывание в направленный поиск**. Первая попытка LLM часто промахивается — модель не знает специфику окружения (версия библиотеки, кодировка файла, особенности системы). Но каждый раунд проверки даёт ей **конкретный feedback** — не абстрактное "не работает", а точный trace ошибки. Модель сужает пространство возможных решений, отсекая уже проверенные варианты.

**Рычаги управления промптом:**

- **Тип верификатора** — линтер (стиль кода), тесты (логика), компилятор (синтаксис) → выбирай под задачу
- **Лимит итераций** — 1-2 для простых багов, 4-5 для сложных → экономия токенов vs thorough
- **Уровень объяснений** — "без комментариев" vs "подробно объясни" → speed vs понимание
- **Scope исправления** — "исправь только эту функцию" vs "пересмотри весь модуль" → точечно vs радикально

---

### Шаблон промпта
```
Задача: {описание проблемы}

Исходный код:
{код}

Ошибка при проверке:
{вывод линтера/тестов/компилятора}

Исправь код. Требования:
1. Минимальные изменения — только то, что нужно для устранения ошибки
2. Объясни ЧТО изменил и ПОЧЕМУ это решает проблему
3. Верни исправленный код отдельным блоком для копирования

---

[После первой попытки, если проблема осталась:]

Твоё исправление дало новую ошибку:
{новый вывод проверки}

Проблема в строке {номер строки}: {контекст ошибки}

Исправь снова. Объясни почему прошлое решение не сработало.

Что подставлять:

  • {описание проблемы} — что не работает, какой результат ожидается
  • {код} — полный код или проблемный участок
  • {вывод линтера/тестов/компилятора} — дословный вывод инструмента проверки
  • {номер строки} и {контекст ошибки} — конкретика для второй итерации

⚠️

Ограничения

⚠️ Нужен автоматический верификатор: Метод работает только если есть инструмент, который объективно скажет "исправлено" или "нет". Без линтера/тестов/компилятора — просто многораундовый диалог с субъективной оценкой.

⚠️ Не для распределённой логики: Если баг в архитектуре (взаимодействие модулей, race conditions, конфигурация окружения) — точечные исправления не помогут. LLM видит локальный контекст, не всю систему.

⚠️ Лимит итераций ≠ решение: Сложные баги могут требовать 5-7 раундов или принципиального переписывания. После 3-4 итераций без прогресса — переформулируй задачу или разбей на части.


🔍

Как исследовали

Команда из George Washington University взяла 740 синтетических сэмплов Python кода с внедрёнными уязвимостями + 1428 реальных примеров из CVE-баз (публичные базы известных уязвимостей). Проверяли на шести LLM — от 1.3B до 7B параметров — в трёх режимах:

  1. Bandit в одиночку — статический анализатор находит проблемы, но не исправляет (0% fix accuracy, baseline)
  2. LLM в одиночку — модель генерирует исправление в один проход без проверки (74% точности, 13.5% ложных правок)
  3. SecureFixAgent — цикл detect→repair→validate с Bandit как верификатором (88% точности, 8% ложных правок)

Почему такая разница? LLM-only часто "исправляет" код косметически — меняет названия переменных, переписывает структуру, но не устраняет саму уязвимость. Например, вместо eval(user_input) пишет exec(sanitized_input) — синтаксически ОК, но проблема injection никуда не делась. Bandit на второй итерации ловит это — "уязвимость всё ещё есть, метод изменился но суть та же". LLM получает чёткий feedback: "твой sanitize не работает, вот trace". Третья итерация — правильное решение с ast.literal_eval().

Что удивило: Fine-tuning на специфичных данных (пары уязвимость→исправление) дал всего +5-8% точности. Основной прирост (+13.5%) пришёл именно от итеративной валидации, не от адаптации весов модели. Это значит workflow важнее натренированности — правильная организация процесса бьёт дотюнинг.

Человеческая оценка: 15 разработчиков (студенты CS, junior devs, senior консультанты) оценивали качество объяснений по шкале 1-5. LLM-only набрал 2.9/5 ("непонятно почему так исправил"), SecureFixAgent — 4.5/5 ("чётко видно логику, почему первая попытка не сработала и что именно изменилось"). Прозрачность процесса повышает доверие — люди видят не магический output, а reasoning.


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

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

LLM часто чинит код так, что синтаксически всё верно, но проблема не решена. Модель переписывает уязвимый участок, но упускает саму суть бага — у неё нет механизма проверки. Метод SecureFixAgent позволяет исправлять код через цикл с объективной проверкой: статический анализатор или тесты ловят промахи мгновенно, результат идёт обратно в LLM, цикл повторяется до устранения проблемы. Фишка: внешний инструмент даёт объективную правду — либо код работает, либо нет. Вместо слепой генерации в один проход — точность с 74% до 88%.

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

Не надейся на одну попытку LLM — запусти цикл с проверкой. Схема: линтер находит проблему → LLM исправляет → линтер проверяет снова → если проблема осталась, результат проверки идёт обратно в LLM с уточнённым контекстом. Цикл повторяется 3-4 раунда до полного устранения или лимита итераций. Каждая итерация уточняет: "твоё прошлое исправление не сработало, вот что показал анализатор".

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

LLM генерирует решения быстро, но не умеет проверять их объективно. Модель может написать код который выглядит правильным — но реально не запустится. У неё нет компилятора в голове, нет runtime для проверки. Итеративный цикл превращает угадывание в направленный поиск. Первая попытка LLM часто промахивается — модель не знает специфику окружения (версия библиотеки, кодировка файла). Но каждый раунд проверки даёт ей конкретный отклик — не абстрактное "не работает", а точный trace ошибки. Модель сужает пространство решений, отсекая уже проверенные варианты.

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

Исправление кода → конкретно для автоматизированного рефакторинга, устранения уязвимостей, багфиксинга, особенно когда есть линтер/тесты/компилятор для объективной проверки. Работает для структурированных данных, формальных правил. НЕ подходит для субъективных задач (креатив, стиль текста) — там нет автоматического верификатора который скажет "правильно" или "нет".

Мини-рецепт

1. Запусти внешний инструмент: линтер/тесты/компилятор находит проблему → получаешь отчёт с конкретным местом и типом ошибки
2. Дай LLM код + отчёт: модель генерирует исправление + объяснение → возвращает патч
3. Применяешь патч → проверяешь снова: если проблема осталась, берёшь новый вывод проверки и возвращаешься к шагу 2 с уточнённым контекстом "твоё прошлое исправление дало ошибку: {вывод}, исправь снова"
4. Лимит итераций: обычно 3-4 раунда — после этого либо проблема решена, либо нужно переформулировать задачу

Примеры

[ПЛОХО] : Вот код который падает на русских символах в CSV. Исправь — одна попытка без проверки, LLM предложит encoding='latin1', символы будут битые
[ХОРОШО] : Итерация 1: Вот код: pd.read_csv('clients.csv'). Ошибка: UnicodeDecodeError 'utf-8' can't decode byte 0xf0. Исправь, объясни что изменил → LLM предлагает encoding='latin1' → запускаешь, видишь битые символы "ООО ÐаÑÑвеÑ". Итерация 2: Твоё исправление с encoding='latin1' запустилось, но русские символы битые. Файл из 1С. Исправь снова, объясни почему прошлое не сработало → LLM даст windows-1251 с обработкой ошибок, объяснит разницу кодировок в контексте российских систем
Источник: SecureFixAgent: A HybridLLMAgent for Automated Python Static Vulnerability Repair
ArXiv ID: 2509.16275 | Сгенерировано: 2026-01-12 05:56

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

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

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