Нейросеть для проверки кода 1С: как проверить её на своём коде до внедрения
Иван Недомолков · Dərc edilib:
Отдать ревью кода 1С нейросети хочется каждому, кто разбирал чужую обработку на тысячу строк. Справится ли модель, по отзывам не понять: нужен код, про который заранее известно, где дефект есть и где его нет, и подсчёт ответов.
Мы так проверяли локальную Qwen2.5-Coder 7B. На двадцати коротких процедурах, написанных для замера, она нашла 11 дефектов из 13, а на шестнадцати процедурах из рабочих обработок, с тем же заданием, 0 из 5. Искать дефекты в рабочем коде модель у нас не смогла. Объяснять находки анализатора может, и имён при этом не выдумывает. Выборка маленькая, код у вас другой, поэтому ниже порядок приёмки, по которому мы теперь проверяем модель, прежде чем пустить её в ревью.
Что считать: полнота и шум порознь
Полнота - сколько известных дефектов модель назвала правильным правилом. Шум - сколько правил она назвала там, где дефекта нет: на чистых процедурах и на дефектных сверх размеченного. В один балл их не сводят, потому что хорошее значение любого из них по отдельности получает и модель, которая код не читает:
| Как отвечает модель | Полнота | Шум | Пример из наших прогонов |
|---|---|---|---|
| перечисляет весь каталог | высокая | почти весь каталог | Qwen2.5-Coder 3B: 11 из 13 и 194 правила на 7 чистых процедурах при потолке 196 |
| на всё отвечает “код корректен” | ноль | ноль | qwen2.5:3b и qwen2.5-coder:7b без каталога правил: 17 таких ответов из 18 на коде с дефектом |
| разбирает код | зависит от набора | единицы | Qwen2.5-Coder 7B: 11 из 13, на чистых ни одного правила |
По полноте 3B сравнялась с 7B. Молчание на чистом коде засчитывается только модели, которая говорит что-то на дефектном: в прогоне без каталога в запросе стояло “если проблем нет - прямо скажи, что код корректен”, и модели выбирали этот ответ почти всегда.
Заведите на прогон четыре счётчика: найдено из N дефектных, лишних правил на дефектных, правил на чистых, чистых без единого правила. Спорные позиции в них не входят и считаются отдельно.
Проверочный набор из своих процедур 1С
Для первого прогона хватит двадцати процедур из рабочих обработок, взятых как есть: половина с дефектом, который вы назовёте правилом из каталога, половина чистых. Берите вразброс по списку. Когда мы гоняли анализ по сотне чужих обработок, брали каждую девятнадцатую, потому что при сортировке по имени подряд шли однотипные по автору и теме.
Чистая процедура без единого подозрительного места проверяет только умение молчать. Полезнее та, где поиск по тексту сработал бы зря: на ней видно, читает модель код или реагирует на слова.
| Что в коде | На что похоже | Почему дефекта нет |
|---|---|---|
КомпоновщикМакета.Выполнить(...) в цикле | запрос в цикле | макет собирается в памяти |
Счётчик = Счётчик + 1 в цикле | накопление строки | переменная числовая |
ДвоичныеДанные.Записать(Путь) в цикле | запись объекта в цикле | пишется файл на диск |
Исключение с записью в журнал и ВызватьИсключение | пустой блок Исключение | ошибка не теряется |
Откуда такие ловушки в рабочем коде и как их снимает разбор лексером и парсером, подробно в статье про анализ кода внешних обработок. Разметку ведите таблицей: процедура, вердикт (дефект, чисто или спорно), правило.
Стенд: локальная нейросеть для 1С на llama.cpp
| Что | Наш вариант |
|---|---|
| Запуск | llama.cpp под Windows: архив вида llama-bXXXXX-bin-win-cpu-x64.zip на 18 МБ, для видеокарты вариант vulkan на 33 МБ, CUDA не нужна. У нас сборка b10569 |
| Модель | Qwen2.5-Coder-7B-Instruct, формат GGUF, квант q4_K_M, 4,4 ГБ, лицензия Apache 2.0 |
| Машина | ноутбук 2019 года: i7-9750H, 6 ядер, 16 ГБ, GTX 1650 на 4 ГБ |
llama-server.exe -m qwen25-coder-7b-q4km.gguf --host 127.0.0.1 --port 8080 -t 6 -ngl 0 -c 16384
Имя файла модели у нас своё, подставьте ваше. Ключ -ngl 0 держит все слои на процессоре. Окна 8192 учебным процедурам хватало, под рабочие длиной до 378 строк мы подняли его до 16384. Запрос шёл на /v1/chat/completions с температурой 0,1, каталог ниже сокращён:
[система]
Ты ревьюер кода на встроенном языке 1С (BSL). Отвечай только по делу, без вступлений и без похвалы. Если дефекта нет, так и скажи.
[пользователь]
Ниже каталог антипаттернов и процедура на языке 1С.
КАТАЛОГ:
PERF001 | Blocker | Запрос к СУБД выполняется внутри цикла
PERF002 | Critical | ПолучитьОбъект() или Записать() внутри цикла
REL003 | Blocker | НачатьТранзакцию без ОтменитьТранзакцию в обработчике исключения
(всего 28 строк: 21 правило по модулям и 7 по схемам компоновки)
ПРОЦЕДУРА:
(текст процедуры целиком)
Назови идентификаторы правил из каталога, которые нарушены в этой процедуре. Если не нарушено ни одного, ответь ровно словом ЧИСТО. Формат ответа: первая строка - только идентификаторы через запятую либо слово ЧИСТО. Ниже одной строкой пояснение.
Разбирается первая строка ответа. Сервер удобнее разового запуска llama-cli: отдаёт готовый JSON без баннера и эха запроса и держит модель в памяти между вызовами.
Время разбора рабочих процедур, 7B на процессоре, один прогон без повторов:
| Строк в процедуре | Секунд |
|---|---|
| 13 | 23 |
| 24 | 38 |
| 78 | 134 |
| 79 | 89 |
| 152 | 197 |
| 219 | 258 |
| 250 | 370 |
Процедуры на 78 и 79 строк разошлись в полтора раза, так что по длине время прикидывается грубо. Весь рабочий набор из 16 процедур занял 29 минут, на двадцать своих закладывайте около часа.
Видеокарта ускоряет, но не на порядок. На GTX 1650 поместились 18 слоёв модели из 28, на 24 кончилась память под кэш контекста, а медиана короткого вызова с ответом до 160 токенов упала с 11,4 до 7,0 секунды.
Четыре проверки, которые ловят ложный результат
Сломанный замер выдаёт правдоподобные числа. До сводки прочитайте целиком хотя бы три сырых ответа модели, потом пройдите четыре проверки. Каждая у нас хоть раз сработала.
1. Модель пересказывает каталог
Признаки:
- в одном ответе 20 правил и больше при каталоге из 28;
- на разных процедурах один и тот же ответ (одинаковое ЧИСТО на чистых не в счёт);
- правила схем компоновки названы на тексте модуля;
- названы идентификаторы, которых в каталоге нет.
У Qwen2.5-Coder 1.5B сработали все четыре: 20 и больше правил в 13 ответах из 20, шесть разных ответов на двадцать процедур, правила компоновки в 13 ответах, несуществующий STD004 в 12. Пересчитайте полноту без таких ответов:
| Qwen2.5-Coder | Найдено | Без пересказа каталога |
|---|---|---|
| 1.5B | 9 из 13 | 1 из 13 |
| 3B | 11 из 13 | 1 из 13 |
| 7B | 11 из 13 | 10 из 13 |
7B сорвалась один раз, на процедуре с запросом в цикле: перечислила все 28 идентификаторов с пояснением, что нарушены все антипаттерны. Модель не может не ответить, она продолжает текст, а весь каталог лежит у неё прямо в запросе. Почему так, разобрано в статье про пять вещей, которые ломаются при подключении нейросети к 1С, а механику можно пройти отладчиком в учебной модели на встроенном языке. Почему ответ модели съезжает в перечисление и повтор, показывает карта её внимания, снятая на встроенном языке. По двенадцати стадиям обучения модели того же устройства видно, как она от случайных букв приходит к уверенным ответам, в том числе на вопросы, которым её не учили.
2. Ошибка в собственной разметке
Признак: независимый разбор не согласен с вашей разметкой хотя бы в одной позиции.
Учебные процедуры мы написали и разметили сами, потом прогнали через свой анализатор. На ловушке под транзакцию без отката он сработал: откат там был, но в цикле стоял Запись.Записать(). Позицию переразметили в дефект записи в цикле. Вердикт спорный: запись менеджером записи в цикле по небольшому регистру настроек бывает вполне обычной практикой, и у себя такое место лучше вести в спорных.
Рабочий набор размечали три независимых прохода языковой модели с поручением опровергнуть каждый вердикт, так что эталон отчасти сделан моделью. Опорой служит анализатор без ИИ, калиброванный на этих позициях: с вердиктами он согласен.
Что делать: сверить разметку с независимым разбором или вторым человеком до прогона модели, спорное выносить в отдельную графу.
3. Инструмент замера врёт
Признаки:
- в ответе виден кусок вашего запроса;
- упавший вызов попал в сводку как ЧИСТО;
- процедура для набора найдена по строке кода, которая в корпусе встречается много раз;
- время разбора не растёт с длиной процедуры.
Ранний прогон через llama-cli показал 147 лишних правил на восьми чистых процедурах: утилита печатает эхо запроса перед ответом, наша чистка вывода не нашла границу ответа, и разбор выгреб из эха все 28 идентификаторов. С тех пор качество меряем через сервер, а ответ с первыми 80 символами запроса считаем браком.
Сбойный вызов, когда сервер вернул ошибку вместо ответа, повторяйте и не засчитывайте ни в полноту, ни в шум. Иначе оборванный прогон выглядит безупречной моделью: пустой ответ разбор читает как ЧИСТО.
Рабочий набор сначала собирали поиском по строке из разметки, такая строка встречалась в корпусе десятки раз, и в две позиции попали не те процедуры. Дальше позиции восстанавливали по двум независимым признакам, несовпавшие в набор не брали.
Последний признак у нас не закрыт. Две копии одной процедуры на 378 строк разобраны за 65 и 18 секунд, хотя на 250 строк ушло 370. Вторую копию сервер отдал из кэша, а прочитала ли модель первую целиком, мы не уверены. На длинных процедурах сверяйте prompt_tokens в ответе сервера с размером запроса.
4. Набор написан вами
Признаки: процедуры короткие, в каждой один дефект на виду, и на своём наборе модель находит заметно больше, чем на рабочем коде.
При том же запросе результат у нас упал с 11 из 13 до нуля. Длину и характер кода наш набор не разводит, так что причина разрыва не установлена. Учебный набор годится проверить стенд и разбор ответов, решение о внедрении принимается на рабочем коде. Набор, написанный автором, повторяет его слепые зоны, как и тесты, которые проходят при ошибке в коде.
Что вышло у нас: одна таблица и её границы
| Qwen2.5-Coder 7B | Учебные процедуры | Рабочие процедуры |
|---|---|---|
| Процедур | 20, от 9 до 25 строк | 16, от 13 до 378 строк, медиана 105 |
| Дефектов | 13 | 5 |
| Найдено правильным правилом | 11, без пересказа каталога 10 | 0 |
| Лишних правил на дефектных | 44, из них 27 в одном ответе | 2 |
| Чистых процедур | 7 | 9 ложных срабатываний поиска по тексту |
| Правил названо на чистых | 0 | 0 |
| Спорных | нет | 2 |
Из 44 лишних правил анализатор подтвердил одно. На переразмеченной процедуре 7B вдобавок к верному правилу заявила, что блок исключения не отменяет транзакцию, хотя ОтменитьТранзакцию() стоит в коде, и что процедура длиннее 125 строк при длине около двадцати.
Границы у таблицы:
- Выборка мала. 11 из 13 совместимо с настоящей полнотой от 55 до 98 процентов, 0 из 5 допускает до 52. Ноль на семи чистых не исключает шума примерно на каждой третьей чистой процедуре, а чтобы ноль означал меньше 12 процентов, чистых нужно около тридцати.
- Два из пяти рабочих дефектов - те самые копии на 378 строк. Наверняка целиком модель видела три дефекта. Один из них пустой блок
Исключениена 24 строки: там 7B назвала два правила безопасности, нарушений которых нет, а дефект пропустила, как и на учебном наборе. - Набор собран из срабатываний поиска по тексту по правилам анализатора. Ошибок смысла, которые правилом не описать, в нём нет, и про них замер ничего не говорит.
- Модели одного семейства и одна задача: поиск нарушений по готовому каталогу одним запросом. Примеры рабочего кода перед вопросом и другие формулировки мы не пробовали, облачные модели не мерили. Задачу другого рода, найти причину торможения обработки в боевой базе, мы давали трём ИИ-агентам, и диагнозы разошлись: разбор эксперимента.
Как поделить ИИ-ревью кода 1С между анализатором и моделью
У себя мы разделили так: ищет обычный разбор кода, модель объясняет найденное.
Поиск. Лексер, парсер и таблица типов переменных на одном коде всегда дают один ответ. Пустой блок Исключение и вложенность глубже пяти уровней, которые 7B пропустила на учебном наборе, разбор находит подсчётом, понимать смысл для этого не нужно. По скорости сравнивать нечего: сто чужих обработок, 100 398 строк, анализатор разобрал за 141 секунду без единого падения, а модели на одну процедуру в 250 строк нужно шесть минут. Разбор без ИИ собран в анализатор кода внешних обработок.
Объяснение. Модель получает правило, строку и процедуру и пишет, чем находка кончится на этом коде. 7B в 16 объяснениях, 13 из них по учебным процедурам, назвала 27 имён: 26 есть в коде, 27-е было предложенным именем временной таблицы. На тех ста обработках qwen2.5:3b дала 60 объяснений с 71 именем: 67 из кода, 4 искажены склонением вроде Справочникам.Склады, выдуманных нет. Проверка механическая: противоречие коду она ловит, неверный вывод о последствиях пропустит.
Починка. Рецепт исправления печатает анализатор из реестра правил. В 4 объяснениях из 60 модель дала вредный совет. Дважды она поставила ОтменитьТранзакцию() в тело Попытка вместо фиксации, и такой код откатывал бы каждую транзакцию, хотя верный рецепт лежал у неё в запросе.
Так устроен ИИ-анализ кода 1С: находки даёт движок на 37 правилах, локальная модель их объясняет. Если модель будет писать код или запросы под вашу конфигурацию, ей нужны настоящие имена объектов, иначе она достроит их по памяти. Как их собрать, разобрано в статье про выгрузку метаданных для нейросети. Принимать её запросы стоит тем же способом, каким мы принимали ревью, на наборе с известным ответом: для УТ 11.5 такой набор уже собран в стенд проверки запросов нейросети, и локальную модель он подключает по OpenAI-совместимому адресу.
Проверить модель на коде вашей базы или поставить разбор чужих обработок перед выкаткой мы можем в рамках оптимизации и доработки 1С. Если нейросетью в компании пользуются не только разработчики и каждый проверяет ответы по-своему, общие правила проверки разбираем с командой на её рабочих задачах: практическое обучение нейросетям.