
Предисловие
Прошло немногим больше двух лет с момента выхода моей прошлой статьи (https://habr.com/ru/articles/786288) на данную тематику. За этот период технологии больших языковых моделей (LLM – Large Language Models) значительно развились, расширив возможности инструментов, применяемых для решения задач нормализации корпоративных справочников номенклатуры. Поскольку компактные модели (SLM – Small Language Models) в ряде задач догоняют LLM по своим возможностям, будем далее пользоваться аббревиатурой LLM/SLM.
Тогда рассматривался лишь базовый пример возможностей LLM/SLM для обработки записей номенклатуры. Сегодня же ситуация существенно изменилась: появились механизмы, которые позволяют эффективно решать подобные задачи. Одним из таких механизмов является использование структурированного вывода (structured output) в LLM/SLM.
Термин “structured output” в блоге Ollama, например, появился 6 декабря 2024 года (https://ollama.com/blog/structured-outputs), так что его возраст можем считать не слишком юным, но и точно не устаревшим – чуть более года. Именно применению такого инструмента для решения задачи нормализации корпоративного справочника номенклатуры посвящена данная публикация.
Пример нормализации позиций номенклатур с помощью локальной LLM/SLM
Рассмотрим нормализацию списка отводов, фигурирующего в предыдущей статье, с помощью механизма structured output, реализованного в LLM/SLM. Чтобы не ломать голову относительно количества токенов и их стоимости, развернём модель локально и будем с ней взаимодействовать через API, предоставляемым Ollama. Для определённости воспользуемся локальной моделью ГигаЧат3, доступной на Hugging Face, а именно – hf.co/ai-sage/GigaChat3-10B-A1.8B-GGUF:Q6_K. Эта модель выбрана, так как целиком помещается в 12Гб домашней потребительской GPU RTX3060 с контекстом в 16К токенов, тогда как hf.co/ai-sage/GigaChat3-10B-A1.8B-GGUF:Q8_0 – уже нет. Детали развёртывания локальных моделей с использованием Ollama здесь опускаем, поскольку вся необходимая информация имеется на сайте ollama.com.
В данном примере построим эксель-шаблон однородной группы эталонных записей (узла корпоративного классификатора) номенклатур для отводов по ГОСТ 17375, взяв в качестве исходной табличку, приведенную в предыдущей публикации:

Источники, откуда можно брать такие шаблоны в реальной работе, разбираются в разделе организационных вопросов ниже.
Для того, чтобы разобрать исходные записи обозначений отводов по характеристикам с помощью structured output, нам для каждой записи потребуется сформировать и передать LLM/SLM JSON-файл вида:
{
"model": "hf.co/ai-sage/GigaChat3-10B-A1.8B-GGUF:Q6_K",
"messages": [
{
"role": "user",
"content": "Расшифруй обозначение: ОТВОД 108*4 СТ20 90"
}
],
"stream": false,
"format": {
"type": "object",
"properties": {
"fitting_name": {
"type": "enum",
"description": "Наименование фиттинга",
"enum": [
"Отвод"
]
},
"angle": {
"type": "enum",
"description": "Угол изгиба (градусы)",
"enum": [
"45",
"60",
"90",
"180"
]
},
...
},
"required": [
"fitting_name",
"angle",
"D_diameter",
"T_thickness"
]
}
}
Полную версию файла можно найти по ссылке.
Поскольку пилить вручную такой JSON-файл довольно муторно, попробуем сгенерировать его автоматически в Excel-файле.
Для начала создадим вкладку настроек:

Перенесем исходную табличку в отдельную вкладку query-table и дополним её 4-мя строками сверху:
-
JSON тэг атрибута – в соответствующих колонках этой строки запишем идентификаторы атрибутов в том виде, в каком они попадут в JSON. Впоследствии по этим идентификаторам будем извлекать значения, заполненные LLM/SLM.
-
JSON тип атрибута – один из допустимых в JSON типов (string – строковое значение; enum – список допустимых значений и т.д.)
-
Значения типа enum – в ячейках этой строки перечисляются значения, если в предыдущей строке указан тип enum.
-
Обязательность – любое непустое значение рассматривается как признак обязательности соответствующего атрибута (попадёт в список тега “required”)
В результате должно получиться нечто такое:

Теперь попросим MS Copilot (или другое подходящее средство) сгенерировать код VBA-функций:
|
Наименование функции |
Заголовок функции |
Краткое описание |
|---|---|---|
|
BuildJsonSchemaFromSheet |
|
Формирует JSON-схему на основе структуры указанного листа Excel. Использует заголовки, типы данных, описания и значения для генерации объекта |
|
HABR_LLM1Fetch |
|
Отправляет JSON-запрос к LLM-модели через Ollama API методом POST и возвращает текстовый ответ. |
|
HABR_LLM1fromJSON |
|
Извлекает значение по указанному тегу из JSON-строки, используя парсер |
|
HABR_LLM1content_fromJSON |
|
Получает содержимое сообщения ( |
В ячейку B6 вкладки настроек запишем вызов функции =BuildJsonSchemaFromSheet($B$5)
Теперь в этой ячейке будет записан JSON-объект под тегом format, сгенерированный из строк 1-5 вкладки query-table.
Дополним табличку на вкладке query-table вызовом перечисленных функций в соответствующих ячейках:

Как видно из скриншота, LLM/SLM корректно разобрала первую строку с исходным обозначением:
-
ОТВОД 108*4 СТ20 90
Последовательность операций при этом была следующей:
|
Адрес ячейки |
Формула |
Описание операции |
|---|---|---|
|
N7 |
=””&SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(‘habr-llm-setup’!$B$4;”{{model}}”;’habr-llm-setup’!$B$3);”{{text}}”;A7);”{{format}}”;’habr-llm-setup’!$B$6) |
формирование JSON-запроса по шаблону из ячейки ‘habr-llm-setup’!$B$4 с подстановкой данных из текущей строки |
|
O7 |
=HABR_LLM1Fetch(N7;’habr-llm-setup’!$B$2) |
Отправка запроса по URL-адресу Ollama API, прописанному в ячейке ‘habr-llm-setup’!$B$2, запись JSON-ответа в текущую ячейку O7 |
|
P7 |
=HABR_LLM1content_fromJSON(O7) |
Извлечение содержимого тега message.content из содержимого ячейки O7 и запись результата в текущую ячейку P7 |
|
D7-J7 |
=HABR_LLM1fromJSON($P7;D$1)…=HABR_LLM1fromJSON($P7;J$1) |
Извлечение содержимого по тегам, прописанным в первой строке |
Ответ, полученный от LLM/SLM и записанный в ячейку O7:
{
"model": "hf.co/ai-sage/GigaChat3-10B-A1.8B-GGUF:Q6_K",
"created_at": "2026-01-28T09:17:06.929477859Z",
"message": {
"role": "assistant",
"content": "{ "fitting_name": "Отвод", "angle": "90", "D_diameter": "108", "T_thickness": "4", "steel_grade": "Ст20" } "
},
"done": true,
"done_reason": "stop",
"total_duration": 1730584481,
"load_duration": 123562864,
"prompt_eval_count": 22,
"prompt_eval_duration": 9576350,
"eval_count": 53,
"eval_duration": 498126336
}
Кому-то данный пример может показаться тривиальным, однако, надеюсь, найдутся и те, кого пример вдохновит на оптимизацию текущих процессов в своей компании с помощью описанного инструментария.
Организационные вопросы при построении корпоративного классификатора номенклатуры: Источники иерархии узлов и характеристик
Для построения корпоративного классификатора должны быть определены: иерархия узлов (классов) и атрибутный состав каждого узла, описывающего однородную группу позиций номенклатуры. (Альтернативный вариант с фасетной классификацией здесь не рассматриваем).
Корпоративный классификатор номенклатур: источники иерархии узлов
В качестве базы для иерархии узлов корпоративного классификатора на практике часто берут национальные классификаторы типа ОКПД2/ОКДП/ОКВЭД или международные UNSPSC и др.
Однако может потребоваться построение собственной иерархии, учитывающей особенности бизнеса конкретного предприятия.
Корпоративный классификатор номенклатур: внешние источники атрибутного состава узлов
Упомянутые в предыдущем пункте классификаторы не регламентируют атрибутный состав однородных групп номенклатур, только иерархию.
В принципе атрибутный состав номенклатур в формате XML достаточно подробно описывается в реализации eClass (https://eclass.eu/) к европейскому ISO 13584, однако официальная русскоязычная версия этой части стандарта, по данным автора, на текущий момент отсутствует.
Ещё один подход реализован в рамках серии стандартов НАТО ISO 22745 от ECCMA в виде глобального каталога характеристик eOTD.org и сервиса валидации эталонных записей eMDV. В рамках этого подхода производители и поставщики регистрируют в каталоге свою продукцию с указанием характеристик и их значений для каждой эталонной позиции. Похожие реализации имеются в русскозычном сегменте, но на национальном уровне.
Особенностью такого подхода является то, что каждая эталонная позиция номенклатуры регистрируется с уникальным глобальным идентификатором, далее хранится и используется индивидуально. С одной стороны, через глобальный идентификатор удобно привязывать позицию номенклатуры корпоративного справочника к эталонной записи глобального каталога. С другой стороны, это создаёт риски при недоступности глобального каталога, а также необходимость регистрировать весь ряд номенклатур, например компактно описанный нормативным документом (ГОСТ или ТУ).
Корпоративный классификатор номенклатур: внутренние источники атрибутного состава узлов
Классический подход при внедрении системы управления НСИ, частью которой является справочник с классификатором номенклатуры, предполагает назначение кураторов данных от бизнеса предприятия (например, из службы снабжения).
В обязанности куратора данных среди прочего прописывается ответственность за формирование атрибутного состава позиций номенклатуры, например в формате эксель-шаблона вида, использованного в примере нормализации выше.
Для позиций, которые закупаются по конкурсным процедурам, атрибуты могут быть естественным образом извлечены из технических спецификаций в составе конкурсных документов, в том числе с применением техники structured output.
Корпоративный классификатор номенклатур: LLM/SLM как источник атрибутного состава узлов
Судя по скриншоту, вынесеному на обложку данной публикации, некоторые LLM/SLM могут “из коробки” “знать” атрибутный состав некоторых однородных групп номенклатуры. Естественно задаться вопросом – “можем ли и каким образом обратиться к LLM/SLM для получения описания однородной группы в виде эксель-шаблона, использованного в примере выше?”. Забегая немного вперёд, можно сказать, что эксперименты автора дают надежду на получение положительного ответа на этот вопрос, однако детали заслуживают отдельной статьи, поэтому выходят за рамки данной публикации.
Выводы
Как показывает приведенный в публикации пример нормализации записей справочника номенклатуры, с развитием LLM/SLM практически отпадает необходимость в извлечении значений характеристик из исходных записей в полуручном режиме с помощью инструментов типа OpenRefine.
Однако открытыми остаются вопросы построения шаблонов однородных групп эталонных записей номенклатуры (узлов классификатора номенклатуры) и проверки сочетаний значений характеристик позиции номенклатуры на допустимость. Некоторые LLM/SLM “из коробки” могут “знать” атрибутный состав отдельных групп номенклатуры, однако пригодность такого атрибутного состава для бизнеса могут оценить только специалисты профильных подразделений предприятия. По некоторым данным, просачивающимся в информпространство, в крупных компаниях среди прочих прорабатывались и реализовывались решения на базе специализированных ML-моделей, обученных извлечению значений характеристик на эталонных выборках однородных групп записей с последующей генерацией эталонных записей по исходным. В силу стохастического характера общецелевых LLM/SLM либо специализированных ML-моделей задача проверки сочетаний значений характеристик позиции номенклатуры на допустимость на 100% ими не решается без доступа к внешним сервисам/источникам данных.
Упростить решение задачи могла бы подготовка нормативных документов (ГОСТ, ТУ, др.), описывающим атрибутный состав номенклатур, органами стандартизации и производителями в формате, пригодном для машинной обработки, однако основным форматом таких документов до сих пор остаётся PDF.
Одно из экспериментальных технических решений этой задачи, апробированное на выборке из ~2000 ГОСТ, ТУ и др., существует уже несколько лет, однако не получило распространения.
Решение включает в себя:
-
компактное представление рядов позиций номенклатур, описываемых нормативными документами, в виде графа знаний (OWL/RDF онтологий), размещаемого в хранилище (triple store),
-
технологию оцифровки исходных PDF нормативных документов с помощью эксель-шаблона,
-
инструменты загрузки заполненных эксель-шаблонов в хранилище с верификацией заполненных данных и проверкой на совместимость с ранее загруженными онтологиями,
-
сервис поиска в хранилище и генерации эталонных описаний позиций номенклатур в соответствии с нормативными документами.
Ресурсы, затрачиваемые на пополнение графового хранилища (triple store) с использованием данного решения, скорее всего, сопоставимы с ресурсами, затрачиваемыми на дообучение общецелевых LLM/SLM либо специализированных ML-моделей новым нормативным документам с учётом необходимости последующего регрессионного тестирования моделей в силу их стохастического характера и динамической природы предметной области.
Автор: v1st


