Хорика · простыми словами · сделано 7 сентября 2026

Почему ресторану предлагают не то

Я прочитал ваш каталог, оба отправленных КП и код — подряд, глазами. Сделано и проверено на боевых данных. Здесь: что было сломано, что теперь работает иначе, и цифры пересобранного предложения. Без терминов.

✓Что уже сделано

Решение построено и проверено на ваших данных. Ниже — что изменилось в отправленном КП, если пересобрать его заново.

КП‑2026‑0001 для ilpatio.ru, пересобранное по новой схеме
ЧтоБылоСтало
Разделов в документе10078, каждый — под слово, для которого товар есть в нужном виде
Соус наполирыбный, чесночный, сырный3 настоящих соуса для пиццы
Сыр фетарикотта, моцарелла, чеддер4 феты НАК
Сыр горгонзолате же триMonBlu Горгонзола
Тесто для пиццытайские спринг-роллы, 26 блюдне печатается; менеджер видит пробел
Расширение меню, 8 пиццспринг-роллы во всех, рыбный соус в 6моцарелла блоками, горгонзола, пармезан, пицца-соус — по каждой пицце
Рыбный соус за 0 ₽11 раз в документе0 раз
Пробелыисчезали молча159 видны менеджеру с пояснением и вариантами «на решение»
«Сыр» в Маргарите«нет в номенклатуре» — при двухстах сырах«есть, на решение менеджера», варианты рядом
«Сливки кокосовые» в том‑ямеобрезались до «сливки» — шли молочныеслово доходит целым, находятся кокосовые
«Курица» в Цезареварёно‑копчёная грудка печаталась как курицана ваше решение, с пометкой «копчёное» (ваше правило 07.09)
«Огурцы» в греческом салатемаринованные из банки печатались как огурцына ваше решение; под «огурцы маринованные» — печатаются
«Соус томатный» для пиццыкетчуп первымКраснодарский и два пицца‑соуса
«Сироп ванильный»любой из 33 сиропов, хоть арбузныйтолько ванильный; нет вкуса — пробел
Моцарелла под пиццушарики по 100 г первыми — дешевле за пачкублоки 2–3,6 кг: цена сравнивается за килограмм
Покрытие ilpatio.ru72 %40 % с родственными, 39 % точное — честные

Сколько это стоит в работе

ЧтоСколько
Сборка одного КП на 242 блюдаоколо 2 секунд, обращений наружу — ноль
Раскладка всех 1633 блюд меню заново, целыми словами15 минут машинного времени на прогон, денег 0
Разовый разбор каталога моделью (черновик)37 минут машинного времени, денег 0
Подбор под один ингредиент0,4 мс
То же, если каталог вырастет вдесятеро4,1 мс — рост ровный

Что проверено на живой базе

правка живётПоправил товар руками, перезалил справочник — правка на месте Запись привязана к коду 1С, а не к названию: выгрузка её не стирает.
новое не ломаетДобавил товар с незнакомым кодом — он встал в очередь разбора Пока товар не разобран, клиенту он не предлагается вовсе.
контрольный набор61 проверка из вашей спецификации проходит на настоящем каталоге Включая все «не должно совпасть ни при каких условиях» и ваши решения по консервам и копчёному.
два прогона модели1633 блюда разложены дважды: 25 % блюд разложены слово в слово одинаково, в среднем 63 % слов совпадают Модель меняет формулировки («лимонный сок» / «сок лимонный»), поэтому каждое написание разобрано отдельно и один раз; на подбор разница слов не влияет.
чтение глазами467 строк, которые уйдут в документы трёх заведений, прочитаны по одной, с причиной у каждой Так нашлись кетчуп под «томатным соусом» и розничные пачки впереди блоков; оба исправлены до вас.

Чего я не сделал

101 раскладка блюд осталась сломанной. «Мякоть молодого бычка одним отрубом» по-прежнему сжимается до слова «мякоть» ещё до того, как дело доходит до товаров. Со стороны каталога это не лечится — это отдельная работа.

Отдельного экрана справочника во фронте нет. Пробелы, пояснения и позиции «на ваше решение» менеджер видит в подборе; чтобы править разбор через интерфейс и одним нажатием брать такую позицию в документ, экран надо дорисовать.

Модель может назвать не тот ингредиент. Пример из IL Патио: пицца «Аль Сальмоне» разложена как ролл — с рисом для суши и нори. Под таким блюдом окажется настоящий, но не тот продукт. Это видно в раскладке на карточке заведения и правится один раз для всех заведений с таким блюдом. Правило «ничего не печатать молча» такую ошибку не ловит — ловит человек.

Винная карта без раздела «Напитки» проходит как блюда. Состав у них пустой, в покрытии они не участвуют, но в числе блюд считаются: у IL Патио 22 из 242.

На прод не выкладывал. Всё в отдельной ветке, проверено на копии боевых данных. Старая система из кода удалена целиком: модули обрезания названий, поиск по кускам слов, разбор по первому слову, корпус чужих рецептов, колонки обрезков в базе.

→Как это устроено

Про каждый товар один раз записано, что это такое. Подбор идёт по этой записи, а не по обрезкам названий.

Сейчас система при каждой сборке КП заново гадает по названию. Предложение — перестать гадать: завести таблицу, где про каждый товар 1С один раз записано, чем он является.

Что в записи

Четыре поля. Все выбираются из готового списка, а не пишутся свободным текстом — это принципиально, объясню ниже.

Пример записи: «85.62.28. Смолевичи бройлер. Наггетсы ТЕМПУРНЫЕ, 2кг»
ПолеЗначениеЗачем оно
что этонаггетсыСам продукт. Больше не обрезок названия
из чегокурицаСтавит наггетсы под курицу — ваше правило
в каком видеполуфабрикатНе даёт им попасть под «куриную грудку»
заменительнетОтделяет настоящий продукт от аналога

Почему из списка, а не своими словами

Я замерил это на ваших данных. Когда модель выбирает из готового списка — она отвечает одинаково в 93–100 % случаев. Когда придумывает формулировку сама — в 76 %, и «йогурт греческий» с «йогуртом греческим натуральным» уже не склеиваются в одну группу. Поэтому списки закрытые.

Почему исправления перестанут стираться

Запись привязана к коду товара в 1С, а не к его названию. Сейчас при каждой выгрузке поле ingredient_canonical пересчитывается заново и затирает всё — это видно в коде, sync.py, строка 72. Новая таблица к названию не привязана, и выгрузка её не трогает вообще.

Что именно исчезнет из КП

Не список заплаток — каждый дефект уходит по механизму.

Что происходит сейчасЧто это убирает
Паста карри и пралине под «Пасту»«что это» у них — паста карри и кондитерская паста
Фасоль под «Соль», печенье под «Печень»Поиска по кускам слов больше нет вообще
Мякоть помидора под мякоть бычка«из чего» — томат, а не говядина
Картофель фри под оливье, кранч-лук под свежий лук«в каком виде» — полуфабрикат и сушёное
Фета, горгонзола, грюйер, бри не находятся«что это» записано, обрезок названия не участвует
Чёрный перец под «перец» в Примавере, где нужен болгарскийОбщее слово ничего не печатает само — решает менеджер
35 складов и строк кросс-докинга лежат в каталоге как еда«это не еда» — модель определила без единой ошибки
8 ключей на сливочное масло, 20 на шоколадОдна запись «сливочное масло», одна «тёмный шоколад»
«Сливки кокосовые» в раскладке обрезались до «сливки»Слово блюда хранится целым; что оно значит, решает та же запись
Любой из 33 сиропов под «сироп ванильный»Вкус — тоже продукт: свой узел, нет вкуса — пробел
Маринованные огурцы под «огурцы», грудка в/к под «курицу»У каждого слова есть естественная форма продукта; всё другое — на решение менеджера
Кетчуп первым под «соус томатный» для пиццыКетчуп — свой продукт, а не частный случай томатного соуса
Шарики моцареллы по 100 г впереди блоковЦена сравнивается за килограмм, а не за пачку

Чего это не решает

Рыбный соус по 0 ₽ останется. Он лезет вперёд не из-за названий, а из-за правила «показывай самое дешёвое» — select.py, строка 141. Чинится отдельно, за час, и починить стоит в любом случае.

101 раскладка блюд останется сломанной. «Мякоть молодого бычка одним отрубом» сжата до слова «мякоть» ещё до того, как дело доходит до товаров. Со стороны каталога это поправить нельзя — на вход подаётся слово «мякоть». Это надо включить в работу отдельным куском.

Как решён вопрос про аналоги

Взято из вашей же спецификации, контрольный набор: «все моцареллы, включая «Продукт белково-жировой Моцарелла» с пометкой, что это аналог». Аналог входит в группу, всегда с пометкой в документе, и никогда не встаёт выше настоящего продукта.

Ниже — как я к этому пришёл: что сломано, почему списками это не чинится, что я замерил и какие ещё пути рассматривал (раздел 06 — все четыре, включая те, что отверг, и почему).

01Что происходит

Система сравнивает не продукты, а первое слово названия. Совпало первое слово — товар едет клиенту.

Три примера из документа, который уже ушёл в IL Патио.

Паста

Пенне Арабьята, Мясная лазанья, Паппарделле Ресторану нужна паста — макароны. предложили Бельгийское пралине из фундука и тайскую пасту карри. Оба названия начинаются со слова «Паста».

Соль

Мясная лазанья, Спагетти болоньезе, ещё 12 блюд Ресторану нужна соль. предложили Три банки красной фасоли. Потому что «соль» — это кусочек слова «фасоль».

Печень

Куриная печень Ресторану нужна куриная печень. предложили Печенье Савоярди для тирамису. «Печень» — кусочек слова «печенье».

Мякоть

Мякоть молодого бычка одним отрубом Ресторану нужен кусок говядины. предложили Мякоть помидора Pomi. Одно слово — два совершенно разных продукта.

Таких мест в одном КП — 47 разделов из 100. А в блоке, где мы сами предлагаем ресторану добавить блюда, все восемь пицц собраны на тайской рисовой бумаге для спринг-роллов вместо теста.

02Почему так вышло

Внутри системы нет никакой записи о том, что такое товар. Есть только его название из 1С, и от названия отрезаются первые одно-два слова. Этот обрезок и считается «продуктом».

Что делает система с названием
название90.70.226. Callebaut. Паста из фундука 24% и миндаля 24% (пралине), вед. 5кг
отрезаликод, бренд, вес, упаковку
осталосьпаста Всё, что делало это пралине — фундук, миндаль, слово «пралине» — выброшено. Осталось слово «паста».

И то же самое происходит со стороны блюда. «Куриная печень» превращается в слово «печень» — курица отброшена. «Филе-миньон из фермерской говядины» превращается в слово «филе» — говядина отброшена. «Зелёный салат с баклажанами» превращается в слово «салат» — и совпадает с салатом из водорослей Чука.

Система сравнивает обрезок с обрезком. Ни на одной стороне никто не знает, что такое продукт.

И это не чинится списками. Можно добавить слово «белая» в список прилагательных, можно запретить искать «соль» внутри «фасоли». Но каждая новая выгрузка из 1С приносит написания, которых в списках нет. А главное — правку некуда записать: при каждой загрузке из 1С все обрезки считаются заново, и любое исправление стирается.

03Что я нашёл нового

Три вещи, которых в спецификации нет.

Фета есть. И горгонзола есть.

В спецификации написано, что их нет в каталоге. Это не так — они есть, просто система их не видит.

4 позицииНАК. Сыр расс. «ФЕТА» 45% — кубики и куски, четыре фасовки Первые два слова названия — «Сыр расс.». Обрезок вышел «сыр расс», и запрос «фета» до него не доходит.
1 позицияMonBlu. Сыр с гол. плесенью «ГОРГОНЗОЛА» 50%, круг 2,5кг Второе слово — предлог «с», его выбрасывают. Осталось просто «сыр» — вместе со ста пятьюдесятью другими сырами.

Это хорошая новость: у вас шире ассортимент, чем показывает система. Ресторану, который просил фету, мы предложили рикотту и чеддер, хотя фета лежала на складе.

Товары с нулевой ценой лезут вперёд всех

Тайский рыбный соус попал в одно КП одиннадцать раз. Не потому, что больше нечего было предложить. А потому, что когда система не может выбрать, она берёт самое дешёвое — а у этого соуса в базе стоит цена 0,00 ₽. Ноль дешевле всего.

Таких товаров с нулевой ценой — 28. Каждый лезет наверх своей группы. Из-за этого же «Картофельные дольки со специями» стоят первыми в разделе «Картофель».

Это чинится отдельно и быстро, и стоит починить в любом случае — даже когда всё остальное заработает.

Нужные товары часто лежат рядом — их просто не находят

Проверено вручную по боевой базе
Что просил ресторанЧто предложилиЧто было на складе
Томатный соус для римской пиццыТайский рыбный соус6 соусов для пиццы: SICA, MUTTI, Pomi, LOLI'K, LUNITO
Картофельное пюре к телячьим щёчкамПюре гуавы, инжира и тыквыDINNER SERVICE, Картофельное пюре
Кунжутное масло в соус барбекюСливочное и подсолнечное маслоREAL TANG, Кунжутное масло, 2 фасовки
Соус демиглас к ростбифуРыбный, чесночный, сырныйDINNER SERVICE, Соус Деми-Гласс
Кленовый сироп к ромовой бабеАпельсин, арбуз, базиликAGROBAR, Сироп «Клен» (Maple Syrup)
Грюйер и бри в сырную тарелкуМоцарелла для пиццы ×3Грюйер EKONIVA, бри President и Schonfeld
Тёмный шоколад в фондан3 позиции, две из них «без сахара»47 настоящих шоколадов

04Как это делают там, где решено

Я посмотрел, как эту задачу решают крупные сети, оптовые каталоги, продуктовые базы и закупочные системы. У всех одно и то же в основе:

  1. Никто не вычисляет продукт из названия в момент запроса. Продукт определяют один раз и записывают. Название — это то, что читают при записи, а не сам ответ.
  2. У записи свой номер, не из системы-источника. Поэтому перезагрузка каталога из 1С ничего не ломает: связь живёт отдельно от строки.
  3. Продукты стоят деревом, а не списком. «Бурый рис» — это частный случай «риса». Ровно ваше правило: наггетс — это курица, а курица — не наггетс.
  4. Когда система не уверена — она спрашивает человека, а не угадывает. Уверена — применяет сама. Неуверена — показывает вопрос. Исправления человека возвращаются обратно и больше не теряются.

Это стандартная связка, ей десятки лет: GS1 в торговле, FoodEx2 и LanguaL в пищевых базах, Open Food Facts в открытом виде.

05Что я проверил на вашей модели

У вас есть свой сервер с языковой моделью — llm.salam0nn.ru. Я взял самые трудные названия из каталога и спросил её, что это за продукты. Реальных денег это не стоит, только машинное время.

Что получилось хорошо

Из 24 самых трудных названий модель верно опознала 22. Нашла фету под «Сыр расс.», горгонзолу под «Сыр с гол. плесенью», вернула рыбу в «Дорадо с/м непотрош.». Пралине назвала кондитерской пастой, а не итальянской. Все склады и кросс-докинг пометила «не еда» — без единой ошибки. Все заменители сыра пометила заменителями.

Что получилось плохо

Модель не знает, когда она не уверена: на всех 24 ответах поставила «уверен», включая те, где ошиблась. И если задать один и тот же вопрос дважды, ответы расходятся: во втором прогоне наггетсы стали «точной курицей», а японский удон — «точной пастой».

Главное измерение

159 названий случайно прошли через модель по два раза. Вот насколько ответы совпали:

Что спрашивалиСовпалоВывод
Это еда или не еда?100 %Полностью надёжно
Это заменитель?98 %Надёжно
Из чего сделано?93 %Надёжно
Сырьё, полуфабрикат или консервы?88 %Требует проверки человеком
Название продукта своими словами76 %Так нельзя — ответы разъезжаются

Разница простая: когда модель выбирает из готового списка — она надёжна. Когда придумывает формулировку сама — «йогурт греческий» и «йогурт греческий натуральный» уже не склеиваются в одно.

Отсюда главный вывод: модель должна выбирать из готового справочника, а её ответ — записываться и замораживаться, а не пересчитываться каждый раз.

06Четыре пути

1. Завести справочник продуктов

советую

Один раз проходим каталог: у каждого товара записываем, что это за продукт — из готового списка, а не своими словами. Спорное подтверждает человек. Запись живёт в отдельной таблице, привязанной к коду 1С.

Дальше выгрузка из 1С может приходить сколько угодно раз — запись не тронется. Новые товары попадают в очередь на разбор и до разбора клиенту не показываются.

Что даёт
Ответ объясним словами. Исправление живёт вечно. Пробел виден. Проверяется обычными тестами.
Разовая цена
Проход модели по 1080 товарам — машинное время вашего сервера, денег не стоит. Плюс подтверждение человеком спорных позиций.
Каждый день
Разбирать только новые коды из 1С. Это десятки позиций, а не тысячи.
Где ломается
У справочника должен быть хозяин. Без него он через год зарастёт.

2. Спрашивать модель в момент сборки КП

не советую

Ничего не строим. Каждый раз при сборке КП отдаём модели весь каталог и спрашиваем, что подходит. Замерил: 26–63 секунды на одно КП.

Почему не советую. Я прогнал один и тот же вопрос дважды — ответы разошлись. Наггетсы стали «точной курицей», удон — «точной пастой». Именно та граница, которая защищает клиента от подмены, и поехала.

И главное: исправление некуда записать. Это тот же корень, что сейчас — ответ считается заново каждый раз и нигде не хранится. Меняется только тот, кто считает.

Где ломается
Ответы разъезжаются между прогонами. Модель недоступна — КП собрать нельзя. Объяснение каждый раз новое.

3. Описывать товар свойствами

хорошая добавка к первому

У товара не одна пометка, а несколько: из чего сделан (курица, молоко, томат), в каком виде (сырьё, полуфабрикат, консервы, заморозка), заменитель или нет.

Тогда ваше правило записывается прямо: наггетсы — это «курица» + «полуфабрикат». Под ингредиент «курица» они годятся, под «куриную грудку» — нет. И объяснение выходит само: «предложили, потому что сделано из курицы, но это полуфабрикат».

Это же убрало бы картофель фри под оливье и сушёный кранч-лук под свежий лук.

Где ломается
Замерил: свойство «в каком виде» модель ставит верно только в 88 % случаев — бекон с пометкой ЗАМ назвала охлаждённым. Это свойство придётся брать из пометок в названии правилами, а не у модели.

4. Копить подтверждения менеджеров

не советую

Ничего не размечаем заранее. Менеджер, собирая КП, отмечает: этот товар подходит, этот нет. Со временем накапливается.

Почему не советую. Пар «ингредиент — товар» больше миллиона. Первые месяцы КП не улучшаются вообще, а менеджер вместо работы занимается разметкой. И новый товар не наследует ничего — всё заново.

Показываю его потому, что это единственный путь совсем без модели, и вы вправе его увидеть.

07Что придётся тронуть сверх ожидаемого

Спецификация выносит качество раскладок блюд за границы задачи — «кроме случаев, когда исследователь докажет, что без этого задачу решить нельзя». Доказательство нашлось.

Так блюда разбираются сейчас
потеряно«Мякоть молодого бычка одним отрубом» → мякоть
потеряно«Филе-миньон от фермерской говядины» → филе
потеряно«Пенне с лососем в сливочном соусе» → соус
потеряно«Зелёный салат с баклажанами» → салат В названии блюда написано «говядины», «лососем», «баклажанами» — и всё это выброшено. Осталось одно слово.

Со стороны товара это не лечится: системе на вход подаётся слово «мякоть», а не «говядина». Таких разборов 101 — немного, но они попадают в дорогие блюда.

Что предлагаю включить в работу: эти 101 разбор и восстановление уточнений, которые теряются («куриная печень» должна оставаться куриной). Всё остальное про раскладки — не трогаем.

08Что мне нужно от вас

Два вопроса вы уже решили, и я их записал:

решеноКаждый наггетс — курица, но не каждая курица — наггетс Продукты стоят деревом. Под общее годится частное, под частное общее не годится.
решеноЧего нет — в документ не печатаем Раздела «Паста» в КП просто не будет. Менеджер при этом пробел на экране видит — иначе мы не узнаем, что не предложили ресторану то, что у нас есть.

Остались два. Оба про то, что считать правильным ответом — без них я не смогу сказать, верно работает вариант или нет.

1. «Белково-жировой продукт "Моцарелла"» — это моцарелла?

По закону это не сыр, а заменитель на растительном жире. Таких позиций в каталоге около сорока, и они дешевле настоящих. Предлагать их ресторану вместе с моцареллой, помечая «аналог»? Или называть своим именем отдельной позицией и не подставлять под моцареллу?

2. Кто разбирает каталог и сколько это допустимо?

Тысяча товаров разбирается человеком примерно за неделю — один раз. Дальше при каждой выгрузке из 1С разбирать надо только новые названия, это десятки позиций. Готовы на это, и кто этим займётся — вы, менеджер или кто-то нанятый?