惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cisco Talos Blog
Cisco Talos Blog
V
V2EX
C
Check Point Blog
GbyAI
GbyAI
D
Docker
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
B
Blog RSS Feed
H
Hackread – Cybersecurity News, Data Breaches, AI and More
N
Netflix TechBlog - Medium
T
Troy Hunt's Blog
博客园 - Franky
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Microsoft Security Blog
Microsoft Security Blog
P
Privacy & Cybersecurity Law Blog
WordPress大学
WordPress大学
The Cloudflare Blog
S
SegmentFault 最新的问题
Latest news
Latest news
Microsoft Azure Blog
Microsoft Azure Blog
P
Proofpoint News Feed
I
InfoQ
博客园 - 【当耐特】
NISL@THU
NISL@THU
A
About on SuperTechFans
T
Tailwind CSS Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
The Hacker News
The Hacker News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Scott Helme
Scott Helme
雷峰网
雷峰网
C
CXSECURITY Database RSS Feed - CXSecurity.com
Security Latest
Security Latest
V
Vulnerabilities – Threatpost
Security Archives - TechRepublic
Security Archives - TechRepublic
A
Arctic Wolf
Hacker News: Ask HN
Hacker News: Ask HN
N
News and Events Feed by Topic
IT之家
IT之家
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
aimingoo的专栏
aimingoo的专栏
T
Threat Research - Cisco Blogs
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
SecWiki News
SecWiki News
大猫的无限游戏
大猫的无限游戏
S
Security Affairs
The Register - Security
The Register - Security
www.infosecurity-magazine.com
www.infosecurity-magazine.com
L
LINUX DO - 热门话题
T
Tor Project blog

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Как научить кодинг-модели не переписывать код заново
PatientZero · 2026-04-25 · via Все публикации подряд на Хабре

Как научить кодинг-модели не переписывать код заново

Уровень сложностиСредний

Время на прочтение15 мин

Охват и читатели349

Перевод

Не надо переписывать то, что не поломано

Код к этому посту доступен на Github.

Кодинг при помощи ИИ стал нормой; мы всё больше позволяем моделям наподобие Cursor, GitHub Copilot, Claude Code и Codex вмешиваться в наш код. Если вы в прошлом пользовались каким-то из этих инструментов, то, вероятно, сталкивались с чем-то подобным: вы просите модель устранить простой баг (допустим, ошибку смещения на единицу или не тот оператор). Модель устраняет баг, но половина функции оказывается переписанной. Появляется новая вспомогательная функция. Совершенно логичное имя переменной меняется на другое. Добавляется новая валидация ввода. И diff из-за этого становится огромным.

Я называю это проблемой избыточной редактуры: модели склонны переписывать код, не нуждающийся в переписывании. На самом деле, это важнее, чем может показаться. При разработке узким местом всегда становится ревью кода: ревьюерам нужно понять, что и почему поменялось, а также безопасно ли изменение. Модель, переписывающая целые функции, пусть даже корректно, существенно усложняет эту работу, потому что код теперь выглядит совершенно иначе.

В своём посте я исследую эту проблему: имеют ли современные LLM склонность к избыточной редактуре и можем ли мы обучить модели редактировать код в должной мере?

Избыточная редактура

Over-editing problem

Рисунок 1: Классический пример проблемы избыточной редактуры. GPT-5.4 (High) переписывает функцию целиком, хотя правильно было бы просто заменить range(len(x) - 1) на range(len(x)).

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

Это хорошо иллюстрирует пример с Рисунка 1. Баг заключается в ошибке смещения на единицу в вызове range() (range(len(x) - 1) должно выглядеть как range(len(x))), и правильным исправлением была бы одна строка. В своём ответе GPT-5.4 (с высокой степенью рассуждений) переписывает функцию целиком: она добавляет проверки на None, преобразования np.asarray с dtype=float, маскирование конечных значений, валидирует размеры массивов, меняет сигнатуру вызова curve_fit и полностью меняет логику построения графиков. Хоть её вывод и проходит тесты, diff получается огромным, но ни об одном из этих добавлений пользователь не просил, да они и необязательны.

Стоит подходить к этому с точки зрения типа выполняемой работы. В общих чертах разработку ПО можно разделить на два режима: создание с нуля и доработку (работу с уже имеющейся кодовой базой). Во втором случае существующий код уже понятен команде, и его намеренно писали в том виде, в котором он сейчас есть. Задача модели — устранить проблему и ничего сверх того.

При работе с ИИ-инструментами кодинга часто рекомендуют просто писать больше тестов, потому что если тест проходит, то код верный. Однако избыточная редактура при работе с уже существующей кодовой базой, в отличие от некорректности кода, невидима для наборов тестов. Когда модели генерируют новый код, разработчикам приходится выполнять больший объём ревью, а избыточная редактура усложняет эту задачу. Им приходится парсить более сложную логику и читать больше кода; при этом повышается вероятность незаметной деградации качества всей кодовой базы.

Как измерять степень избыточной редактуры

Для изучения избыточной редактуры нам сначала понадобится датасет изменений в коде, где конкретно определено «эталонное изменение» с конкретной степенью «минимальности». Вместо того, чтобы использовать другую LLM для добавления багов (как поступает большинство существующих бенчмарков), мы программным образом поломаем 400 задач из BigCodeBench, что позволит нам обеспечивать более точный контроль: например, поменяем оператор сравнения (< → <=), заменим + на - или изменим булевы значения (True → False)1. Каждый повреждённый образец остаётся синтаксически валидным, но точно не проходит соответствующие тестовые случаи. Это гарантирует, что эталонное изменение будет заключаться ровно в откате этой поломки; таким образом, это изменение минимально по построению. Тогда мы сможем оценить не только то, устранила ли модель баг, но и то, какой объём другого кода она изменит в процессе этого.

Метрики

Большинство бенчмарков кодинга оценивают модели по корректности при помощи той или иной разновидности Pass@1. Однако Pass@1 необходим, но недостаточен. Модель может получить идеальную оценку по Pass@1, при этом полностью переписав все затронутые ею функции. Для этого эксперимента нам нужны метрики, отражающие объём кода, изменённого моделью сверх необходимого.

Расстояние Левенштейна на уровне токенов. В отличие от стандартного расстояния Левенштейна, подсчитывающего минимальное количество вставок, удалений и замен символов для преобразования одной строки в другую, мы используем вариант его вычислений на Python для уровня токенов. Сначала код проходит через токенизатор Python, разбивающий его на атомарные синтаксические единицы (def, add, (, a, ,, b, ), :, return, a, +, b). Затем расстояние Левенштейна вычисляется для этой последовательности токенов, а не для сырых символов.

Например, рассмотрим следующие две функции:

def add(a, b):                    def someotherfunctionname(a, b):
    return a + b                      return a + b

Расстояние Левенштейна на уровне символов вернёт результат 19. На уровне токенов результат будет равен 1, потому что someotherfunctionname становится одним токеном. Мы выполняем нормализацию по общему количеству токенов, чтобы оценки были сравнимыми для функций разной длины.

Кроме того, вместо простого сравнения вывода модели с эталоном мы сравним то и другое с повреждёнными входными данными. Пусть C будет испорченным решением, G — эталоном, а M — выводом модели. Истинное минимальное изменение (просто откат внесённой ошибки) равно D_{\text{true}} = d(G, C), а изменение модели D_{\text{model}} = d(M, C), что даст нам относительную оценку патча:

S(M) = D_{\text{model}} - D_{\text{true}}

Близкие к нулю значения обозначают, что патч модели напоминает истинное минимальное исправление. Мы можем интерпретировать исходное неиспорченное решение, как наилучшее возможное изменение испорченного решения, вычислить оценки для этого наилучшего возможного патча, а затем сравнить их с выводом модели.

Добавленная когнитивная сложность. Когнитивная сложность (более качественная по сравнению с цикломатической сложностью оценка) измеряет сложность понимания кода. Она штрафует код за вложенность, рекурсию, смешанные логические операции и неочевидный поток управления. Например, одну строку кода без ветвлений гораздо проще читать, чем код, требующий от читающего хранить состояние, скажем, if, цикл или try/except. Вот пример:

def process(items):
    result = []
    for item in items:          # +1
        if item > 0:            # +2 (штраф за вложенность: внутри цикла)
            if item % 2 == 0:   # +3 (штраф за вложенность: двухуровневая глубина)
                result.append(item)
    return result
# Когнитивная сложность: 6

Так как все наши поломки меняют значения, а не структуру, правильное исправление всегда будет добавлять ноль когнитивной сложности. Любое увеличение объёма вывода модели появляется без желания пользователя. Мы определяем абсолютную разность между выводом модели и оригиналом, которая должна быть нулевой для истинного минимального изменения. Значения ниже 0 тоже нежелательны, потому что необязательное упрощение кода неприемлемо.

Вносят ли модели избыточную редактуру?

Да, даже самые передовые.

Модель

Pass@1 ↑

Нормализованное расстояние Левенштейна ↓

Добавленная когнитивная сложность ↓

Модели с рассуждениями

GPT-5.4

0.723

0.395

2.313

Claude Opus 4.6

0.912

0.060

0.200

Gemini 3.1 Pro Preview

0.858

0.145

0.501

GLM 5 High

0.859

0.099

0.320

Qwen 3.6 Plus

0.858

0.145

0.048

Kimi 2.5

0.835

0.151

0.770

DeepSeek R1

0.820

0.232

0.673

DeepSeek Chat V3.1

0.795

0.232

0.694

GPT-5 High

0.713

0.438

3.832

Модели без рассуждений

GPT-5.4

0.770

0.327

1.563

Claude Opus 4.6

0.900

0.079

0.313

Gemini 3.1 Pro Preview

0.860

0.129

0.358

GLM 5

0.840

0.097

0.235

Qwen 3.6 Plus

0.870

0.106

0.605

Kimi 2.5

0.770

0.140

0.687

DeepSeek V3

0.800

0.201

0.803

DeepSeek Chat V3.1

0.802

0.235

1.223

GPT-5 Minimal

0.738

0.397

2.877

Таблица 1: Сравнение результатов рассуждающих и не рассуждающих моделей. Модели, встречающиеся в обоих разделах — гибридные. Наилучшие оценки каждой метрики выделены полужирным шрифтом.

Среди новых передовых моделей больше остальных склонна к избыточной редактуре GPT-5.4. Она имеет расстояние Левенштейна 0,39 в режиме рассуждений и 0,33 в режиме без рассуждений; её добавленная когнитивная сложность равна, соответственно, 2,31 и 1,56. Несмотря на это, её Pass@1 равен всего 0,723 и 0,770, из-за чего она одна из худших по корректности. Claude Opus 4.6 достигает наибольшего Pass@1 среди всех протестированных моделей (0,912 с рассуждениями, 0,900 без рассуждений), при этом обеспечивая наименьшие diff с расстояниями Левенштейна 0,06 и 0,08, добавленной когнитивной сложностью 0,20 и 0,31. Gemini 3.1 Pro Preview находится в похожей ситуации, а GLM 5, похоже, самая консервативная из моделей с открытыми весами.

Помогает ли промптинг?

Во многих научных статьях, утверждающих о нахождении нового режима отказа LLM, не выполняется предварительное тестирование того, может ли модель выполнить задачу, если её попросить напрямую. Поведение, кажущееся невозможным при одной схеме, может оказаться легко реализуемым при явном промпте, поэтому я исследовал влияние добавления в промпт инструкции «IMPORTANT: Try to preserve the original code and the logic of the original code as much as possible» («ВАЖНО: Старайся максимально сохранять оригинал кода и логику оригинала кода»).

Reasoning vs Non-Reasoning

Рисунок 2: Изменения в Pass@1 и расстоянии Левенштейна, когда моделям специально указывают в промпте необходимость минимальных изменений.

При явном промптинге все модели улучшают показатели и снижают расстояние Левенштейна, и улучшают свой Pass@1 (за исключением DeepSeek R1/v3). Можно интерпретировать это так, что, ограничивая модель внесением минимальных изменений, мы непреднамеренно сужаем пространство поиска возможных исправлений, направляя модели в сторону точных нацеленных изменений, которые будут правильными с наибольшей вероятностью. Влияние на расстояние Левенштейна наиболее выражено в моделях с рассуждениями; вероятно, это результат того, что они умеют строже придерживаться инструкций.

Приводят ли рассуждения к чрезмерным размышлениям и избыточной редактуре?

В общем случае считается, что модели с рассуждениями лучше справляются с задачами кодинга, и они действительно имеют более высокие оценки в Pass@1. Но поскольку нам любопытен стиль этих изменений, нужно взглянуть на результаты под другим углом.

Reasoning vs Non-Reasoning

Рисунок 3: Сравнение расстояний Левенштейна у моделей с рассуждениями и без рассуждений. Модели сгруппированы в пары из одной с рассуждениями и другой без рассуждений. Чем ниже столбцы, тем лучше. Метки над каждой парой обозначают количество задач, в которых обе модели получили правильный ответ.

На Рисунке 3 модели сгруппированы в пары, каждая из которых содержит модель с рассуждениями и без них из одного и того же семейства. Для каждой пары мы создаём график расстояния Левенштейна только для тех образцов, в которых обе модели получили правильный ответ. Это позволяет нам изолировать минимальность изменений от корректности, поскольку чаще ошибающаяся модель имеет меньше образцов для избыточной редактуры, что могло бы привести к перекосу сравнений.

В общем случае (верхняя часть Рисунка 3) модели с рассуждениями больше склонны к избыточной редактуре, чем модели без рассуждений. У DeepSeek V3, GPT-5, GPT-5.4, Gemini 3.1 Pro Preview, Qwen 3.6 Plus и Kimi 2.5 столбец модели с рассуждениями выше. Похоже, модели с рассуждениями естественным образом выполняют более сложное переписывание, при котором модель рассуждениями приходит к «лучшей» реализации, чем минимальное исправление. Примечательным исключением стал Claude Opus 4.6, у которого модель с рассуждениями редактирует существенно меньше.

В ситуации с явным промптом (нижняя часть) картина существенно меняется. Когда моделям чётко приказывают сохранить оригинальный код, у моделей с рассуждениями расстояние Левенштейна существенно меньше, чем у моделей без, они сравнимы или лучше них почти в каждой паре. Расстояния Левенштейна Claude Opus 4.6 (с рассуждениями) упали ниже, чем у всех других моделей в этой ситуации. У GPT-5 и GPT-5.4 с рассуждениями столбцы снизились, однако GPT-5.4 без рассуждений всё равно чуть-чуть их лучше.

Следовательно, можно сделать вывод, что по умолчанию большинство моделей с рассуждениями склонно к избыточной редактуре. Если не поставить перед ними ограничений, расширенные рассуждения дают моделям больше пространства для «улучшения» кода, не требующего улучшений. Но та же способность к рассуждениям позволяет им лучше соблюдать ограничения, если они заданы. Разница между общим случаем и явным указанием промпта для моделей с рассуждениями существенно больше; из этого можно сделать вывод, что избыточная редактура — не фундаментальная особенность, а поведение по умолчанию, которое можно изменить.

Обучение

Естественным образом возникает следующий вопрос: можно ли обучить модели, чтобы они были более точными редакторами? В этом эксперименте я в качестве базовой модели взял Qwen3 4B 2507 Instruct. В качестве отправной точки я использовал вместе промптинг 0-shot и 8-shot, в явном виде приказав сохранять оригинальный код. Во всех остальных методиках во время оценки использовался общий случай без явных инструкций в промпте.

Схема

Сначала я при помощи описанного выше подхода создал синтетический датасет испорченных задач из DeepCoder. В дополнение к этому программно сгенерированному датасету я при помощи модели Qwen3 4B 2507 Instruct создал синтетический датасет путём самодистилляции. Я попросил модель в промпте сгенерировать по 8 завершений на задачу, оставив только функционально корректные образцы и ранжировав их по расстоянию Левенштейна. Затем модель была обучена без явных инструкций, аналогично Context Distillation.

Мы оценили четыре методики:

  • SFT: fine-tuning с учителем на программно сгенерированном датасете.

  • rSFT: Rejection-sampled SFT, при котором мы обучали наши завершения с тремя наименьшими расстояниями Левенштейна на каждый образец из датасета самодистилляции.

  • DPO: оптимизация предпочтений между завершениями с наибольшим и наименьшим расстоянием Левенштейна для каждого примера из набора данных само-дистилляции.

  • RL: обучение с подкреплением с вознаграждением, объединяющим в себе функциональную корректность и минимальность правок на основе расстояния Левенштейна. Структура вознаграждения представляет собой взвешенную сумму расстояния Левенштейна и штрафа за непрохождение тестовых случаев.:

r = r_edit + 0.1   # если генерация проходит все тестовые случаи
r = -0.2           # в противном случае
 
# r_edit - нормализованное вознаграждение на основании расстояния Левенштейна

Сработало ли это?

Модель

Pass@1 ↑

Нормализованное расстояние Левенштейна ↓

Добавленная когнитивная сложность ↓

Базовая (0-shot)

0.735

0.169

0.731

Базовая (8-shot)

0.775

0.115

0.479

SFT

0.932

0.002

0.000

rSFT

0.782

0.100

0.435

DPO

0.752

0.021

0.113

RL

0.802

0.046

0.112

Таблица 2: Сравнение результатов различных методик fine-tuning при обучении на данных предметной области: обучающий и тестовый датасеты содержат одни и те же типы испорченного кода.

При первой попытке подозрительно хорошо проявил себя SFT: получившаяся модель как будто идеально научилась задаче. Мне показалось это крайне удивительным; моя первая гипотеза заключалась в том, что модель просто запоминала состояние, обратное этому датасету испорченных решений, а не обучалась общему поведению минимального редактирования. В результате этого я пересоздал синтетические датасеты, но для проверки модели на обобщённость использовал датасет испорченных решений, полностью отличающейся от оценочного датасета. Базовая гипотеза заключалась в том, что модель просто обучилась обращать определённый набор действий.

Обобщается ли эта задача?

Модель

Pass@1 ↑

Нормализованное расстояние Левенштейна ↓

Добавленная когнитивная сложность ↓

Изменение LiveCodeBench ↓

Базовая (0-shot)

0.735

0.169

0.731

Базовая (8-shot)

0.775

0.115

0.479

SFT

0.458

−0.008

0.006

−0.149

rSFT

0.780

0.107

0.501

−0.069

DPO

0.787

0.092

0.348

−0.046

RL

0.782

0.050

0.185

+0.006

Таблица 3: Сравнение результатов разных методик fine-tuning при обучении на данных вне предметной области: в обучающем и тестовом датасете содержатся разные типы порчи кода.

Вне предметной области результаты SFT резко ухудшаются. Pass@1 падает до 0,458, потому что модель обучилась вносить конкретные минимальные изменения вне зависимости от того, исправляют ли они что-нибудь. rSFT и DPO лучше, но общее улучшение по сравнению с отправными данными 8-shot незначительное. Это говорит о том, что обучения на данных, извлечённых из самой базовой модели, достаточно, чтобы добиться некоторой степени обобщения. RL — единственная правильно обобщаемая методика, улучшающая все три метрики относительно базовой модели. То, что модель с RL сильнее улучшилась в отношении расстояния Левенштейна и добавленной когнитивной сложности, чем Pass@1 — дополнительное свидетельство того, что она не просто запоминает данные, обратные испорченным, а на самом деле обобщается до минимальной редактуры.

Учитывая неспособность модели с SFT даже устранять баги, мы также захотели взглянуть на показатель катастрофического забывания (Catastrophic Forgetting). В частности, узнать, приводит ли fine-tuning под минимальную редактуру к деградации общие способности к кодингу. Мы проверили все модели с fine-tuning на LiveCodeBench v6 и сравнили результаты с исходной предварительно обученной моделью. В идеале после обучения производительность должна быть схожей.

SFT продемонстрировала деградацию показателей на 43%, что согласуется с нашим предыдущим наблюдением о том, что модель больше не может выявлять и устранять простые баги. Модели с rSFT и DPO подверглись небольшой деградации; это показывает, что несмотря на их обучение на образцах, сгенерированных исходной моделью, сама природа задачи приводит к определённой степени катастрофического забывания. Модель с RL не показала никакой деградации. Если также учесть то, что она лучше всех справляется с задачей, RL способно обучать модель новому поведению, не приводя к деградации обретённых ранее способностей. Это согласуется с прошлыми исследованиями, демонстрирующими, что SFT запоминает, а RL обобщает.

На основании других работ, показавших, что RL имеют перекос в сторону KL-минимальных решений, снижающий забывание, мы интерпретировали эти результаты с точки зрения распределения. В частности, распределение программно сгенерированного датасета сильно отличается от исходного распределения модели. В результате этого распределения модели с SFT сильно изменились, а потому страдают от катастрофического забывания. В случае же rSFT и DPO распределение самодистиллированного датасета более выровнено, а потому меньше влияет на формирование распределения обученной модели. Следовательно, вероятно то, что степень катастрофического забывания пропорциональна разности между исходным распределением модели и распределением обучающих задаче данных.

Дополнительные эксперименты

RL с LoRA: нужен ли нам полный Fine-Tuning?

Учитывая то, что эта задача связана больше не с обучением модели новым знаниям, а с подстройкой её стиля под готовую задачу, мы также захотели исследовать, достаточно ли будет для этого LoRA. Так как базовая модель уже обладает способность редактирования кода и устранения багов, полный fine-tuning может и не потребоваться.

Ранг

Pass@1 ↑

Нормализованное расстояние Левенштейна ↓

Добавленная когнитивная сложность ↓

Дельта LiveCodeBench ↑

1

0.738

0.166

0.676

-0.022

8

0.775

0.112

0.426

-0.022

16

0.805

0.087

0.328

-0.005

32

0.795

0.065

0.235

-0.011

64

0.797

0.051

0.160

+0.001

Полное RL (лучшее)

0.782

0.050

0.185

+0.006

Таблица 4: Сравнение показателей разных рангов LoRA.

Результаты подтверждают эту гипотезу. LoRA при ранге 64 почти соответствует RL по расстоянию Левенштейна и превосходит его по добавленной когнитивной сложности. Показатели LiveCodeBench немного снижаются при малых рангах, но ранг 64 практически плоский, а полное RL в целом остаётся лучшим. С увеличением ранга наблюдается чёткий монотонный тренд: расстояние Левенштейна и добавленная когнитивная сложность стабильно снижаются с ранга 1 по ранг 64. Впрочем, скорость улучшений не равномерна; наибольшее снижение происходит на ранних этапах. Наибольший вклад в снижение расстояния Левенштейна вносят ранги с 1 по 16 (0,166 → 0,087), а ранги с 16 по 64 уменьшают оставшийся разрыв более плавно (0,087 → 0,051). Кроме того, на рангах с 1 по 8 происходит снижение корректности в обмен на минимальность редактуры; это может быть объяснено недостатком способности обучаться обеим функциям вознаграждения; происходит перекос модели в сторону минимальности редактуры, обеспечивающей большее вознаграждение.

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

Примечание о хакинге вознаграждений

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

Масштабируется ли этот подход?

Для валидации результатов с моделями большего размера я применил ту же схему RL, использовав данные вне предметной области в модели Qwen3 14B. Даже при большем количестве параметров все показатели улучшаются: повышается Pass@1, снижается расстояние Левенштейна, снижается добавленная когнитивная сложность и отсутствуют признаки катастрофического забывания. Это даёт мне уверенность в том, что такую схему для задачи минимальной редактуры кода можно расширить на различные модели разных масштабов.

Модель

Pass@1 ↑

Нормализация расстояния Левенштейна ↓

Добавленная когнитивная сложность ↓

Дельта LiveCodeBench ↑

Базовая: 14B

0.770

0.136

0.315

-

RL

0.833

0.059

0.165

+0.011

Таблица 5: Сравнение показателей RL при обучении Qwen3 14B.

В заключение

Примечание о GPT 5.4 и Opus 4.6

Стоит отметить, что, несмотря на современность модели, GPT 5.4 испытывает трудности с задачей минимальной редактуры, особенно при обобщённой схеме и относительно Opus 4.6. Однако Рисунок 3 демонстрирует, что у неё происходит наибольшее улучшение показателей при явном указании промпта в режиме рассуждений; её опережает только её предшественница GPT 5, из чего можно сделать вывод о сильных способностях следования инструкциям. Для сравнения: Opus 4.6 демонстрирует одни из наименьших улучшений показателей; впрочем, это просто может отражать и так хорошие базовые показатели. Этот паттерн соответствует представлению о том, что хоть GPT 5.4 часто по умолчанию склонна к генерации излишне многословного кода («слопа»), её поведением можно эффективно управлять при помощи промптинга.

Исходя из всего вышесказанного, результаты говорят о том, что избыточная редактура широко распространена и её можно измерить. В то же время, результаты промптинга показывают, что это не исключительно ограничение способностей. Простая инструкция о необходимости сохранения оригинального кода приводит к гораздо более качественной редактуре, особенно у моделей с рассуждениями; это многообещающий признак того, что когда модели наподобие GPT 5.4 редактируют слишком большой объём кода, качество их работы можно повысить.

Кроме того, из результатов обучения можно сделать вывод, что такое поведение можно улучшить. Обучение с подкреплением привело к внесению более качественных изменений без деградации общей способности к кодингу, и эти улучшения воспроизводились в моделях Qwen3 4B и 14B.

Сфера бенчмарков кодинга перешла от оценок простых единичных функций к более агентским парадигмам оценки наподобие SWE-Bench Pro. Относительно них оценка устранений багов в изолированных функциях по-прежнему остаётся довольно компактной задачей, учитывая природу багов.

Но даже при этом, несмотря на преобладание избыточной редактуры во всех современных моделях кодинга, уже долгое время было сложно оценить её численно в реалистичных условиях. Надеюсь, наша работа станет первым шагом к оценке и совершенствованию способности кодинг-моделей к минимальной редактуре, а в конечном итоге и к повышению общего качества генерируемого ИИ кода.


  1. Полный список внесённых изменений можно найти в коде.