Оглавление
Проблематика
Начнем с того, для чего нам вообще понадобился классификатор номенклатуры? Основной профиль заказчиков, для которых назрел вопрос товарной аналитики продаж, – крупные металлотрейдеры.
Исторически процессы у них сложились следующим образом: сделки ведутся в CRM-системе (например, Битрикс24), товары добавляются в табличную часть «Товары» сделки, с достаточной степенью детализации (название товара, количество, габариты, цена, налог, скидка). Однако сам формат названий не согласован и не стандартизирован, то есть каждый товар можно записать практически неограниченным количеством способов, в том числе с опечатками.
Причин этому много: например, некоторые их клиенты просят вписать конкретное название товара, как того требует тендерная документация, кто-то руководствовался внутренними регламентами по неймингу, а кто-то просто никогда не задумывался об этом. Также наименования товаров в CRM-системе никак не связаны с товарами, размещенными на сайте (или в иных информационных ресурсах).
Соответственно, ранее аналитика сезонности спроса, прибыльности и маржинальности не велась в разрезах товарных групп. Если бы мы научились с высокой степенью точности определять категорию, к которой принадлежит товар, заведённый менеджером в сделку, это бы открыло дорогу ко многим видам аналитики: региональной, сезонной, связки с товарами в контекстной рекламе.
Так мы приступили к созданию классификатора. Первую рабочую версию классификатора мы создали за один месяц командой из трёх человек. За это время удалось согласовать структуру каталога, сформировать семантическое ядро, реализовать предварительную обработку названий и запустить классификацию всего массива товарных позиций.
Какие варианты у нас были
1. ML-модель
В целом модели работы в текстом можно разделить на две большие группы. Первая группа – локальные модели (interaction-focused), в которых каждое слово соответствует уникальному идентификатору. Релевантность в них представлена функцией от точного соответствия идентификаторов запросов в документе, возможно, например, с учетом позиционной составляющей. Этот подход хорош в задаче матчинга. Если у нас есть редкий токен, например, марка стали «12Х18Н10Т», который не практически не встречается в остальной части корпуса наименований товаров, то даже относительно простая модель (такая как индекс BM25) неплохо справляется с сопоставлением названия товара и его каноническим наименованием.
Вторая группа – распределенные модели (representation-focused). В них слова и текст имеют векторное представление в латентном пространстве (эмбеддинги). Релевантность в них – функция схожести от схожести эмбеддингов запросов (товаров из CRM) и документов (канонических наименований товаров). Явное преимущество – возможность учитывать не только точное соответствие ключей, но и соответствие по смыслу. Например, для запроса «Nickel Alloy 400» соответствие документу «Никелевая труба».
Модели имеют тенденцию обращать внимание на разные триггеры, указывающие на релевантность документа запросу. Главная проблема эмбеддингов в распределенных моделях в том, что как бы хорошо мы не обучали векторные представления слов, вектора для марок / ГОСТов / артикулов / бредовых названий, которые отличаются на 1-2 символа будут максимально похожими векторами в пространстве. То есть модель, оперирующая эмбеддингами, укажет на их полное соответствие. Это недопустимо в нашем случае, так как зачастую ГОСТы / марки, отличающиеся в 1 символ, несут кардинально разный бизнес-смысл.
Именно поэтому в первую очередь мы рассматривали продвинутую альтернативу, представляющую собой комбинацию этих двух типов, – KNRM. В ней учитываются связи «каждый с каждым» относительно слов запроса (товара из CRM) и документа (канонического наименования товара), в качестве меры близости косинусное сходство (cosine similarity), а полученная матрица сворачивается с помощью ядер (кернелов).

Основное ограничение, с которым мы столкнулись, – нам потребовалась качественно размеченная выборка. Опечатки и дубли (они встречаются в ~7-8% товаров) снижают качество данных. Также проблемой становится дисбаланс категорий (некоторые товары, такие как шпунт Ларсена, встречаются намного реже остальных).
То есть еще до того, как начать обучение модели, необходимо было провести разметку огромного массива данных без гарантий минимального порога качества на следующем этапе. Это очень дорогой путь.
2. Использование локальной LLM в связке с Python SDK
Второй вариант – можно отдать классификацию товаров локальной LLM. Мы развернули модель Qwen 3.8-27b (квантизованную) через Ollama и обращались к ней из Python (ollama.chat), скармливая название товара, правило распределения и просили вернуть категорию в нужном формате.
LLM показала себя неплохо. Она понимала сокращения, додумывала недостающий контекст и могла объяснить свой выбор. Например, для детали «отвод для трубы 90° 57×3,5» модель понимала, что «отвод» основной ключ, а «трубы» – шум, и относила товар в правильную ветку.
При этом почти для каждого товара приходилось формулировать дополнительный контекст (что в приоритете, что под запретом и куда вообще можно относить товары), в какой категории мы хотим видеть такие товары. А формирование универсального справочника потребовало бы ручного перебора всех товаров и определения правил с учетом каждого из них. Это очень ресурсозатратная задача.
Более того, у этого подхода очень дорогой инференс (по меньшей мере, сервер с GPU и механизм выборочной проверки, т.к. LLM может галлюцинировать в любой момент). Поэтому мы отказались от LLM в качестве основного инструмента. Как запасной вариант она нам ещё пригодится, но об этом дальше.
3. Эмпирические методы (создание продвинутого бизнес правила)
Третий вариант (к нему мы в итоге и пришли) – написать развернутое правило, которое работает с семантическим ядром: учитывает заданную конфигурацию ключевых слов и на основе них определяет принадлежность к какому-то классу товаров.
Какие преимущества у этого подхода? Главное – абсолютная интерпретируемость результата. Никаких чёрных ящиков, если алгоритм ошибся, всегда можно установить почему и исправить ошибку («отминусовать» проблемные ключевые слова, изменить приоритеты ключей, добавить новые ключи и правила распределения).
С какими сложностями мы столкнулись?
1. Невозможность однозначно установить принадлежность товара к конкретному классу – всегда есть двойственность в выборе
Даже такой формальный документ как ГОСТ (возьмем для примера ГОСТ 28548-90, устанавливающий термины и определения понятий основных видов стальных труб) не исключает возможность отнести трубу как категории горячекатаных бесшовных стальных труб (по способу производства), так и к плоскоовальным стальным трубам (по форме сечения).

Чтобы устранить эту неоднозначность, классификатор должен точно определять, что является более важным характеризующим свойством трубы: её способ производства или форма сечения. И так по каждому виду / подвиду товарной группы.
По этой же причине было сложно найти компромисс между каталогами разных проектов (выработать универсальный вариант классификации). Например, у большинства проектов один и тот же товар находился одновременно в нескольких ветвях каталога («виртуальных» категориях): допустим, в разделах «Трубы стальные бесшовные» и «Трубы плоскоовальные стальные».
2. Название товара состоит из множества взаимоисключающих (зачастую) частей
Из каких частей может состоять артикул:
вид товара (труба, лист)
категорийная принадлежность (бесшовная, холоднокатаная)
цель применения (водогазопроводная, для нефтепроводов)
материал (сталь, медь)
марка металла (09Г2С, Ст20)
свойство доп. обработки (перфорированная, оребренная, ППУ)
тип и номер стандарта (ГОСТ, ОСТ, АТК, ТУ, EN, DIN, JIS)
При этом наличие одной из частей можно неявно исключить другие. Например, исходя из названия «Труба 32х1,5 8732-78» неявно подразумевается, что:
Категорийная принадлежность – бесшовная горячедеформированная;
Материал – сталь;
Тип стандарта – ГОСТ.
Декартово произведение всех таких комбинаций просто огромно.
3. Высокая кардинальность свойств товаров
Существует огромной количество вариаций, которыми можно записать одно и то же свойство: б/ш, бесшовная, бс/ш, бесш., б\ш бс.\ш, и т.д.
Вот несколько реальных примеров, как менеджеры записывали бесшовную трубу:


4. Ошибки пользовательского ввода (опечатки)
Эта проблема отчасти связана с предыдущим пунктом – при полном отсутствии контроля ввода менеджеры опечатываются, эти опечатки нужно корректно выявлять и обрабатывать.

5. Пересечения и конфликты ключей
Чем осложнено простое перечисление ключей? Возникают конфликты ключевых слов при классификации. Например, «отвод для трубы» может быть присвоен категории «Трубы», хотя должен относиться к категории «Отводы».
Как выглядит реализованное решение
Как я и сказал ранее, из трёх вариантов мы выбрали именно создание продвинутых бизнес-правил.
Какие виды правил были созданы
Ключевое слово – обязательное, наследуется от узла-родителя к узлу-потомку с учетом наследования весов;
Вес ключевого слова – влияет на общую сумму баллов, которая присвоена классу-кандидату. Чем более специфичный ключ, тем больший вес ему лучше присвоить;
Слово-блокер – при наличии в товаре слова-блокера исключается возможность присвоения класса и его дочерних элементов товару. Наследуются от узла-родителя к узлу-потомку;
Слово-требование – ключ, обязательный к наличию в товаре, чтобы класс (или его дочерние элементы) могли быть присвоены данному товару. Наследуются от узла-родителя к узлу-потомку.
Поддерживаемые «операторы» для записи бизнес правил
! – оператор перезаписи
Если от узла-родителя к узлу-потомку пришли ключи, которые необходимо переписать на уровне потомка, используется оператор перезаписи: !фильтр, !фильтры, !грязевик, !грязевики.
^ – оператор начала строки
Если необходимо, чтобы ключевое слово было первым в названии товара.
Итоговая категорийная матрица бизнес-правил
Итоговая матрица содержит 22 категории верхнего уровня и 1100+ категорий всего:

Препроцессинг данных
Предварительная подготовка товаров состоит из трех частей:
Детекция опечаток – считает по словарю отслеживаемых ключей расстояние Левенштейна и предлагает наиболее вероятные кандидаты на опечатки;
Маппинг марок – сопоставляет марку стали с материалом;
Маппинг ГОСТов – сопоставляет ГОСТ изделия с типом / маркой / материалом.
Например, у нас есть исходный товар:
БРС по типу "CAMLOCK" DN 80 PN 25 12Х18Н10Т
Прогоняем его через обработчик пользовательского ввода и в результате получаем скорректированную версию названия товара:
БРС по типу "CAMLOCK" DN 80 PN 25 12Х18Н10Т | cam-lock | стальной
Полный пайплайн
Шаг 1. Преподготовка данных
Исправляем опечатки, маппим марки и ГОСТы, обработка батчами:

Шаг 2. Классификация
Предсказываем класс по бизнес правилам:

Шаг 3. Артикулизация
Присваиваем артикулы, обработка батчами:


Оцениваем полученное качество
В нашей категорийной матрице 1100+ категорий, и в них наблюдается явный дисбаланс – есть товарные категории, встречающиеся намного реже остальных. Именно поэтому метрики должны учитывать частотность категорий. Мы оцениваем решение сразу в трех срезах: точность категории верхнего уровня, взвешенное категорийное качество и качество автоматической классификации при заданном пороге уверенности.
Методика оценки
Контрольная выборка ~ 1,5 млн. товарных позиций, которые не использовались при разработке правил. Их мы разметили вручную. Чтобы одинаковые или почти одинаковые названия не попали одновременно в разработку и контроль, дубли предварительно объединялись в группы и целиком относились только к одной выборке.
Точность конечной категории
Доля товаров, для которых классификатор выбрал правильную конечную категорию:
где — эталонная категория товара,
— результат классификатора, а
— индикатор совпадения.
Качество по отдельным классам
Общая точность не показывает, насколько хорошо распознаются редкие категории. Поэтому для каждого класса отдельно вычисляются precision, recall и F1:
Взвешенный F1 с учетом доли каждого класса в выборке:
где — число объектов класса
.
Точность на верхнем уровне каталога
Ошибки между соседними подкатегориями менее критичны для аналитики, чем попадание товара в другую товарную группу (ошибка определения категории верхнего уровня), поэтому:
Точность автоматической классификации и покрытие
Когда данных недостаточно, корректнее не присвоить категорию вообще, нежели записать заведомо неверный результат. Поэтому классификатор принимает решение только при уверенности выше заданного порога (гиперпараметр).
Покрытие (доля товаров, которую система классифицирует автоматически):
где — нормированный отрыв (по сумме набранных весов) победившего класса от ближайшего кандидата.
Точность автоматической классификации, рассчитанная только среди принятых решений:
Результаты:
на верхнем уровне каталога категория определялась правильно в 96% случаев;
при заданном пороге
система автоматически классифицировала 86% товаров;
точность среди принятых решений составила 93%.
Около 80% всех товаров обрабатывались автоматически и корректно, и только 14% неоднозначных позиций требовали дополнительной проверки.
Дальнейшие планы развития инструмента
Следующий шаг развития проекта – интеграция в CRM в формате помощника для менеджера и обработка редких товаров.
1. Поиск поставщиков
Как только менеджер добавляет товар в сделку в Битрикс24, система поймет, что это за категория, и сразу предложит подходящих поставщиков, историю закупок и другую полезную информацию. Менеджеру не придется искать все это вручную.
2. Допродажи
Здесь можно либо предлагать то, что обычно берут в комплекте с этим товаром, либо то, что нравится клиентам с похожим профилем. Поскольку теперь у нас есть четкие категории, мы можем строить такие связи на уровне групп товаров, а не копаться в миллионах хаотичных названий.
3. Сложные товарные позиции
Если наши правила не смогли определить категорию или разрыв между классами-кандидатами меньше заданного порога, товар можно отдать локальной LLM вместе с уже разработанным списком бизнес правил. Такие товары можно обрабатывать не в регулярном пайплайне, а в ручном режиме на устройстве аналитика, поэтому дополнительных затрат на инференс не возникнет.

