Интеграция ИИ в 1С
Опубликовано · 12 мин чтения
Интеграция ИИ в 1С сводится к HTTP-запросу из серверного кода. Вы собираете JSON с текстом задачи, отправляете его через HTTPСоединение на адрес провайдера и разбираете ответ через ЧтениеJSON. Внешние компоненты и промежуточный сервис для этого не нужны, всё есть в платформе. Ниже код для GigaChat и YandexGPT и те места, где схема ломается на проде, от сертификатов и таймаутов до лимитов и проведения документов. Адреса и модели провайдеров приведены по документации на 4 октября 2026 года.
Листинги ниже — шаблон. Версии платформы, БСП, настройки прокси и права на серверах у каждой базы свои, и на живой базе код не запускался. Перед боевым использованием прогоните его на тестовой копии, а порядок параметров HTTPСоединение сверьте с синтакс-помощником своей версии платформы.
Как подключить ИИ к 1С: три способа и какой из них здесь#
Под словами «подключить ИИ к 1С» прячутся три разные задачи. Они различаются тем, кто кого вызывает.
- 1С сама ходит к модели: серверный код делает исходящий HTTP-запрос и пишет результат в базу. Это тема статьи.
- Внешняя система ходит в 1С: вы публикуете HTTP-сервис, и агент или скрипт забирает данные оттуда. Пишется отдельным кодом на стороне 1С.
- Стандартный интерфейс OData: платформа сама отдаёт объекты наружу без кода, но с ограничениями по составу и правам. Границы разобраны в статье что 1С отдаёт наружу по OData.
Если нужно, чтобы ИИ-агент видел вашу базу и отвечал на вопросы по ней, вам нужен второй или третий путь и разговор о правах доступа, а он идёт в статье про MCP-сервер для 1С. Если нужно, чтобы кнопка в документе отправила текст модели и положила ответ в реквизит, вам сюда.
Серверный вызов: HTTPСоединение, HTTPЗапрос, HTTPОтвет#
За исходящий HTTP во встроенном языке отвечают три объекта. HTTPСоединение держит соединение с сервером, HTTPЗапрос несёт адрес ресурса, заголовки и тело, HTTPОтвет возвращает код состояния и тело ответа.
Писать это надо в серверном контексте. Ключ доступа к модели, положенный в клиентский модуль, уезжает на машину пользователя, и это главная причина писать вызов на сервере. Общий модуль с признаком «Сервер», вызванный через &НаСервере, держит ключ внутри кластера.
Функция ОтправитьЗапросКМодели(Сервер, АдресРесурса, ТелоЗапроса, ЗаголовокАвторизации) Экспорт
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/json");
Заголовки.Вставить("Authorization", ЗаголовокАвторизации);
Запрос = Новый HTTPЗапрос(АдресРесурса, Заголовки);
Запрос.УстановитьТелоИзСтроки(ТелоЗапроса, КодировкаТекста.UTF8,
ИспользованиеByteOrderMark.НеИспользовать);
// Порядок: сервер, порт, пользователь, пароль, прокси, таймаут (сек), защищённое соединение
Соединение = Новый HTTPСоединение(Сервер, 443, , , , 60,
Новый ЗащищенноеСоединениеOpenSSL());
Попытка
Возврат Соединение.ОтправитьДляОбработки(Запрос);
Исключение
ЗаписьЖурналаРегистрации("Интеграция.Модель",
УровеньЖурналаРегистрации.Ошибка, , ,
ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат Неопределено;
КонецПопытки;
КонецФункцииОтправитьДляОбработки отправляет POST. Метод возвращает HTTPОтвет, но до этого может выбросить исключение, если сеть недоступна или сертификат сервера не прошёл проверку. Строка заголовка авторизации приходит готовой, потому что у двух провайдеров она устроена по-разному; откуда она берётся, разобрано ниже.
Три расхождения в вызове GigaChat и YandexGPT#
Оба провайдера принимают JSON по HTTPS и отвечают JSON, но расходятся в трёх местах: как получить доступ, как называется модель и где лежит текст ответа. У Яндекса есть два интерфейса, нативный и совместимый с OpenAI, поэтому в таблице три колонки. Данные на 4 октября 2026 года по документации Сбера и Yandex AI Studio.
| Что сравниваем | GigaChat | YandexGPT, нативный API | YandexGPT, совместимый с OpenAI |
|---|---|---|---|
| Адрес получения токена | https://ngw.devices.sberbank.ru:9443/api/v2/oauth | не нужен | не нужен |
| Авторизация | Basic <ключ авторизации> для токена, затем Bearer <токен> | Api-Key <ключ> | Api-Key <ключ> |
| Срок жизни токена | 30 минут | токена нет, ключ сервисного аккаунта | токена нет, ключ сервисного аккаунта |
| Адрес вызова | https://api.giga.chat/v1/chat/completions | https://ai.api.cloud.yandex.net/foundationModels/v1/completion | https://ai.api.cloud.yandex.net/v1/chat/completions |
| Поле модели | model: например GigaChat-3-Ultra | modelUri: gpt://<каталог>/yandexgpt-5-lite | model: gpt://<каталог>/yandexgpt-5-lite |
| Поле текста сообщения | content | text | content |
| Где текст ответа | choices[0].message.content | alternatives[0].message.text | choices[0].message.content |
Несколько оговорок по таблице. Идентификатор GigaChat-3-Ultra в документации Сбера отмечен как доступный физическим лицам в режиме Freemium; на платных тарифах эта модель пока недоступна, поэтому идентификатор берите из ответа GET https://api.giga.chat/v1/models и выносите в настройку.
У Яндекса модель в каталоге на эту дату называется yandexgpt-5-lite, yandexgpt-5-pro или yandexgpt-5.1, флагман — aliceai-llm. В актуальных примерах документации URI модели дан без /latest, и документация советует явные URI вместо /latest. Часть сторонних моделей в каталоге имеет даты окончания поддержки (Qwen3 235B была доступна до 30 сентября 2026 года, gpt-oss доступна до 30 октября 2026 года), поэтому имя модели нельзя зашивать в код.
Последняя оговорка. В примере документации Яндекса для совместимого интерфейса передаётся заголовок OpenAI-Project с идентификатором каталога. Нужен ли он, когда каталог уже указан в gpt://<каталог>/…, проверьте на своём ключе; листинг ОтправитьЗапросКМодели выше этот заголовок не передаёт.
Авторизация по токену Сбера на 30 минут и по ключу Яндекса#
У GigaChat доступ двухшаговый. Сначала POST на адрес авторизации с заголовком Authorization: Basic <ключ авторизации>, уникальным RqUID в формате UUID4 и телом scope=GIGACHAT_API_PERS для физлица, GIGACHAT_API_B2B для предпринимателей и юрлиц с пакетами или GIGACHAT_API_CORP для оплаты по факту. В ответ приходит токен на 30 минут, он и идёт в Authorization: Bearer при вызове модели.
С 17 июля 2026 года для подключения используется адрес api.giga.chat; кто подключился раньше, может продолжать работать на gigachat.devices.sberbank.ru, но для новых подключений используйте api.giga.chat.
Функция ПолучитьТокенGigaChat(КлючАвторизации, Скоуп) Экспорт
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded");
Заголовки.Вставить("Accept", "application/json");
Заголовки.Вставить("Authorization", "Basic " + КлючАвторизации);
Заголовки.Вставить("RqUID", Строка(Новый УникальныйИдентификатор));
Запрос = Новый HTTPЗапрос("/api/v2/oauth", Заголовки);
Запрос.УстановитьТелоИзСтроки("scope=" + Скоуп, КодировкаТекста.UTF8,
ИспользованиеByteOrderMark.НеИспользовать);
Соединение = Новый HTTPСоединение("ngw.devices.sberbank.ru", 9443, , , , 30,
Новый ЗащищенноеСоединениеOpenSSL());
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Если Ответ.КодСостояния <> 200 Тогда
ВызватьИсключение "Токен GigaChat не получен, код " + Ответ.КодСостояния;
КонецЕсли;
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку("UTF-8"));
Разобранный = ПрочитатьJSON(Чтение, Истина);
Чтение.Закрыть();
Возврат Разобранный.Получить("access_token");
КонецФункцииТокен живёт полчаса, а запрос на его получение ограничен десятью в секунду, поэтому получать токен перед каждым вызовом незачем. Храните его вместе с временем получения и обновляйте, когда до конца остаётся несколько минут. Проще всего хранить его в записи регистра сведений с полем «Действует до».
У YandexGPT шаг один, заголовок Authorization: Api-Key <ключ>, где ключ выдан сервисному аккаунту с ролью ai.languageModels.user и областью действия yc.ai.foundationModels.execute. Ключ показывают один раз при создании, повторно его не прочитать.
Сам ключ в коде не держат. В конфигурации с БСП для этого есть безопасное хранилище. ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище(Владелец, Данные, Ключ) кладёт значение, парная функция ПрочитатьДанныеИзБезопасногоХранилища достаёт. Владельцем выступает ссылка, например на элемент справочника; произвольное значение туда не передать.
Без БСП сгодится отдельный регистр сведений, закрытый ролью, которой у обычных пользователей нет. Константа не годится, потому что право на чтение констант часто раздано широкому кругу ролей.
Собираем тело запроса через ЗаписьJSON#
Тело запроса к чат-модели устроено одинаково, это имя модели и массив сообщений, у каждого сообщения роль и текст. Ролей три. system задаёт поведение модели, user несёт вопрос, assistant хранит её прежние ответы, если вы ведёте диалог.
Собирать строку конкатенацией не стоит. Текст из базы содержит кавычки и переводы строк, и склейка ломается на первом же наименовании вида Труба 25х2,5 "Премиум". ЗаписьJSON экранирует всё сама, а массивы, структуры и соответствия сериализуются рекурсивно.
// Формат GigaChat и совместимого интерфейса Яндекса: поле content
Функция ТелоЗапросаЧата(Модель, СистемноеСообщение, ТекстЗадачи) Экспорт
Сообщения = Новый Массив;
Сообщения.Добавить(Новый Структура("role, content", "system", СистемноеСообщение));
Сообщения.Добавить(Новый Структура("role, content", "user", ТекстЗадачи));
Параметры = Новый Структура;
Параметры.Вставить("model", Модель);
Параметры.Вставить("messages", Сообщения);
Возврат ЗаписатьВСтрокуJSON(Параметры);
КонецФункции
// Формат нативного API Яндекса: modelUri, completionOptions и поле text
Функция ТелоЗапросаЯндекс(ИдентификаторКаталога, Модель, СистемноеСообщение, ТекстЗадачи) Экспорт
Сообщения = Новый Массив;
Сообщения.Добавить(Новый Структура("role, text", "system", СистемноеСообщение));
Сообщения.Добавить(Новый Структура("role, text", "user", ТекстЗадачи));
Параметры = Новый Структура;
Параметры.Вставить("modelUri", "gpt://" + ИдентификаторКаталога + "/" + Модель);
Параметры.Вставить("completionOptions",
Новый Структура("stream, temperature, maxTokens", Ложь, 0.3, "2000"));
Параметры.Вставить("messages", Сообщения);
Возврат ЗаписатьВСтрокуJSON(Параметры);
КонецФункции
Функция ЗаписатьВСтрокуJSON(Данные)
Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку();
ЗаписатьJSON(Запись, Данные);
Возврат Запись.Закрыть();
КонецФункцииmaxTokens в нативном API Яндекса уходит строкой, потому что в справочнике поле объявлено как строка с 64-битным целым. Температура задаётся числом от 0 до 1, по умолчанию 0,3.
Читаем ответ и поля, которых может не быть#
Второй параметр Истина заставляет ПрочитатьJSON читать объекты в Соответствие. Ключи ответа приходят от чужого сервиса и не обязаны быть допустимыми идентификаторами 1С. Путь к тексту у провайдеров разный, как в таблице выше. У GigaChat и совместимого интерфейса Яндекса это choices[0].message.content, у нативного API Яндекса alternatives[0].message.text, без внешнего поля result.
// Путь: массив "choices" (формат OpenAI) или "alternatives" (нативный Яндекс)
Функция ТекстОтвета(Ответ) Экспорт
Если Ответ = Неопределено Тогда
Возврат "";
КонецЕсли;
ТелоКакСтрока = Ответ.ПолучитьТелоКакСтроку("UTF-8");
Если Ответ.КодСостояния <> 200 Тогда
ЗаписьЖурналаРегистрации("Интеграция.Модель",
УровеньЖурналаРегистрации.Ошибка, , ,
"Код " + Ответ.КодСостояния + ": " + Лев(ТелоКакСтрока, 1000));
Возврат "";
КонецЕсли;
Попытка
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(ТелоКакСтрока);
Разобранный = ПрочитатьJSON(Чтение, Истина);
Чтение.Закрыть();
Исключение
// Код 200, но тело не JSON: считаем ответ пустым
ЗаписьЖурналаРегистрации("Интеграция.Модель",
УровеньЖурналаРегистрации.Ошибка, , ,
"Тело не JSON: " + Лев(ТелоКакСтрока, 1000));
Возврат "";
КонецПопытки;
Варианты = Разобранный.Получить("choices");
Если Варианты = Неопределено Тогда
Варианты = Разобранный.Получить("alternatives");
КонецЕсли;
Если Варианты = Неопределено ИЛИ Варианты.Количество() = 0 Тогда
Возврат "";
КонецЕсли;
СообщениеМодели = Варианты[0].Получить("message");
Если СообщениеМодели = Неопределено Тогда
Возврат "";
КонецЕсли;
Содержимое = СообщениеМодели.Получить("content");
Если Содержимое = Неопределено Тогда
Содержимое = СообщениеМодели.Получить("text");
КонецЕсли;
Возврат ?(Содержимое = Неопределено, "", Содержимое);
КонецФункцииПроверки на Неопределено подряд выглядят избыточно ровно до первого раза, когда провайдер вернёт 200 и пустой массив вариантов. Обращение Разобранный["choices"][0]["message"]["content"] в этот момент упадёт прямо в пользовательской форме. Получить возвращает Неопределено вместо исключения, и код остаётся управляемым. Тело ответа читается один раз в переменную, дальше работаем с ней.
Сквозной пример на разборе реквизитов из текста письма#
Типичная задача — достать из свободного текста письма реквизиты контрагента и заполнить ими карточку. Модель просят вернуть JSON в системном сообщении, а ответ проверяют на своей стороне, потому что она может обрамить JSON пояснением или вернуть другие имена полей.
Функция РазобратьРеквизиты(ТекстПисьма) Экспорт
Система = "Достань из текста ИНН, КПП и наименование организации. "
+ "Ответь только JSON вида {""inn"":"""",""kpp"":"""",""name"":""""}, без пояснений.";
Токен = ПолучитьТокенGigaChat(КлючАвторизацииИзХранилища(), "GIGACHAT_API_PERS");
Тело = ТелоЗапросаЧата(МодельИзНастроек(), Система, ТекстПисьма);
Ответ = ОтправитьЗапросКМодели("api.giga.chat", "/v1/chat/completions", Тело, "Bearer " + Токен);
Текст = ТекстОтвета(Ответ);
Если Текст = "" Тогда
Возврат Неопределено;
КонецЕсли;
Попытка
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(Текст);
Результат = ПрочитатьJSON(Чтение, Истина);
Чтение.Закрыть();
Исключение
// Модель вернула не JSON: в базу не пишем ничего
Возврат Неопределено;
КонецПопытки;
Возврат Результат;
КонецФункцииЗаписывать в реквизиты то, что не разобралось, хуже, чем не записать ничего. Если результат пришёл, перед записью проверьте ИНН контрольной суммой, потому что модель легко придумывает правдоподобные цифры.
Что ломается на проде#
Сначала сводка по кодам GigaChat из справочника Сбера. У Яндекса причину точнее всего называет тело ошибки, его и читайте.
| Код или симптом | Причина | Что делать |
|---|---|---|
| 401 | токен истёк (30 минут) или ключ неверный | получить новый токен и повторить запрос один раз; повторный 401 — смотреть ключ и scope |
| 422 | невалидный запрос: порядок сообщений, переполнение контекста по размеру содержимого | сократить входные данные, проверить порядок ролей |
| 429 | превышено число одновременных запросов | повторить позже; не запускать запросы пачкой |
| исключение до ответа | сеть, прокси, сертификат | журнал регистрации, проверка корневого сертификата |
| 200 и пустой массив вариантов | модель не вернула ответ | считать задачу невыполненной, в базу не писать |
- Российские эндпоинты подписаны сертификатами НУЦ Минцифры, и Сбер прямо пишет, что без корневого сертификата Минцифры обмен с GigaChat API не пойдёт. 1С со своей стороны проверяет цепочку: конструктор
ЗащищенноеСоединениеOpenSSLбез указанных сертификатов удостоверяющих центров проверку сервера всё равно выполняет, а список доверенных корневых лежит в файлеcacert.pemв каталогеbinустановленной платформы. Если сертификата Минцифры нет вcacert.pem, вызов может упасть на проверке цепочки. Добавлять его придётся на каждом сервере кластера, а после обновления платформы стоит перепроверить: каталогbinу новой версии свой, и сертификат там надо проверить заново. - Стандарт разработки 1С №748 требует задавать предельное время ожидания при работе с внешними ресурсами. Не задали — ожидание может оказаться бесконечным, и интерфейс или регламентное задание зависнет. Для ближайших по смыслу операций, получения сведений об одном контрагенте и обмена сообщениями, стандарт называет 60–120 секунд (для вызова LLM это ориентир по аналогии, не норма) и отдельно оговаривает, что больше трёх минут в общем случае брать не стоит.
- На превышение числа одновременных запросов приходит код 429. У GigaChat физлицу доступен один поток, юридическому лицу по умолчанию дают десять. Двух пользователей, нажавших кнопку одновременно, хватит, чтобы физлицо получило 429.
- Размер запроса ограничен окном контекста модели. На невалидный запрос GigaChat отвечает кодом 422 «Ошибка валидации параметров запроса», и среди причин — переполнение контекста (по размеру содержимого) и неверный порядок сообщений. Печатную форму акта на сорок позиций целиком в модель отправлять не нужно: соберите только те реквизиты, по которым нужен ответ.
Повтор после 429 удобно делать паузой, но платформа разрешает её не везде. Метод ВызватьПаузу(<интервал в миллисекундах>) появился в 8.3.25 и работает только на сервере, то есть в фоновых заданиях, веб- и HTTP-сервисах. При вызове из клиент-серверного вызова он выбрасывает исключение, чтобы не подвесить интерфейс. Документация платформы называет ожидание готовности внешней системы его сценарием и предостерегает от бесконечных циклов на нём.
На версиях до 8.3.25 паузы во встроенном языке нет, и повтор строится иначе. Неудачный запрос кладётся в регистр-очередь, регламентное задание разбирает её через минуту.
Почему нельзя звать модель в проведении документа#
Проведение выполняется в транзакции, которую платформа открывает сама, а стандарт разработки «Транзакции: правила использования» требует не делать транзакции длинными. HTTP-вызов к внешнему сервису как раз длинный и недетерминированный: ответ может занять секунды и оборваться, так что в транзакции ему не место. Это вывод из стандарта, а не его прямая норма.
Блокировки, наложенные внутри транзакции, держатся до её завершения, а ожидание блокировки по умолчанию длится 20 секунд, после чего транзакция завершается с исключением «Превышено время ожидания установки блокировки». Если модель отвечает полминуты, сеансы, вставшие в очередь за теми же регистрами, получают это исключение.
Вызов выносится в фоновое задание, а документ проводится как обычно и получает результат позже, в реквизите или регистре сведений.
ПараметрыЗадания = Новый Массив;
ПараметрыЗадания.Добавить(СсылкаНаДокумент);
КлючЗадания = "Модель_" + Строка(СсылкаНаДокумент.УникальныйИдентификатор());
Попытка
ФоновыеЗадания.Выполнить("ИнтеграцияСМоделью.ОбработатьДокумент",
ПараметрыЗадания, КлючЗадания, "Разбор документа моделью");
Исключение
// Задание с этим ключом уже выполняется: второй клик игнорируем
КонецПопытки;Третий параметр задаёт ключ задания. Пока задание с таким ключом выполняется, второе платформа не запустит, и попытка стартовать его выбросит исключение. Поэтому вызов обёрнут в Попытка, и двойной клик по кнопке не превращается ни в два оплаченных запроса, ни в окно с ошибкой. Явное приведение УникальныйИдентификатор() к строке через Строка() надёжнее неявного.
Коннектор из сообщества или свой код#
В сообществе 1С есть готовые коннекторы к десяткам моделей, в том числе с открытым кодом. Они выигрывают, когда нужны стриминг, несколько провайдеров с переключением и единый интерфейс для всех конфигураций, а это сотни строк, которые не хочется поддерживать.
Свой код оправдан, когда задача одна, провайдер один и нужно знать каждую строку: аудит безопасности, закрытый контур, минимум чужих зависимостей. Чужой коннектор, как и свой, не снимает вопросов про сертификат, таймаут и транзакцию: они лежат ниже, на уровне платформы.
Писать такую интеграцию удобнее там, где агент читает весь проект целиком. WorkAI — IDE с ИИ-агентом внутри; расширения ставятся из Open VSX, расширение для языка 1С там есть.
Скачать WorkAI IDE — бесплатноЧастые вопросы
Можно ли подключить GigaChat к 1С без внешних обработок?
Да. Достаточно общего модуля с признаком «Сервер» и четырёх объектов встроенного языка: HTTPСоединение, HTTPЗапрос, ЗаписьJSON и ЧтениеJSON. Отдельный сервис-посредник и внешние компоненты не нужны.
Можно ли сделать это расширением, не снимая конфигурацию с поддержки?
Да. Общий модуль с признаком «Сервер» добавляется расширением, снимать конфигурацию с поддержки для этого не нужно. Точкой вызова служит заимствованный обработчик или подписка на событие. В типовой без БСП ключ придётся хранить в собственном регистре сведений расширения, потому что безопасного хранилища там нет.
Как передать данные базы в нейросеть и не отдать лишнего?
Запрос собирают из конкретных реквизитов, печатную форму целиком не выгружают: в модель уходит ровно то, что вы положили в тело. Ключ держать на сервере, в журнал регистрации тело писать без заголовка Authorization. Сколько данных можно отправлять наружу, решают политика организации и закон о персональных данных, не платформа: перед отправкой текста с персональными данными стоит убедиться, что провайдер и условия обработки это допускают.
Что делать с ошибкой сертификата?
Установить корневой сертификат НУЦ Минцифры на каждом сервере кластера в cacert.pem каталога bin платформы, а после обновления платформы проверить его наличие заново.
Как понять, что ушло и что пришло, когда ответ странный?
Писать в журнал регистрации тело запроса и первые пару килобайт ответа отдельным событием, без заголовка Authorization, иначе ключ окажется в журнале, который читают все администраторы. Код состояния и тело ошибки провайдера обычно объясняют проблему точнее текста исключения 1С.
Как считать расход, чтобы не сжечь лимит?
Нативный API Яндекса возвращает в ответе секцию usage с полями inputTextTokens, completionTokens и totalTokens. Пишите эти числа в регистр сведений вместе со ссылкой на объект и датой: без этого первый же счёт станет неожиданностью, а найти обработку, которая запускает лишние вызовы, не получится. Тарифы меняются, поэтому актуальную цену токена смотрите в прайсе провайдера на день расчёта.