Архитектура 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 читает — с радостью передам координаты по любому удобному каналу.
Вопросы к сообществу
Если вы строили похожее, мне правда интересно:
Кто гоняет несколько LLM в production ансамблем? Как устроен арбитраж и как меряете согласованность?
Embeddings для категоризации товаров — оправданно для маркетплейс-домена или избыточно?
Опыт с rate-limits Ozon Performance API — как сделана retry-логика?
Wildberries Suppliers API — кто интегрировался без боли, и был ли он вообще?
Что дальше
Из ближайшего: интеграция с Wildberries и переход с синхронизации по расписанию на webhook ради обновлений ближе к реальному времени.
Буду рад разбору в комментариях, особенно по открытым вопросам выше.
