Основная «придумка» эксперимента:
- выбрать задачу, которая редко встречается в повседневной практике, чтобы не получить решение из запасников.
- взять пару-тройку бесплатных или недорогих ИИ-агента и сравнить результат.
Что б «дёшево и сердито», для первого опыта.
Выбор задачи.
Утверждение «Оно само пишет рабочий код и запросы» - на мой взгляд, нуждается в проверке.
Пару месяцев назад мне как раз попалась такая задача, на которую янд.Алиса чётко и безапелляционно выдала несуществующие в 1С операторы запросов и подкрепила ссылкой на страницу с контентом, явно нашлепанным с помощью ИИ. Пришлось отлаживать самостоятельно.
В задаче требовалось сделать функцию для HTTP-сервиса с пагинацией (постраничной выдачей) цен и свободных остатков. Хорошая задачка, несложная и нетиповая, возьмём за основу.
По результатам статей на форумах за последние месяцы понял, что для уверенной работы ИИ нужен будет MCP-сервер (хотя бы на метаданные конфы). В мои планы и ресурсы такой узел схемы для экспериментов не подходил.
А что если попросить выборку по объекту, который ИИ, уж точно знает? Справочник Номенклатура и его самые популярные реквизиты!
Ну, и для пущего упрощения: не требовать JSON, получать результат в виде таблицы значений.
Получится такая проверятельная, обаятельная «сферическая лошадь в вакууме массой в один килограмм» (benchmark, репер)
Выбор ИИ-агентов
Агент СМИТ найден не был, «эка незадача» этим нас не остановишь, ну что я Neo какой-нибудь
Удалось зарегистрироваться на Gemini-Pro, Qwen, GROQ
Можно начинать эксперимент.
Промпт
нужен код функции на языке 1С (BSL) производящей Пагинацию выборки Номенклатуры.
Выполнение на сервере.
Входящие параметры: КоличествоПозицийНаСтраницу, НомерСтраницы.
Запросом выбираем элементы из Справочника Номенклатура.
Поля результата Наименование, Код, Артикул, ЕдиницаИзмерения
Результат функции - таблица значений с числом строк = КоличествоПозицийНаСтраницу, и взятое из страницы с номером = НомерСтраницы.
Результаты генерации
публикую комментарии к полученному коду и наиболее успешные результаты генерации
GROQ (объявил использование qwen3.6 120b)
GROQ не стал мудрить, взял в запрос весь справочник и при выборке в цикле пропускал лишние строки, а для нужных позиций создавал строку в таблице значений.
Правда в выдаче почему-то не завершил Функцию и Цикл, хотя в рассуждениях всё было.
Код с грубыми ошибками, больше похожий на гибрид 1с 8 и 1с 7.7
Итог: неэффективные запрос и код; код нерабочий.
Qwen-coder
Примитивный запрос с фантомными операторами от SQL
Оптимально по размеру текста, но работать в 1С 8 не будет
Похоже, что агент рассчитан на веб-разработку и то, что к ней прилежит.
Итог: запрос с ошибками; код нерабочий.
Gemini-PRO
Разные запросы и ветви логики для первой и остальных страниц
два вложенных запроса со встречной сортировкой на предварительную выборку и на вхождение для ГДЕ т.е. два множества Отбираем (из них взять первые КоличествоНаСтраницу) и не брать из выборки «Пропускаем».
Может и не оптимально, но логически стройно.
Проверка НЕ выявила прямых ошибок в коде и в запросе (!)
В запросе использована сортировка по Номенклатура.Ссылка (совершенно справедливо)
Явно недостаёт использования параметров запроса, в остальном всё хорошо.
Не оптимальный, НО работоспособный и код и запрос.
Код функции и комментарии агента
В языке запросов 1С:Предприятие нет прямых операторов OFFSET или LIMIT. Для эффективной серверной пагинации используются конструкции ПЕРВЫЕ N и соединение/вложенный запрос для отсечения предыдущих страниц.
Ниже представлен оптимальный вариант с отсечением по уникальному ключу (Ссылка) и детерминированной сортировкой:
Фрагмент кода
&НаСервере
Функция ПолучитьСтраницуНоменклатуры(Знач КоличествоПозицийНаСтраницу, Знач НомерСтраницы) Экспорт
// Валидация входных параметров
Если КоличествоПозицийНаСтраницу <= 0 Тогда
КоличествоПозицийНаСтраницу = 20;
КонецЕсли;
Если НомерСтраницы <= 0 Тогда
НомерСтраницы = 1;
КонецЕсли;
Запрос = Новый Запрос;
// Для первой страницы достаточно простого ограничения ПЕРВЫЕ N
Если НомерСтраницы = 1 Тогда
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ " + Формат(КоличествоПозицийНаСтраницу, "ЧГ=0") + "
| Номенклатура.Наименование КАК Наименование,
| Номенклатура.Код КАК Код,
| Номенклатура.Артикул КАК Артикул,
| Номенклатура.ЕдиницаИзмерения КАК ЕдиницаИзмерения
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| НЕ Номенклатура.ЭтоГруппа
| И НЕ Номенклатура.ПометкаУдаления
|УПОРЯДОЧИТЬ ПО
| Номенклатура.Наименование ВОЗР,
| Номенклатура.Ссылка ВОЗР";
Иначе
// Общее количество записей до конца целевой страницы
ВсегоДоКонцаСтраницы = КоличествоПозицийНаСтраницу * НомерСтраницы;
// Количество записей, которые нужно пропустить
КоличествоПропускаемых = КоличествоПозицийНаСтраницу * (НомерСтраницы - 1);
// Выбираем N первых записей целевого среза и отсекаем те, что входят в предыдущие страницы
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ " + Формат(КоличествоПозицийНаСтраницу, "ЧГ=0") + "
| Выборка.Наименование КАК Наименование,
| Выборка.Код КАК Код,
| Выборка.Артикул КАК Артикул,
| Выборка.ЕдиницаИзмерения КАК ЕдиницаИзмерения
|ИЗ
| (ВЫБРАТЬ ПЕРВЫЕ " + Формат(ВсегоДоКонцаСтраницы, "ЧГ=0") + "
| Номенклатура.Наименование КАК Наименование,
| Номенклатура.Код КАК Код,
| Номенклатура.Артикул КАК Артикул,
| Номенклатура.ЕдиницаИзмерения КАК ЕдиницаИзмерения,
| Номенклатура.Ссылка КАК Ссылка
| ИЗ
| Справочник.Номенклатура КАК Номенклатура
| ГДЕ
| НЕ Номенклатура.ЭтоГруппа
| И НЕ Номенклатура.ПометкаУдаления
| УПОРЯДОЧИТЬ ПО
| Номенклатура.Наименование ВОЗР,
| Номенклатура.Ссылка ВОЗР) КАК Выборка
|ГДЕ
| Выборка.Ссылка НЕ В
| (ВЫБРАТЬ ПЕРВЫЕ " + Формат(КоличествоПропускаемых, "ЧГ=0") + "
| ПредСтраницы.Ссылка
| ИЗ
| Справочник.Номенклатура КАК ПредСтраницы
| ГДЕ
| НЕ ПредСтраницы.ЭтоГруппа
| И НЕ ПредСтраницы.ПометкаУдаления
| УПОРЯДОЧИТЬ ПО
| ПредСтраницы.Наименование ВОЗР,
| ПредСтраницы.Ссылка ВОЗР)
|УПОРЯДОЧИТЬ ПО
| Выборка.Наименование ВОЗР,
| Выборка.Ссылка ВОЗР";
КонецЕсли;
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
Ключевые технические нюансы реализации:
Детерминированность выборки: В секции УПОРЯДОЧИТЬ ПО обязательно присутствует Ссылка. Если сортировать только по неуникальному полю (Наименование), СУБД может произвольно менять порядок строк с одинаковыми именами между запросами, что приведёт к дублированию или потере строк между страницами.
Форматирование чисел: Формат(..., "ЧГ=0") обязателен при подстановке чисел в текст запроса, чтобы избежать появления неразрывных пробелов-разделителей тысяч (например, 1 000).
Отсечение групп и мусора: По умолчанию добавлен фильтр НЕ ЭтоГруппа И НЕ ПометкаУдаления (если требуется выбирать папки или удаленные элементы, условия можно скорректировать).
Итог: Сразу работоспособный код и запрос. Оптимизация явно нужна.
Qwen3.7-Plus
При первой выдаче
использование вложенного запроса вместо создания виртуальной таблицы.
использование фантомных операторов запроса типа НомерЗаписи или АвтоНомер
Этот вариант показался пригодным к доработке
После пяти итераций с моими явными указаниями
- использование корректного оператора для внутреннего ранжирования выборки,
- использование временной таблицы,
- сортировка по «ссылка» вместо «код»,
- выборка во временную таблицу ссылку вместо реквизитов,
- использование обращения к вложенным реквизитам,
- понятного названия таблиц/переменных
получился вполне компактный и оптимизированный запрос
Код функции
&НаСервере
Функция ПолучитьНоменклатуруПоСтраницам(КоличествоПозицийНаСтраницу, НомерСтраницы) Экспорт
// Рассчитываем диапазон строк для текущей страницы
НачальнаяПозиция = (НомерСтраницы - 1) * КоличествоПозицийНаСтраницу + 1;
КонечнаяПозиция = НомерСтраницы * КоличествоПозицийНаСтраницу;
// Объединяем оба запроса в один пакет
ТекстЗапроса =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка,
| АВТОНОМЕРЗАПИСИ() КАК НомерСтроки
|ПОМЕСТИТЬ втНоменклатура
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|УПОРЯДОЧИТЬ ПО
| Номенклатура.Ссылка
|;
|
|ВЫБРАТЬ
| втНоменклатура.Ссылка.Наименование КАК Наименование,
| втНоменклатура.Ссылка.Код КАК Код,
| втНоменклатура.Ссылка.Артикул КАК Артикул,
| втНоменклатура.Ссылка.ЕдиницаИзмерения КАК ЕдиницаИзмерения
|ИЗ
| втНоменклатура КАК втНоменклатура
|ГДЕ
| втНоменклатура.НомерСтроки МЕЖДУ &НачальнаяПозиция И &КонечнаяПозиция";
Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("НачальнаяПозиция", НачальнаяПозиция);
Запрос.УстановитьПараметр("КонечнаяПозиция", КонечнаяПозиция);
// Выполняем пакет запросов и возвращаем результат второго запроса
Результат = Запрос.ВыполнитьПакет();
Возврат Результат[1].Выгрузить();
КонецФункции
Итоги: Качественный запрос, работающий код процедуры получены за 20 минут. Основное время – мои проверки в 1С.
Приемлемый результат получен только благодаря моему знанию: «какой должен быть оптимальный запрос».
Общие выводы:
Получаемый сразу от ИИ-агента код - неоптимальный,
но, возможно, что агент подстроится к регулярным требованиям.
Если бы я использовал такой метод работы в реальном проекте, то потратил бы больше времени на разбор ошибок, поскольку «идеи чужие, и сначала надо поймать идею, а уж потом следующую из неё ошибку».
Вот в этот раз: не сразу понял логику от Gemini, а потому результат смог правильно оценить только на следующий день :)
И тут выявляется ещё один подводный камень работы с ИИ: легко можно получить работающий код с неполноценной логикой.
Тогда получается, что к ИИ-кодировщику обязательно подцеплять ИИ-тестировщика; что для нетиповых проектов будет довольно накладно по вычислительным ресурсам и по времени. А настройка ИИ-тестировщика, как понимаю, это отдельная серьёзная задача.
Хотя, возможно, скоро появятся готовые сборки инструмента, затем они станут стандартными ...
и профессия архитектора-разработчика 1С станет архаикой, как индивидуальный пошив обуви в наши дни
Но, сегодня все свои проекты продолжу разрабатывать и кодировать так, как делал раньше.
Благодарю за уделённое внимание.
До встречи на Инфостарте!