Рестораны · Внутренняя система
Ostera
Сеть из 64 ресторанов: показатели пяти систем сведены в один слой, а вопрос о вчерашней прибыли задают словами и получают ответ вместе с исходными данными.
- Роль
- Аналитика, бэкенд, интеграции, ИИ-ассистент
- Срок
- 10 недель
- Стек
- NestJS · ClickHouse · OpenAI API
Что изменилось
- 2 часа → 18 минут
- ежедневный операционный разбор. Показатели собраны до того, как в них заглянули, — менеджеру остаётся решение.
- 4–7 дней → сутки
- среднее время между отклонением и тем, что его заметили: стало меньше 24 часов.
- −17%
- списаний в ресторанах пилотной группы за первые три месяца.
- +3,8 п.п.
- к средней операционной марже десяти пилотных точек.
Ни одну систему не заменяли: касса, склад и сервисы доставки остались на местах, а управляющих не заставили заполнять новую форму. Отсюда и предел: платформа знает ровно то, что есть в источниках, и чего там нет, в ней не появится.
Что было до
Утро регионального менеджера начиналось с кассовой системы, складской программы, кабинетов агрегаторов и таблиц с точек: показатели по своим ресторанам он сводил руками, источник за источником. В управляющую компанию всё это приходило пачкой отчётов, и каждый был чьим-то таким же утром. Проблема с food cost или списаниями всплывала в них не тогда, когда началась, а днями позже.
- 64 ресторана в трёх городах, и одинаковых среди них нет. Сравнение двух точек начиналось с вопроса, одинаково ли у них посчитан показатель, — и часто на этом же вопросе заканчивалось.
- Больше 40 ежедневных отчётов и таблиц доходило до управляющей компании. Это не 40 ответов, а 40 срезов, которые ещё предстояло сложить в один.
- Около 2 часов каждое утро уходило у регионального менеджера на сбор показателей — до того, как он успевал по ним что-нибудь решить.
- От 4 до 7 дней проходило между отклонением по food cost или списаниям и моментом, когда его замечали. К этому времени точка успевала отработать неделю с тем же отклонением.
Что сделали
Один слой метрик: 47 показателей посчитаны по общему определению для всех 64 ресторанов, а не собраны заново в каждом отчёте.
Пять источников в одной модели: касса, склад, агрегаторы доставки, таблицы с точек и учёт рабочего времени, сведённые общим справочником ресторанов и позиций.
Ассистент отвечает на вопрос, заданный словами, и показывает строки, на которых стоит ответ; утренняя сводка уходит без запроса.
Результат
Кассу, склад и доставку никто не трогал — они стали источниками, а разбор показателей переехал в слой над ними. Операционный директор спрашивает словами и получает ответ вместе с данными, из которых он собран; отклонение доходит до человека в тот же день, а утренняя сводка приходит раньше, чем кто-нибудь пошёл смотреть. Что делать с рестораном, по-прежнему решает человек: платформа доводит до него цифру и гипотезу, а не действие.
Кто заказчик
Сеть ресторанов: 64 точки в трёх городах, у каждой своя кухня, свой склад и свой управляющий. Над точками — управляющая компания, которая отвечает за экономику всей сети и до этого проекта видела её только через отчёты, приходившие снизу.
У точки есть выручка в зале и заказы у агрегаторов, закупки и списания, смены и часы персонала — и всё это в разных системах. Региональный менеджер ведёт несколько ресторанов сразу, и складывать эти цифры ему приходилось столько раз, сколько у него точек.
Задача
- Как ставил заказчик
- «Хотим один dashboard с продажами ресторанов»: выручка по всем 64 точкам на одном экране, чтобы за ней не ходить в четыре десятка таблиц.
- Как задача выглядела после разбора
- Интервью с управляющими показали: ещё один дашборд ничего не изменит. Данных было достаточно — не хватало интерпретации: цифры сходились, но не отвечали почему. Сделали не витрину, а ассистента операционного директора. Его спрашивают словами — «Где падение выручки объясняется трафиком, а где средним чеком?» — а он собирает показатели, находит аномалии, строит гипотезы и показывает данные, на которых стоит вывод.
Почему нельзя было в лоб
Главная сложность оказалась не в языковой модели. Данные лежали в пяти местах, в каждом по своим правилам, и прежде чем ассистенту стало что отвечать, их нужно было привести к одной модели и договориться, как считается каждый показатель.
- Кассовая система
- Чеки, выручка зала и средний чек живут в POS каждой точки. Оттуда видно то, что происходило в зале, но ни списаний, ни часов персонала там нет — а значит, любой показатель, где выручка делится на что-то ещё, собирается уже не из одного источника.
- Складская система
- Закупки, остатки и списания — та половина food cost, которой касса не видит. Чтобы показатель сошёлся, движение товара и проданное блюдо должны встретиться на одной позиции справочника, а встречались они не всегда.
- Агрегаторы доставки
- Часть выручки приходит мимо зала: заказ оформлен у агрегатора, а готовит его та же кухня. Пока доставка считается отдельно от зала, сравнение двух ресторанов зависит от того, какая доля заказов у каждого пришла снаружи.
- Excel-отчёты
- Часть показателей существовала только в таблицах, которые собирали на местах. У такого источника нет ни схемы, ни гарантии, что завтрашний файл придёт в том же виде: разбирать его нужно каждый день, а не один раз при подключении.
- Учёт рабочего времени
- Часы персонала лежат в отдельной системе и обновляются в своём ритме. Показатель, которому нужны два источника с разной частотой обновления, обязан нести правило на случай, когда второй ещё не приехал, — иначе он молча посчитается по неполным данным.
- Одно и то же под разными именами
- Названия ресторанов и товаров различались от системы к системе: одна и та же точка и одна и та же позиция назывались по-своему в кассе, на складе и у агрегатора. Пока это не сопоставлено, сводный показатель — не результат, а совпадение.
Как шла работа
- 01
Аудит данных и метрики
Недели 1–2Разбирали, что где лежит и что из этого можно посчитать: какие поля отдаёт каждая система, где они расходятся и какие показатели нужны управляющей компании. Итог этапа — не хранилище, а список из 47 метрик: у каждой записано, из каких источников она собирается и за какой период.
- 02
Интеграции и единое хранилище
Недели 3–5Пять источников подключены и приведены к одной модели: касса и склад, агрегаторы доставки, таблицы с точек, учёт рабочего времени. Здесь же собран справочник, в котором один ресторан и одна позиция имеют один идентификатор, как бы их ни называли на стороне источника.
- 03
Отклонения и алерты
Неделя 6Поверх посчитанных метрик появился слой, который сравнивает показатель точки с её собственной историей и отправляет отклонение адресату в тот же день. До этого этапа платформа умела показать цифру, но не умела сказать, что с ней что-то не так.
- 04
Ассистент и вопрос словами
Неделя 7Вопрос, заданный словами, стал ещё одним входом к тем же метрикам. Модель разбирает формулировку и выбирает показатели, разрез и период; считает по-прежнему хранилище, а к ответу прикладываются данные, на которых он построен.
- 05
Ежедневная сводка
Неделя 8То же самое без вопроса: executive summary собирается автоматически и приходит утром, до того как кто-нибудь успел спросить. На вопрос «какие точки требуют внимания сегодня» сводка отвечает раньше, чем его задали.
- 06
Пилот и переход сети
Недели 9–10Сначала десять ресторанов: показатели платформы сверяли с тем, что считали на местах, и расхождения разбирали до того, как сводку увидела вся сеть. После пилота на платформу перевели все 64 точки.
Технические решения
Стек выбран под объём данных и под вопрос, заданный словами: NestJS держит сервис и пять интеграций, ClickHouse считает метрики по всей сети, OpenAI API переводит вопрос, заданный словами, в обращение к этим метрикам.
Аналитический слой раньше ассистента
ИИ подключили последним, поверх нормализованных данных. В обратном порядке модель отвечала бы по пяти несогласованным источникам, и её ошибку нельзя было бы отличить от ошибки в данных. Сначала 47 определений и одна модель, только потом — вопрос словами.
Один идентификатор точки и позиции
Справочник соответствий: у ресторана и у товара один внутренний идентификатор, а имена из кассы, склада и агрегаторов лежат рядом с ним. Он же отвечает, откуда взялась строка в сводном отчёте, — без него сравнение двух ресторанов остаётся спором о названиях.
Метрика — определение, а не запрос
Каждый из 47 показателей описан один раз: источники, период, разрез. Сводка, алерт и ответ ассистента берут одно и то же определение, поэтому три места не могут дать три разные цифры по одному вопросу.
Модель выбирает показатели, считает хранилище
OpenAI API разбирает вопрос и превращает его в набор метрик, точек и дат; арифметику делает ClickHouse. Модель ничего не складывает и не держит числа в памяти — поэтому ответ воспроизводится, а рядом с ним показываются те самые строки, из которых он собран.
Отклонение находится до вопроса
Аномалии считаются на слое метрик и приходят сами: показатель, точка, период и то, с чем его сравнили. Вопрос директора и утренняя сводка — два входа в один и тот же расчёт, и поэтому обнаружение отклонения перестало зависеть от того, догадался ли кто-то посмотреть.
Что осталось за рамками
Часть работы сознательно не входила в платформу: либо источник принадлежит не нам, либо решение принимает человек.
Источники данных. POS, складская система и сервисы доставки остались у заказчика вместе со своими правилами и своим ритмом обновления: мы читаем их и не пишем в них ничего.
Ручной сбор на местах. Таблицы, которые составляют на точках, остались как были: платформа читает их каждый день, но не отменяет. Новую форму в сеть не приносили — вместе с ней не принесли и способ обойтись без старых.
Проверка гипотезы. Ассистент говорит, где показатель разошёлся и чем это может объясняться; сойдётся ли объяснение с тем, что происходит на кухне, выясняют на точке — туда платформа не смотрит.
Эффект по всей сети. И 17% списаний, и 3,8 п.п. маржи — это десять пилотных ресторанов. Остальные точки подключились позже, и такого же периода наблюдения по ним у нас пока нет.
Сейчас платформа работает на всех 64 ресторанах: утренняя сводка собирается каждый день, а отклонение доходит до адресата за сутки, а не за неделю.
Другие проекты
Страхование
Klarim
Разбирает пакет сканов по страховому обращению: находит поля в справках, фотографиях и выписках и переносит их в учётную систему.
40 → 6 минут
на разбор одного обращения
Python · FastAPI · Anthropic API
Логистика
Reista
Кабинет для клиентов транспортной компании: статус груза, маршрут и документы по каждой отправке — без звонка диспетчеру. Основная работа была не в кабинете: до проекта статус нигде не хранился, он жил в переписке водителей и в памяти диспетчера.
−70%
звонков в диспетчерскую
Next.js · TypeScript · PostgreSQL
Контакты
Пришлите описание задачи
Ответ с объёмом работ, сроками и оценкой бюджета придёт в течение 24 часов.
Первый звонок — 30 минут, без обязательств с вашей стороны.