Вызываем LLM из нативного кода 1С: Предприятие (внешняя обработка, HTTP-запрос и парсинг ответа)
Файлы
ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.
Подписка PRO — скачивайте любые файлы со скидкой до 85% из Базы знаний
Оформите подписку на компанию для решения рабочих задач
Оформить подписку и скачать решение со скидкойВы можете заказать платную доработку или адаптацию этой разработки под вашу конфигурацию на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.
09.2-companion.zip: ii-zapros.bsl, готовая обработка simple-client-ai.epf, каталог stand/ (сборка базы и обработки, сценарии вызовов, заглушка, запуск кластера, клиента и веб-публикации, Dockerfile СУБД, сравнение сервисов, протоколы), шаблон промпта, чек-лист по данным, примеры ответов JSON, READMEПрограммисту 1С: как вызвать языковую модель из модуля обработки и вернуть ответ в базу. Встроенного ИИ в конфигураторе нет, сервис вызывают через HTTPСоединение, HTTPЗапрос, ЗаписьJSON, ЧтениеJSON. Модуль прогнан на платформе 8.3.27.2130: файловая и клиент-серверная база, тонкий и веб-клиент, фоновое задание, OpenRouter. В архиве модуль, обработка .epf, стенд и чек-лист по данным.
- Встроенного ИИ в платформе 1С нет: «1С:Напарник» работает в среде 1С:EDT, а из кода 1С модель вызывается по HTTP.
- Тело запроса собирают Структурой и ЗаписьJSON, ответ читают ЧтениеJSON в Соответствие, код состояния проверяют до разбора тела; на платформе проверены ответы 200, 429, 401, 400, пустой choices и таймаут.
- Таблицу значений переводят в текст с разделителем и ограничивают число строк: у модели есть предел входного контекста.
- Ключ доступа живёт в настройке, поля перечисляются явно, персональные данные обезличиваются до отправки.
- Долгий вызов уводится в фоновое задание: синхронный запрос держит сеанс.
Обращение к LLM из 1С - это HTTP-запрос и парсинг JSON на штатных объектах платформы. Внешний редактор не нужен, но нужен ответ на вопрос, какие данные допустимо отправлять во внешний сервис.
Для кого: программисты 1С, которым нужен ИИ внутри контура: в обработке на сервере, в регламентном задании или на рабочем месте пользователя.
Встроенного ИИ в платформе 1С нет. Платформа даёт HTTP-соединение и работу с JSON, а обращение к модели пишется в модуле обработки. Отдельный продукт 1С с моделями, «1С:Напарник», работает в среде 1С:EDT: в конфигуратор и в пользовательский режим он не встроен.
Обработке внутри базы не нужна выгрузка конфигурации в файлы и не нужен редактор. Она видит данные через запросы, запускается по расписанию или по команде пользователя и отдаёт результат в форму или в табличный документ. Плата за это: ключ доступа, исходящий HTTPS с сервера и решение о том, какие данные допустимо отправлять во внешний сервис.
📦 Что берём из платформы
Схема стенда: прогон модуля ii-zapros.bsl на платформе 8.3.27.2130 против локального HTTPS-сервиса
Для обращения к сервису хватает четырёх объектов встроенного языка:
HTTPСоединение: соединение с сервером. В конструкторе задаются сервер, порт, таймаут и объект защищённого соединения. МетодОтправитьДляОбработкиотправляет POST-запрос,Получитьчитает ответ GET.HTTPЗапрос: адрес ресурса, заголовки и тело. МетодУстановитьТелоИзСтрокикладёт в тело строку, кодировка по умолчанию UTF-8.HTTPОтвет: свойствоКодСостоянияи методПолучитьТелоКакСтроку.ЗаписьJSONиЧтениеJSON: сборка тела и разбор ответа, плюс глобальные процедурыЗаписатьJSONиПрочитатьJSON.
HTTPS требует объекта защищённого соединения: без него соединение пойдёт по HTTP и сервис его отклонит. В справке платформы приведён пример Новый ЗащищенноеСоединениеOpenSSL(Новый СертификатКлиентаОС, Новый СертификатыУдостоверяющихЦентровОС, РежимПроверкиОтзываСертификатовУдостоверяющихЦентров.Строгий).
Чего в платформе нет: клиента конкретного сервиса, учёта израсходованных токенов, потоковой выдачи ответа и общей для всех моделей обёртки. Всё это пишется в модуле обработки или не делается вовсе.
🧱 Тело запроса
Тело - обычная структура с полем model и массивом сообщений, как в OpenAI-совместимом протоколе. Заголовок Authorization несёт ключ доступа, Content-Type сообщает формат.
Таймаут задаётся числом секунд в конструкторе соединения; в примере он приходит параметром. Порт и объект защищённого соединения тоже можно передать снаружи: по умолчанию это порт 443 и сертификаты операционной системы, а для проверки на локальном сервисе с собственным сертификатом подставляется Новый ЗащищенноеСоединениеOpenSSL(Неопределено, Новый СертификатыУдостоверяющихЦентровФайл(ПутьКСертификату)). Адрес ресурса и имя модели зависят от сервиса: у каждого провайдера свой адрес и свои поля, поэтому сверяйте их с его документацией. Ключ в модуле не хранят - он приходит из настройки или из переменной окружения.
🧪 Разбор ответа
Ответ приходит в JSON. Объекты удобно читать в Соответствие: тогда к полям обращаются по имени, и лишние поля сервиса не ломают разбор.
Два места, где разбор обычно падает. Первое: код ответа проверяют до чтения тела, иначе ошибка сервиса приходит как ошибка разбора JSON. Второе: пустой массив choices встречается при срабатывании фильтров сервиса, и обращение к нулевому элементу без проверки даёт исключение.
🧰 Данные из базы в текст
Таблица значений в JSON уходит плохо: модель читает текст и структуру таблицы не видит. Дешевле перевести строки в текст с разделителем, а число строк ограничить.
Числа Строка() выводит по региональным настройкам: 1000,5 превращается в 1 000,5 с неразрывным пробелом (код U+00A0) и десятичной запятой. Модель такой текст читает, а разбирать его обратно кодом без замены пробела не стоит.
Ограничение по строкам обязательно: у модели есть предел входного контекста, и таблица на сотни тысяч строк его переполнит. Вместо выгрузки строк подряд считайте агрегаты запросом: суммы, средние, группировки по месяцам и складам.
🔬 Что показал прогон на платформе
Прогон шёл на платформе 1С:Предприятие 8.3.27.2130 в три этапа: серверный вызов через COM-соединение против локальной заглушки, настоящий сервис OpenRouter и простейшая внешняя обработка в тонком клиенте. Стенд: файловая база вне OneDrive, модуль из архива как общий модуль с признаками «Сервер» и «Внешнее соединение», вместо сервиса модели на первом этапе - локальный Python-сервер на https://localhost:8443 с самоподписанным сертификатом. Он принимает тело запроса, проверяет заголовок Authorization и отвечает по имени модели в теле. Проверку модулей платформа прошла (/CheckModules для тонкого клиента, сервера и внешнего соединения: «Синтаксических ошибок не обнаружено!»).
Этап 1. Вызов на сервере
| Случай | Что вернул модуль |
|---|---|
| Нормальный ответ | код 200, текст из choices[0].message.content; сервис получил тело с кириллицей и max_tokens: 200 |
| Код 429 | исключение «Сервис вернул код 429» с телом ответа, до разбора JSON дело не дошло |
Код 200 и пустой choices |
пустая строка, исключения нет |
| Ответ позже таймаута (2 секунды, сервис ждёт 6) | исключение «Превышен таймаут», обрыв через 2068 мс |
| Самоподписанный сертификат при сертификатах ОС (вариант по умолчанию) | исключение «Удаленный узел не прошел проверку» |
| Таблица из 5 строк, максимум 3 | заголовок колонок, три строки и «... строк не показано: 2» |
Этап 2. Настоящий провайдер
Те же функции модуля, без правок, против openrouter.ai на порту 443 с сертификатами операционной системы, модель google/gemini-2.5-flash-lite, ключ из переменной окружения:
| Случай | Что вернул модуль |
|---|---|
| Вопрос «Ответь одним словом: столица Франции?» | код 200, текст «Париж», 901 мс |
Сводка по таблице из 4 строк (ТаблицаВТекст и запрос к модели) |
код 200, ответ называет болт М8х40 (15 шт) и шпильку М10 (0 шт) как позиции с дефицитом, 831 мс |
| Просроченный ключ | исключение «Сервис вернул код 401» с телом API key expired, 633 мс |
| Ключ несуществующего пользователя | код 401, User not found., 442 мс |
| Несуществующая модель | код 400, ... is not a valid model ID, 314 мс |
Сертификаты ОС для openrouter.ai дополнительной настройки не потребовали. Все три ошибочных ответа дошли до исключения с понятным текстом, разбор JSON при этом не запускался.
Этап 3. Внешняя обработка в тонком клиенте
Простейшая обработка «Простой клиент ИИ» собрана платформой из XML (build_epf.py в архиве, файл 10 403 байта). В модуле объекта лежит код из архива и функция Спросить, форма содержит поля сервера, порта, адреса ресурса, ключа, модели, файла сертификата, запроса и ответа и кнопку «Спросить модель». Открывается обработка в тонком клиенте через «Файл - Открыть» (Ctrl+O), и платформа сразу спрашивает разрешение:
Предупреждение безопасности при открытии файла обработки: ответ «Да» открывает форму.
Форма обработки: в полях значения для локальной заглушки.
Нажатие «Спросить модель» против локальной заглушки:
Заглушка отвечает «Получено символов: 52. Макс. токенов: 300.»: запрос дошёл до сервиса и ответ разобран.
Модель limit: в поле ответа текст ошибки с кодом 429 и телом ответа.
Тот же вызов против настоящего сервиса: в форме сервер openrouter.ai, порт 443, адрес /api/v1/chat/completions, модель google/gemini-2.5-flash-lite, поля ключа и сертификата пустые, ключ обработка берёт из переменной окружения:
Ответ настоящей модели: «Позиция с дефицитом (меньше 100 шт) - болт М8х40.»
Клиент показал то, чего не видно на сервере:
- Чтение переменной окружения. Во встроенном языке такой функции нет: имена
ПолучитьПеременнуюСреды,ПолучитьПеременнуюОкружения,ПолучитьПеременнуюСредыОкруженияиПолучитьЗначениеПеременнойСредыдали ошибку компиляции. Ключ берётся черезНовый COMОбъект("WScript.Shell")иExpandEnvironmentStrings; это работает на Windows и в файловой базе, на сервере 1С хранят ключ в настройке. - Предупреждение о COM-объекте. Первое обращение к
WScript.Shellплатформа прерывает и спрашивает разрешение для модуля. После ответа «Да» текущее действие нужно повторить: первое нажатие кнопки ответа не даёт.
Предупреждение о подключении исполнимого файла для модуля обработки.
Этап 4. Веб-клиент
Кнопка «Спросить в фоне» запускает ФоновыеЗадания.Выполнить("ПроверкаИИ.ФоновыйВызов", ...), ждёт ОжидатьЗавершенияВыполнения(60) и читает сообщения задания. В тонком клиенте с файловой базой задание завершилось успешно:
Фоновое задание в тонком клиенте: состояние «Задание выполнено», вызов модели занял 1 057 мс, всё задание 1 797 мс.
Одна ошибка прогона касается формы: имя Параметры занято самой формой, присвоение массиву даёт «Поле объекта недоступно для записи», переменную пришлось назвать МассивПараметров. Из COM-соединения то же задание после ожидания в 120 секунд оставалось в состоянии «Задание выполняется»; причину я не выясняла.
Веб-клиент проверялся на той же файловой базе. Публикацию сделал webinst.exe -publish -apache24 в 32-битный Apache 2.4 с модулем wsap24.dll из поставки платформы: порт 8081, права администратора не понадобились, IIS не включался. Страница http://localhost:8081/nopik/ открывается в Microsoft Edge. Обработку веб-клиент открывает через собственное окно «Выбор файлов» (Ctrl+O, «выберите с диска»), предупреждения безопасности при этом нет:
Веб-клиент: ответ «Берлин» от настоящего сервиса, ключ взят из окружения процесса Apache.
Веб-клиент: фоновое задание выполнено за 1 603 мс, вызов модели 762 мс.
При автоматическом вводе в веб-клиенте нужны паузы между действиями: при быстрой подстановке текст запроса попал в поле сертификата. После обрыва браузера без выхода из сеанса следующий вход через тот же Apache выдал «В данный момент вход в приложение невозможен»; перезапуск Apache помог.
Этап 5. Сравнение сервисов на наборе вопросов
Модуль из архива ни от чего, кроме формата тела, не зависит, поэтому на нём удобно сравнивать сервисы на регрессионном наборе. Здесь сравнение коротких ответов двух сервисов: сервис А - OpenAI-совместимый шлюз (google/gemini-2.5-flash-lite), сервис Б - вопросно-ответный сервис с контрактом {question, product}, разработка автора статьи; адрес в статье не приводится. Пять вопросов (у сервиса А температура 0), ответы проверены на платформе 8.3.27.2130 (stand/compare-run.json, stand/claims-run.txt):
| Вопрос | Сервис А | Сервис Б | Проверка на платформе |
|---|---|---|---|
| Столица Германии? | «Берлин», 0,8 с | «Берлин», 11,7 с | совпадают |
Какой объект отправляет запрос и возвращает HTTPОтвет? |
HTTPСоединение, 1,1 с |
HTTPСоединение и метод ОтправитьДляОбработки, 6,6 с |
оба верны, Б точнее |
Как прочитать JSON в Соответствие? |
ПрочитатьJSON у объекта ДжейсонТекст, 0,8 с |
функция ПреобразоватьJSONВСоответствие, 5,6 с |
оба неверны: ДжейсонТекст - «Тип не определен», ПреобразоватьJSONВСоответствие - «Процедура или функция не определена»; верно ПрочитатьJSON(Чтение, Истина) |
| Как ограничить таблицу перед отправкой? | обрезать строки или агрегировать, 0,8 с | Свернуть(), ПЕРВЫЕ, лимит по токенам, 12,2 с |
Свернуть выполняется; оба ответа применимы |
Что делает УстановитьТелоИзСтроки? |
тело из строки в UTF-8, 0,8 с | тело из строки, кодировка и BOM, 5,6 с | вызов с тремя параметрами (строка, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать) выполняется; оба верны, Б полнее |
Сервис А отвечал за 0,8-1,1 секунды, сервис Б за 5,6-12,2 секунды с номерами источников в ответе. Ошибка в вопросе про JSON общая: имя из ответа модели нужно проверять компилятором, прежде чем нести в код. Выборка из пяти вопросов иллюстрирует способ сверки; рейтинга сервисов из неё не получается.
Этап 6. Клиент-серверный вариант
Кластер серверов 1С входит в поставку платформы, но информационной базе в кластере нужна СУБД. Стандартный PostgreSQL 16 на создание базы ответил ошибкой extension "mchar" is not available: расширения 1С в нём отсутствуют. Рабочим оказался пакет postgrespro-1c-17 из репозитория производителя (PostgreSQL 17.10, Debian 12 в Docker, русская локаль); Dockerfile и start.sh лежат в stand/docker. Кластер поднимался из процессов пользователя без службы и без прав администратора (stand/start_cluster.ps1): агент на порту 2540, менеджер кластера 2541, сервер администрирования ras 2545, база создана командой rac infobase create --create-database и заполнена /LoadConfigFromFiles с подключением /S localhost:2541\nopik_llm.
Строка подключения к серверу 1С содержит порт менеджера кластера (2541). С портом агента (2540) Конфигуратор отвечает «Адрес не является адресом кластера серверов 1С:Предприятия».
Тонкий клиент подключается к базе кластера, обработка открывается так же, как в файловом варианте:
Клиент-серверный вариант: ответ «Берлин» получен рабочим процессом кластера; ключ читается из окружения процесса агента.
Фоновое задание на сервере: состояние «Задание выполнено», 848 мс, вызов модели 650 мс.
Ключ OpenRouter рабочий процесс кластера получает от агента, поэтому агент запускают с переменной окружения; в службе Windows её задают в параметрах службы. В клиент-серверной базе фоновое задание исполняет рабочий процесс кластера, и ему же принадлежит исходящее соединение: файрвол и прокси настраиваются для сервера 1С; рабочее место пользователя в этом соединении не участвует.
Регламентное задание проверено в базе кластера (sched.ps1, метод ПроверкаИИ.РегламентныйВызов, протокол sched-run.txt): предопределённое задание ПроверкаВызоваМодели включено с периодом 60 секунд, за 210 секунд прошло четыре запуска, ответ OpenRouter «Вена» пришёл за 601-947 мс, после чего задание выключено. Ключ задание берёт из окружения процесса рабочего сервера, как и фоновое.
Прогон дал две правки кода и одну находку. Первая правка: функции без ключевого слова Экспорт из общего модуля снаружи не видны, платформа отвечает «Метод объекта не обнаружен». Внутри модуля обработки они работают, а при переносе в общий модуль нужен Экспорт; в архиве он уже стоит. Вторая: порт 443 и сертификаты ОС были вшиты в функцию, и локальный сервис на другом порту проверить было нечем. Теперь Порт и Защита приходят необязательными параметрами. Находка касается чисел и описана выше, в разделе про таблицу.
Границы прогона. Качество ответов проверялось одной моделью на коротких запросах; лимиты провайдера и поведение при длинных ответах не измерялись. Запуски шли на сервере через внешнее соединение, в тонком клиенте и в веб-клиенте с файловой базой и в тонком клиенте с базой кластера серверов (один сервер, один пользователь, без нагрузки). Отказоустойчивость кластера, блокировки и параллельные сеансы не проверялись. Регламентное задание проверялось в базе кластера: период 60 секунд, четыре запуска за 210 секунд. Расписание по дням недели, повтор после сбоя и запрет заданий на сервере не проверялись.
🚧 Границы
- Модель не знает вашу конфигурацию. Имена реквизитов, регистров и процедур ей нужно передать в промпте: описанием структуры или выдержкой из метаданных.
- Ответ модели - текст. Если из него нужно получить запрос или код, его придётся разобрать и проверить: синтаксис BSL и язык запросов модель знает неровно.
- Обработка на сервере не имеет доступа к интерфейсу. Всё, что показывается пользователю, собирается в отдельной процедуре.
- Синхронный вызов держит сеанс. Долгий запрос к сервису на клиенте выглядит как зависшая форма, поэтому такие вызовы выносят в фоновое задание.
- Привилегированный режим и права: обработка, читающая данные для отправки, работает под правами пользователя, и обходить RLS в ней не следует.
🔒 Безопасность
Главный вопрос при внедрении - какие данные уходят. Три правила, которые закрывают большинство случаев:
- Перечисляйте поля явно. Запрос на отправку строится из фиксированного списка колонок: произвольную таблицу пользователя в тело не кладут.
- Обезличивайте персональные данные. ФИО, телефоны, адреса, номера документов заменяются масками до отправки; обратная замена делается на стороне 1С по справочнику соответствия.
- Отделяйте окружения. Ключ доступа и адрес сервиса берутся из настройки: в коде, в Git и в поставке обработки их быть не должно.
Если внешний сервис недопустим по требованиям, тот же модуль работает с локальной моделью: меняются адрес, порт и имя модели, схема обмена остаётся прежней. Проверять качество ответов стоит на копии базы и на обезличенных данных.
📋 Порядок внедрения
- Выберите одну задачу: сводка по данным, разбор текста комментариев, черновик запроса по описанию.
- Возьмите внешнюю обработку с четырьмя функциями из архива, подставьте адрес сервиса, имя модели и ключ.
- Прогоните вызов на копии базы с ограничением в 10-20 строк таблицы и посмотрите, что приходит в ответе.
- Зафиксируйте в списке полей, какие данные разрешено отправлять, и внесите обезличивание в код до первого запуска на рабочей базе.
- Оформите обработку как регламентное задание с логированием: дата, пользователь, длина запроса, код ответа. Полные тексты запросов в журнал не пишут.
📚 Источники
- Синтакс-помощник платформы 1С:Предприятие 8.3.27.2130, файл справки
shcntx_ru.hbk: описанияHTTPСоединение,HTTPЗапрос,HTTPОтвет,ЗаписьJSON,ЧтениеJSON,ЗащищенноеСоединениеOpenSSL,СтрСоединить,СтрШаблон. - Документация OpenAI API, раздел Chat Completions - формат тела запроса и структура ответа
choices[].message.content. - 1С:Предприятие, раздел «Искусственный интеллект» - «1С:Напарник для 1C:EDT»: работа с моделями в среде EDT.
📎 Файл к статье
Во вложении архив к статье: модуль, шаблон промпта, чек-лист по данным, два примера ответа сервиса и описание к ним.
ii-zapros.bsl: модуль обработки целиком - сборка тела, отправка, разбор ответа, перевод таблицы в текст;shablon-prompta.md: шаблон промпта для разбора таблицы и три примера заполнения;chek-list-dannyh.md: чек-лист по данным - что можно отправлять во внешний сервис, как обезличивать, что писать в журнал;primer-otveta.json: условный пример ответа сервиса, на котором проверялся разбор;primer-otveta-oshibka.json: условные примеры ответа с кодом 429 и ответа с пустым массивомchoices- два случая, где разбор падает без проверок;stand/: стенд прогона - сборка проверочной базы, вспомогательный модуль, сценарий вызовов, локальный HTTPS-сервис-заглушка, сценарий проверки на OpenRouter, сборка обработкиbuild_epf.py, запуск клиентаlaunch_client.ps1и протоколы прогоновe2e-run.txtиopenrouter-run.txt;simple-client-ai.epf: готовая простейшая внешняя обработка «Простой клиент ИИ»;README.md: что внутри, как подключить модуль к внешней обработке, что проверено на платформе и что нет.
Модуль из архива можно вставить в модуль внешней обработки или в общий модуль серверного вызова: он не зависит от конкретной конфигурации и не обращается к её объектам.
🏁 Итог
Обращение к языковой модели из 1С собирается из штатных объектов платформы: HTTPСоединение, HTTPЗапрос, ЗаписьJSON, ЧтениеJSON. Встроенного ИИ в конфигураторе при этом нет, и «1С:Напарник» живёт в отдельной среде. Код из архива сверен со справкой платформы 8.3.27.2130 и прогнан на ней: на сервере против локальной заглушки, против OpenRouter и в тонком клиенте во внешней обработке. Первый запуск на своей базе делайте на копии с ограниченной выборкой и обезличенными данными. В комментариях интересно, какие задачи вы пробовали решать моделью прямо из обработки и что пришлось переделать после первых ответов.
- Первый промпт для BSL: как научить ИИ-агента сверяться с метаданными конфигурации
- Синтакс-помощник 1С как MCP-инструмент: индекс из справки платформы и сервер на Python SDK
- Несколько ИИ-агентов на одном репозитории 1С: git worktree, своя база и ConfigDumpInfo.xml
- LangGraph для 1С-разработчика: агент ждёт вашего «да» перед записью, стенд за 3 минуты
Вступайте в нашу телеграмм-группу Инфостарт