Клиент присылает Excel со строкой «шляпа для вытяжки» или «труба 160», а в 1С товар называется «Зонт надшахтный ЗП 400» и «Воздуховод спирально-навивной ф160». Такие заявки лучше сопоставлять с номенклатурой каскадом: код разбирает файл, проверяет словарь клиента, ищет точные маркировки, делает нечёткий и смысловой поиск, а языковая модель выбирает из короткого списка кандидатов или отказывается. Размеры и единицы проверяет код, спорные строки остаются менеджеру. Ниже — как мы собрали такой каскад для каталога на 30 000+ позиций и что показал прогон 2 900 строк реальных заявок.
Почему одного поиска по словам мало
Обычный поиск по подстроке пропускает синонимы. Мы начинали с RapidFuzz и сравнения токенов по расстоянию Левенштейна, и для инженерной номенклатуры результат оказался плохим: запрос «Врезка прямая прямоугольная 600x500» получал всего 57 % сходства с нужной позицией «Врезка прямая ф100 500х600», зато «Воздуховод D100» и «Воздуховод D160» при этом совпадали на 95 %.
Лёгкая локальная модель эмбеддингов paraphrase-multilingual-MiniLM-L12-v2 понимала смысл, но не цифры: клиенту нужен диаметр строго 125, а поиск предлагал 160, «потому что это тоже круглая труба». Строку «Шумоглушитель кр. D125 мм., L=600» она не связывала с записью «LDC 125-600, шумоглушитель круглый».
LLM без списка кандидатов способна придумать позицию, которой нет в базе. Поэтому надёжнее собрать несколько методов в последовательность и дать каждому свою роль.
В нашем проекте локальная копия справочника содержит 30 951 позицию. Система работает с выгрузкой 1С и не делает произвольных запросов в инфобазу во время каждого матчинга. Итоговый каскад выглядит так:
строка заявки
→ [0] жёсткий словарь клиента → зелёный, 0 мс
→ [1] кэш подтверждённых пар → зелёный, < 1 мс
→ [2] RapidFuzz + фильтр по числам → кандидаты, < 100 мс
→ [3] векторный поиск ChromaDB → кандидаты, < 500 мс
→ объединение, score ≥ 0,95 → зелёный
→ [4] проверка LLM → ~1 с
→ иначе: жёлтый или красный статусПохожее название ещё не означает тот же товар
Точный словарь и маркировки
Сначала проверяем утверждённые пары и буквенно-цифровые модели.
Нечёткий и смысловой поиск
Собираем короткий список кандидатов из существующего каталога.
Проверка размеров и единиц
D125 и D160 не становятся одинаковыми из-за текстовой близости.
Выбор или отказ
LLM выбирает из кандидатов; сомнительный результат проверяет менеджер.
Шаг 1. Разобрать входной файл
До ИИ нужно правильно понять структуру заявки. Файл может содержать преамбулу, объединённые ячейки и разные названия колонок.
Парсер ищет шапку в первых строках и распознаёт варианты наименование, номенклатура, количество, ед. изм.. Строка становится шапкой только при наличии названия и ещё одной смысловой колонки. Если заголовки не найдены, код выбирает столбец по текстовому содержимому и отдельно защищается от числовых колонок.
Текстовый ввод тоже разбирается по правилам:
Вентилятор канальный SM 300 — 2 шт
Воздуховод D160, L=3000 — 9 м
Фильтр кассетный 500×300 4 штКоличество ищется в конце строки или в соседней ячейке. Числа внутри маркировки и размеров остаются частью названия.
Результат этого этапа имеет простую структуру:
{
"original_name": "Вентилятор канальный SM 300",
"quantity": 2,
"unit": "шт"
}Шаг 2. Проверить известные соответствия
У одного заказчика товар может годами называться одинаково. Нет смысла каждый раз вызывать модель.
Система сначала проверяет:
- жёсткий словарь конкретного клиента;
- ранее утверждённый кэш;
- общий словарь, если он разрешён для этого контекста.
Известная пара возвращается сразу. Словари перечитываются после изменения файла, поэтому новая запись начинает работать без старого кэша в процессе.
Главное ограничение: нельзя обучать такой словарь на каждом клике. Ошибка одного менеджера иначе станет автоматической ошибкой для следующих заявок.
Шаг 3. Собрать кандидатов несколькими способами
Если готового правила нет, система запускает три поиска.
Нечёткое совпадение
RapidFuzz сравнивает нормализованные строки и отбирает близкие названия. Перед этим раскрываются несколько рабочих сокращений, а кандидаты фильтруются по категории товара.
Этот слой быстрый, но одинаковые слова ещё не доказывают, что размер и модель совпадают.
Точная маркировка
Отдельный регулярный разбор извлекает токены вроде SM 300. Поиск учитывает границы токена, чтобы короткая модель не совпала с частью другого артикула.
Такой слой появился после реальной ошибки: смысловой поиск мог поставить выше товар с похожим описанием и потерять точную модель из заявки.
Смысловой поиск
Названия из справочника заранее преобразуются в embeddings и хранятся в ChromaDB. Для новой строки система получает ближайшие по смыслу позиции. После неудачи с локальной моделью embeddings строятся через облачный API Gemini, а индекс хранится локально.
Важная деталь: крупные модели эмбеддингов обучены на асимметричный поиск. Позиции справочника индексируются с типом задачи RETRIEVAL_DOCUMENT, а строка заявки отправляется с типом RETRIEVAL_QUERY. Так модель ищет документ под запрос, а не просто похожий текст.
Если фильтр категории не дал результатов, поиск повторяется без него. Ошибка классификации категории не должна обнулить весь подбор.
Шаг 4. Дать LLM ограниченную задачу
Модель не ищет товар во всей базе и не сочиняет название. Она получает исходную строку и до 20 лучших уникальных кандидатов. В проекте работает Gemini 2.5 Flash Lite, ответ — строгий JSON. Упрощённый пример:
Клиент запросил: «Вентилятор канальный SM 300»
Кандидаты из справочника 1С:
1. Вентилятор SM 300, 230 В
2. Вентилятор SMI 300 EC
3. Вентилятор SM 250, 230 В
Выбери один вариант или верни null.Ответ ожидается в JSON. Если модель возвращает лишнее пояснение, код выделяет JSON-объект. При timeout, ошибке API или отказе выбрать кандидата позиция не становится автоматически подтверждённой.
Такая постановка проще для контроля. Модель сравнивает варианты, которые действительно существуют в справочнике.
Шаг 5. Проверить числа и маркировки кодом
После LLM остаётся обычная валидация. Она нужна даже при высокой уверенности модели.
В рабочем матчинге автоматический зелёный статус требует высокого порога и совпадения значимых чисел. Если у кандидата есть размер, которого не было в запросе, автоподтверждение блокируется. Если модельные токены исходной строки и выбранной позиции различаются, результат понижается до жёлтого.
Количество тоже может потребовать преобразования. Например, клиент указывает метры, а в 1С товар учитывается штуками фиксированной длины. Такие правила должны быть написаны в коде и проверены для конкретной категории. LLM не должна сама решать, сколько упаковок получится из 200 штук.
Шаг 6. Показать человеку спорные строки
В интерфейсе используются три статуса:
- зелёный: правило или проверки дают достаточно оснований для автоматического выбора;
- жёлтый: кандидат есть, но его нужно подтвердить;
- красный: подходящей позиции нет либо менеджер её отклонил.
Для жёлтой строки менеджер выбирает предложенный вариант или ищет другой товар в выпадающем списке. Красная строка не должна молча превращаться в ближайший результат.
После подтверждения система формирует Excel с исходной фразой, выбранной номенклатурой, количеством, единицей и статусом. Отдельный аудит сравнивает исходное предложение ИИ с финальным решением менеджера.
Как система учится и не закрепляет ошибку
Подтверждение заявки и обучение словаря разделены.
Менеджер может закончить конкретный заказ. Новая пара после этого попадает в очередь администратора. Администратор видит исходную строку и выбранный товар, затем принимает, заменяет или отклоняет соответствие.
Только одобренная пара начинает давать мгновенный зелёный результат в следующих заявках. Для отдельных клиентов правила хранятся отдельно. Это полезно, когда одинаковое слово у двух заказчиков означает разные внутренние позиции.
Четыре ошибки, которые стоит проверить до запуска
Количество стало названием товара
Excel пришёл без ожидаемой шапки, и парсер выбрал числовую колонку. Мы добавили профилирование столбцов и повторный выбор, если большая часть значений является числами.
Модель потерялась в семантике
Слова категории оказались сильнее артикула. После этого маркировки стали искать отдельно и добавлять найденные позиции в список до LLM.
Похожий размер получил высокую оценку сходства
Текст почти одинаковый, но отличается диаметр или индекс модели. После поиска код отдельно сверяет числа и маркировки.
Отклонённая подсказка стала новым правилом
Менеджер убрал кандидата, а запасная логика вернула его в итог. Теперь у красной строки нет автоматического значения, а обучение проходит через очередь администратора.
API рабочего процесса
В этой системе загрузка и обработка разделены. Это не даёт тяжёлой задаче стартовать до проверки входа:
POST /api/crm/chat/upload
→ preview_id и число строк
POST /api/crm/chat/start/{preview_id}
→ task_id
GET /api/crm/chat/task/{task_id}
→ прогресс и session_id
GET /api/session/{session_id}
→ кандидаты и статусы
POST /api/session/{session_id}/approve
→ подтверждённая сессия
POST /api/session/{session_id}/export-excel
→ итоговый ExcelЗагрузка, запуск обработки и просмотр прогресса в CRM требуют JWT. Изменение номенклатуры и очередь новых маппингов доступны администратору. Production URL, реальные IDs и секреты в статью не выносятся.
Что показал прогон 2 900 строк
В историческом прогоне обработали 2 900 позиций из клиентских заявок. Ниже — статусы строк после поиска, а не точность модели:
| Статус строки | Округлённая доля от всех строк прогона |
|---|---|
| Автоматическое совпадение | Около 9 % |
| Кандидат найден, нужна проверка инженером | Около 90 % |
| Подходящей позиции не нашлось | Около 1,5 % |
Это приблизительные значения одного прогона; из-за округления сумма отличается от 100 %. Они показывают объём ручной проверки, а не гарантируют качество на новых заявках. Решения LLM внутри каскада — другой этап, их не смешиваем с итоговыми статусами строк.
Качество проверяем отдельно на размеченных строках: был ли выбран правильный товар, совпали ли размеры и что изменил инженер. Одобренные администратором пары можно повторно использовать; насколько это сокращает ручную работу, нужно измерять на следующих заказах.
Чаще всего модель отклоняла кандидатов из-за несовпадения размеров и диаметров, реже — из-за брендов. Иногда позиции просто нет в 1С: в этой базе не было ни одной крестовины, только тройники, и отказ сопоставлять был правильным.
Одна строка из реального прогона
Клиент запросил «Пятиступенчатый трансформаторный регулятор скорости R-E-12». Слова похожи у нескольких товаров, поэтому важно проследить всю строку до решения менеджера:
| Этап | Что получилось |
|---|---|
| Нечёткий поиск | Первым оказался R-D-2G с оценкой 93 % |
| Векторный поиск | Первым оказался R-E-12 с оценкой 88 % |
| Проверка моделью | Из 14 кандидатов выбрана R-E-12; в объяснении совпали модель и число ступеней |
| Передача менеджеру | Жёлтая строка, требующая подтверждения; уверенность модели 0,88 не сделала её автоматически зелёной |
Проценты двух поисков относятся к разным способам сравнения. Их нельзя складывать или выдавать за точность всей системы.
После проверки результат выгружается в Excel с исходной фразой, номенклатурой, количеством и статусом. Новое постоянное соответствие отдельно одобряет администратор. Кейс LISVENT показывает весь маршрут заявки; в услуге обработки заявок перечислены системы и состав пилота.
Как оценивать качество
Одной общей «точности» недостаточно. На размеченном наборе полезно считать отдельно:
- сколько строк разобрано без потери;
- долю автоматических зелёных совпадений;
- ошибочные зелёные, это самый дорогой класс;
- сколько жёлтых менеджер принял без изменения;
- сколько кандидатов он заменил;
- сколько красных действительно отсутствовало в справочнике;
- среднее время проверки одной заявки;
- число новых правил, которые администратор отклонил.
Особенно важно измерять ложные зелёные. Пустая строка заметна и уйдёт человеку. Уверенно выбранный неправильный товар может попасть в счёт.
Где проходит граница автоматизации
Модель помогает понять человеческую формулировку и сравнить кандидатов. Код отвечает за формат, числа, единицы, права и статусы. Менеджер решает спорные строки. Администратор контролирует, чему система научится на будущее.
В текущем проекте результатом является проверенный Excel: оператор видит все позиции с цветовой маркировкой и копирует проверенные строки одной кнопкой для вставки в 1С. Прямого создания документа в 1С нет. Как вообще подключать ИИ к 1С — через OData, HTTP-сервисы или обмен файлами, — разобрано в отдельной статье.
Geron Labs может проверить такой каскад на обезличенной выгрузке и наборе реальных заявок. Похожий поиск по каталогу работает и в подготовке КП из тендерного ТЗ. Для пилота достаточно справочника, нескольких типовых файлов и сотрудника, который знает цену неправильного сопоставления.