Архитектура SaaS-аналитики прибыли для продавцов Ozon и Wildberries. Консилиум из трёх моделей, реверс-инжиниринг API, параллельные агенты Claude Code. Без приукрашивания — что сработало, а что нет.

Бизнес-контекст и ретроспектива первых недель — отдельной статьёй на VC.ru. Тут — техника.

Консилиум из трёх моделей-«провидцев» и арбитратор
Консилиум из трёх моделей-«провидцев» и арбитратор

С чего всё началось

Мой знакомый Николай держит на Ozon магазин постельного белья. Со стороны всё нормально: оборот есть, товар продаётся, кабинет не пустует. А денег в конце месяца — нет. Не «мало», а непонятно куда они делись.

Я стал разбираться — и понял, что это не его частная беда. Полный P&L по каждому товару никто не считает: на каталоге в 500–2000 позиций это часы в неделю. Товар крутится в топе по обороту — но оборот ничего не говорит о марже: после возвратов и рекламы он годами уходит в минус, в полной слепой зоне. Инструментов на рынке хватает, но почти все просто показывают ещё одну P&L-таблицу — много цифр, красиво, и ровно ноль ответа на вопрос «и что мне теперь с этим делать».

Так появился SKUmind — сервис, который сводит прибыль по каждому SKU и говорит, что с ней делать. Под катом — почему я выкинул привычную для BI логику на правилах, как собрал консилиум из трёх AI-моделей разных вендоров с арбитратором, как реверс-инжинирил Ozon API двумя параллельными сессиями Claude и почему ревью кода теперь съедает 60–70% времени.

Почему правила не работают

Когда строишь аналитику, первый инстинкт — написать правила. Быстро, и как будто логично:

if return_rate > 15%        then "флаг: высокие возвраты"
if ad_spend / revenue > 20% then "снизить рекламу"
if margin < 5%              then "снять с продажи"

И ровно настолько же бесполезно. Эти правила врут тем сильнее, чем разнообразнее рынок. 25% возвратов в одежде — обычное дело. Те же 25% в книгах — что-то сломалось. Высокая доля рекламы перед Новым годом оправдана, в феврале — нет. Комиссия 30% в БАДах никого не удивляет, в крупной бытовой технике она съедает экономику целиком.

Чтобы правила перестали врать, их надо делать категорийно-специфичными. А это десятки тысяч пограничных случаев. Если бы такой код писал человек, за пару месяцев он превратился бы в legacy, который потом страшно трогать.

Я пошёл иначе. SKUmind отдаёт финансовый контекст товара языковой модели и просит вердикт с объяснением — так, как ответил бы аналитик, который реально посмотрел на конкретный товар в конкретной категории. Не «риск 0.7», а «убыточен, потому что в этой категории 18% возвратов плюс реклама не отбивается».

От одной модели к консилиуму

Сначала было просто. Один Claude, один промпт, один вердикт на товар. Работало.

Но довольно скоро меня начало смущать одно: у одной модели один взгляд. Там, где она уверена, она уверена красиво и убедительно — а свериться не с чем. Это нервирует, когда от результата зависят деньги продавца.

Дальше сошлись две вещи. Первая — название продукта. SKUmind, и зашитая в него отсылка к «Особому мнению»: три провидца предсказывают будущее, иногда один расходится с большинством, и это расхождение — minority report — бывает важнее консенсуса. Вторая — чисто инженерное наблюдение. Если взять модели от разных вендоров, обученные на разных корпусах разными методами, их ошибки не совпадают. Где они согласны — туда можно ступать. Где спорят — там стоит притормозить и посмотреть внимательно.

Так метафора превратилась в архитектуру. Функция называется «Особое мнение» и под капотом это консилиум:

            ┌──────────────────────────┐
            │  Финансовый контекст SKU │
            │  (предрассчитан, без     │
            │   обращений модели в БД) │
            └────────────┬─────────────┘
                         │  параллельные вызовы
          ┌──────────────┼──────────────┐
          ▼              ▼              ▼
   ┌────────────┐ ┌────────────┐ ┌────────────┐
   │  Precog 1  │ │  Precog 2  │ │  Precog 3  │
   │  вендор A  │ │  вендор B  │ │  вендор C  │
   └──────┬─────┘ └──────┬─────┘ └──────┬─────┘
          └──────────────┼──────────────┘
                         ▼
            ┌──────────────────────────┐
            │   Арбитратор (Opus 4.7)  │
            │  синтез + матрица        │
            │  согласия + уверенность  │
            └──────────────────────────┘

Три модели-«провидцы» получают одинаковый контекст и отвечают независимо, не зная про ответы друг друга. Четвёртая — арбитратор, у нас это Opus 4.7 — видит все три анализа плюс исходный вопрос. Она синтезирует общий вердикт и отдельно показывает, где провидцы сошлись, а где разошлись. Согласие 3/3 — высокая уверенность. 2/3 — арбитратор честно говорит, что вопрос спорный, и объясняет, в чём именно спор.

У «Особого мнения» два режима:

  • Точечный. Продавец жмёт ? на конкретной кампании, товаре или ценовом решении —
    и получает консилиум прямо по нему, под конкретный вопрос.

  • Разбор всего кабинета. На вход уходит состояние кабинета целиком, на выходе — развёрнутый стратегический разбор: AI сам ищет проблемы и расставляет приоритеты. Результат сохраняется как артефакт — PDF, письмо на почту, отправка в Telegram, HTML-страница.

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

Архитектура: два контура и слой предупреждений

Сверху система делится на два контура с разной частотой.

┌──────────────────────┐
│   API маркетплейса   │  Ozon Seller + Performance API
│                      │  Wildberries Suppliers (в разработке)
└──────────┬───────────┘
           │ синхронизация по расписанию (1–24 раза/сутки)
           ▼
┌──────────────────────┐
│   Postgres warehouse │  сырые данные: транзакции, реклама,
│   (каждого селлера)  │  возвраты, метаданные SKU
└──────────┬───────────┘
           │ агрегация
           ▼
┌──────────────────────┐
│   Распределение      │  полный финансовый отчёт
│   расходов → SKU     │  по каждому артикулу
└──────────┬───────────┘
           ├──────────────┐
           ▼              ▼
┌──────────────────┐ ┌──────────────────┐
│  AI-анализ       │ │  Слой            │
│  (консилиум,     │ │  предупреждений  │
│   еженедельно)   │ │  (детекторы,     │
│                  │ │   ежечасно)      │
└────────┬─────────┘ └────────┬─────────┘
         └────────────┬───────┘
                      ▼
            ┌──────────────────┐
            │  Кабинет + отчёт │
            │  + Telegram      │
            └──────────────────┘

Сырые данные тянутся с API часто — где-то раз в час, где-то четыре раза в сутки. Продажи, карточки, заказы FBO и FBS — каждый час. Остатки по регионам — дважды в сутки. Возвраты — раз. Это нужно, чтобы реагировать на операционку без задержки.

AI-анализ работает по-другому: раз в неделю — полный разбор по всему каталогу, на части поверхностей кабинета — облегчённый ежедневный. Продавцу не нужна классификация SKU поминутно, ему нужно понимать, что делать на этой неделе. Гонять консилиум в реальном времени стоило бы кратно дороже и не дало бы ничего.

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

Разница в том, для чего правила применяются. Для вердикта «убыточен ли товар» правило врёт — слишком много категорийных нюансов. А чтобы заметить, что выручка за сутки просела вдвое, правило идеально. Заметить аномалию и вынести вердикт — две разные задачи.

Ценность этого слоя — в скорости. Продавец узнаёт об аномальном событии практически в реальном времени — уведомление в кабинет и в Telegram, не дожидаясь еженедельного разбора. Детекторы работают на голом SQL, без моделей. Модель подключается потом — когда аномалию надо не заметить, а объяснить.

Claude API в роли аналитика: форма запроса

Код ниже — псевдокод, не production. Реальную структуру промптов, системные инструкции и схему вывода я не публикую. Методология нарабатывалась неделями подбора и до сих пор калибруется — это ключевая экспертиза продукта. Псевдокод показывает форму. И только форму.

Роль: независимый аналитик прибыли SKU на маркетплейсе

Контекст:
- метаданные товара (категория, ценовой сегмент, себестоимость)
- финансовая динамика за 6 недель (выручка, комиссии,
  возвраты, реклама, фулфилмент, налоги, чистый P&L)
- категорийные бенчмарки (медиана возвратов, типичная
  доля рекламы, целевой ROAS)

Задача:
- классифицировать товар: убыточный / поднять цену /
  растить / стабильный
- объяснить вердикт одной фразой

Вывод: структурированный JSON

Это я заложил в логику сразу: модель не ходит в базу и не дёргает API сама. Весь контекст собирается заранее и приходит готовым блоком. Модель только рассуждает. Так быстрее, предсказуемее и дешевле — а ещё проще отлаживать, потому что вход воспроизводим.

Каждый SKU — отдельный запрос. На каталоге в 500 товаров это 500 запросов в неделю на одного продавца. Да, это дороже правил, где вычисление стоит копейки. Но качество несопоставимое: продавец получает не абстрактную оценку, а понятное «делай вот это вот поэтому». За это и платят.

Сколько это стоит

Подход на AI дороже rule-based по определению, и я не буду делать вид, что нашёл волшебную экономию. «Особое мнение» — это полноценный дорогой вызов: три топовые языковые модели как провидцы плюс Opus 4.7 арбитратором. Четыре прохода больших моделей на каждый разбор.

Очевидный ход для удешевления — кэширование промптов: общая часть контекста (методология, описания категорий, бенчмарки) одинакова между запросами, по идее её можно не пересчитывать. У нас это не сработало — на нашем gateway кэш молча не подхватывался, и полагаться на него было нельзя.

Так что да, операция дорогая — и это осознанный выбор. На расчёте прибыли, по которому продавец будет принимать решения, экономить на моделях нельзя: дешёвый вердикт, которому не получится доверять, не стоит ничего. Конкретные цифры — стоимость на SKU, тарифные пороги — не привожу, они калибруются на первых продавцах.

Реверс-инжиниринг Ozon API

До первой строчки production-кода надо было понять, что Ozon Seller API реально умеет. Документация официальная и подробная. Но методов много, версии разные (v1–v6), часть эндпоинтов устарела, часть только для Premium-тарифа, а часть просто упоминается и молчит в ответ.

Сверять каждый метод руками — недели. Я сделал по-другому: две параллельные сессии Claude, одна в браузере, вторая на компьютере.

Сессия в браузере. Я запустил Claude как расширение Chrome прямо в окне Ozon Seller-кабинета. Расширение смотрело за всеми API-запросами, которые интерфейс кабинета делает в фоне: вытаскивало эндпоинты, параметры, реальные ответы с настоящими именами полей, отмечало неочевидные переменные. По сути перехват трафика — но не MITM-прокси, а живой агент, который понимает, что видит, и умеет показать пальцем на интересное. Находки уходили во вторую сессию.

Сессия на компьютере. Тут работал Claude Code с официальной документацией Ozon, загруженной локально. Он принимал находки из браузера и сверял их с документацией: где совпадает, где «дока обещает X, а API возвращает Y», какие эндпоинты на самом деле мертвы или спрятаны за Premium. Получалась перекрёстная проверка — документация против того, что кабинет делает на самом деле.

За два дня собралась полная карта актуальных версий методов, список из десятков расхождений между докой и реальностью, и структурированная база ограничений по тарифам и rate-limits. Конкретные числа найденного я не публикую — это та самая разведка, которая дала фору. Но против ручного чтения документации это сэкономило недели три.

Почему здесь нужен 1M контекст

Документация Ozon Seller API целиком не влезает в обычное окно на 200k токенов — это несколько мегабайт текста. А даже если бы влезла впритык, не осталось бы контекста на саму работу с ней. Пришлось бы резать на куски — и модель потеряла бы перекрёстные ссылки между разделами. А они тут критичны.

Конкретный случай. Браузерная сессия прислала находку с полем accrual_type в реальном ответе. Чтобы понять, что это поле значит и какой эндпоинт обрабатывает его правильно, нужно одновременно держать перед глазами раздел про транзакции, справочник начислений, перечень их типов и примеры запросов. Это четыре разных места документации. В нарезке на чанки сверка не складывается — контекст рвётся ровно там, где нужен.

В режиме 1M (Opus 4.7 или Sonnet 4.6) вся дока лежит в одной беседе. Это меняет сам способ работы с большими API. Не «спросил — получил ответ», а «вывалил всё разом и поток входящих сигналов сверху — а теперь итерируй гипотезы».

Схема переносится на любой крупный API со сложной документацией — Wildberries, Amazon SP-API, Stripe, Telegram Bot API. Дока целиком в Claude Code с 1M контекстом, расширение Claude в живом интерфейсе продукта на перехвате трафика, перекрёстная сверка, структурированная база знаний на выходе.

Разработка: параллельные агенты Claude Code

Claude в SKUmind на двух уровнях. Первый — в продукте, как аналитик. Второй — на разработке, и это отдельный разговор.

Выглядит так. Я открываю план в Claude Code, план режется на 3–5 параллельных задач, под каждую Claude Code заводит агента в своём git worktree. Агенты работают сами по себе: пишут код, тесты, открывают PR. Я ревьюю и мержу.

По темпу за три недели с момента старта вышло под 200 смерженных PR — в среднем около десяти в день. В вялый день, когда я подхожу к проекту на час, выходит 4–5; в обычный — заметно больше. Каждый PR на 200–500 строк с тестами. Тесты, кстати, влетели в копеечку по-своему: за эти недели мы сожгли больше 2000 минут CI и упёрлись в месячный лимит GitHub Actions.

Звучит как «AI пишет код за меня». Честная картина другая: ревью теперь съедает 60–70% моего рабочего времени. Узкое место просто переехало. Раньше скорость упиралась в то, как быстро пишется код. Теперь — в то, как быстро я решаю, что вообще строить.

Без пары оговорок картинка будет приукрашенной. Claude Code не пишет идеальный код — нужны типизация, тесты, линтер, иначе огрехи копятся тихо. Архитектуру всё равно держу я: агент силён в исполнении, но не в проектировании, дай ему расплывчатую задачу — получишь расплывчатый PR. И главный риск тут не плохой код. Главный риск — быстрый код не туда. Когда исполнение почти ничего не стоит, цена ошибки в выборе направления только растёт.

Финансовые расчёты Ozon: природа сложности

Точные формулы распределения расходов не привожу — это методологическая ценность продукта. Но про саму природу сложности рассказать стоит. На ней спотыкаются все, кто берётся считать прибыль на маркетплейсе, и я не был исключением.

Выплата — это не прибыль. То, что приходит продавцу на счёт, складывается из нескольких финансовых документов с разными правилами. Напишешь в коде «выплаты → P&L» — попадёшь на 10–30%. Корректный расчёт требует разобрать несколько источников начислений, и пока сам не упрёшься, это совершенно неочевидно.

Дальше — полиморфизм идентификаторов. В разных типах операций одно и то же поле id значит разное: где-то номер заказа, где-то номер отправления, где-то ссылки нет вообще. Без явной логики разбора по типу операции атрибуция расходов едет молча.

Лимит НДС в 20 млн ₽. После 20 млн годовой выручки УСН 6% превращается в УСН плюс НДС, и эффективная ставка прыгает с 6% до примерно 12–14% — сразу на весь каталог. Не заложишь в модель — потеряешь около 8% маржи на половине товаров и будешь долго не понимать почему.

Часть данных живёт за Premium-тарифом. Конкурентная аналитика и ряд полей доступны только на верхних тарифах подписки самого продавца. API это не обходит, и закладываться надо сразу.

Rate-limits жёсткие. Синхронизация 500 SKU с многонедельной историей транзакций требует backoff и retry. Наивное for sku in skus: get_data(sku) упрётся в лимит на первых десятках товаров.

И последнее: документация отстаёт от API. Часть эндпоинтов исчезла, а в доке осталась. Production-код должен такое переживать, а не падать.

Каждый из этих пунктов когда-то стоил мне отдельного вечера. Поэтому они задокументированы — память команды дешевле, чем заново ловить те же грабли.

Что пока не решено

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

Категорийные бенчмарки и циклическая зависимость. Чтобы AI сказал «возвраты выше нормы», нужна сама норма по категории. Считать по своим подключённым продавцам — смещение выборки: наши продавцы это не рынок. Брать публичные данные Ozon и WB — доступны кусками. Спрашивать самих продавцов — мало кто заполнит. Сейчас работает смесь первого и второго, но для первого продавца в новой категории это холодный старт, и красивого решения у меня нет.

Консилиум по одному SKU или пакетом. По одному — лучше качество объяснений, модель отдаёт всё внимание одному товару. Пакетом — дешевле и мягче к rate-limits. Пока остаёмся на «по одному»: качество вердикта мне важнее экономии. Но на росте до тысяч продавцов это придётся пересматривать, и где окажется точка перелома — я честно не знаю.

Бонус: AI как корректор

Неожиданный побочный эффект работы с Opus 4.7 на 1M контексте: модель замечает опечатки в текстовых полях документации и в названиях полей API раньше, чем человеческий глаз. Просто потому, что видит всё сразу и цепляется за несогласованность.

Так мы нашли несколько опечаток в API-полях Ozon. На production они не влияют, но факт забавный — инструмент для разбора структуры заодно работает корректором. На несколько сотен методов пять опечаток это около 0.01%, объективно мало. Просто новое применение инструментов с большим контекстом.

Если кто-то из коллег Ozon Tech читает — с радостью передам координаты по любому удобному каналу.

Вопросы к сообществу

Если вы строили похожее, мне правда интересно:

  1. Кто гоняет несколько LLM в production ансамблем? Как устроен арбитраж и как меряете согласованность?

  2. Embeddings для категоризации товаров — оправданно для маркетплейс-домена или избыточно?

  3. Опыт с rate-limits Ozon Performance API — как сделана retry-логика?

  4. Wildberries Suppliers API — кто интегрировался без боли, и был ли он вообще?

Что дальше

Из ближайшего: интеграция с Wildberries и переход с синхронизации по расписанию на webhook ради обновлений ближе к реальному времени.

Буду рад разбору в комментариях, особенно по открытым вопросам выше.

Ссылки

  • Открытый журнал разработки: Telegram, X

  • Ретроспектива первых недель, бизнес-сторона: статья на VC.ru

Комментарии (0)