Price index на маркетплейсе: скрытая ошибка в оценке LLM-классификатора категорий
Маркетплейс хочет считать price index — сравнивать свои цены с ценами конкурентов на тех же товарах. Для этого нужен matching: каждый товар на нашей площадке нужно сматчить с тем же товаром у конкурента. Один из главных сигналов для матчинга — категория. Если у нас товар лежит в «Беговые кроссовки», у конкурента — в «Спортивная обувь → Беговые», это тот же функциональный класс товаров, нужно матчить.
Категории у разных маркетплейсов разные: разная глубина дерева, разное именование, разная гранулярность. На большом маркетплейсе их десятки тысяч, в комбинации с конкурентами — миллионы пар. Ручное сопоставление было бы 10 человеко-лет.
LLM умеет это решать: даём промпт «вот категория с маркетплейса A, вот 20 кандидатов с маркетплейса B, какие ближе по смыслу», получаем ranked list. На bench-test получили 85% precision. Можно выкатывать в production.
Не так быстро. Эта страница про скрытую ошибку в такой оценке. Истинное «85%» при разном distribution категорий между golden set и production может означать 75% в production. Решение про rollout не должно опираться на одну overall-цифру — нужна heterogeneous-оценка.
Гетерогенность как угроза category-matching evaluation
Главное содержание этого кейса. Категории не одинаковы по сложности матчинга, и это меняет всё в evaluation.
Сегменты по сложности
Электроника. Бренды + модельные ряды + чёткие спецификации. «iPhone 15 Pro 256GB Titanium» матчится с аналогичным однозначно. LLM-точность здесь высокая — обычно 92-97%. Объём — большой, но не доминирующий.
Fashion. Цвета, размерные сетки, материалы, сезоны. «Платье черное Zara M летнее» — это не «платье черное Zara M». LLM путает похожие позиции, придумывает атрибуты, по-разному обрабатывает варианты бренда. Точность — 70-80%. Объём — большой.
Food & FMCG. Составы, веса, количество в упаковке, варианты «оригинал/диет/ без сахара». «Coca-Cola 1L» и «Coca-Cola Zero 1L» — два разных товара, не вариант. LLM часто не различает. Точность — 55-70%. Объём средний.
Long tail (нишевые категории). Хобби, профессиональные товары, узкоспециализированные позиции. Обучающих данных мало, LLM работает на знаниях из training data. Точность — 40-60% и сильно зависит от того, обсуждалась ли категория публично. Объём по штукам мал, но категорий много.
Почему это рушит overall-оценку
Команда собирает golden set — 1000 пар «правильных» матчей, размеченных вручную. Считает на нём accuracy своего LLM-классификатора. Получает 85%. Сообщает: «готовы выкатывать».
Проблема: pattern, по которому собирали golden set, не соответствует production. Обычно golden set смещён в сторону электроники (легче размечать, легче выбирать эталоны) — например, 50% электроники в golden vs 30% в production. Fashion и food недопредставлены.
Численно: если в golden 50% электроники (precision 95%), 30% fashion (precision 75%), 20% остального (precision 55%) — overall = 84%. Если в production 30% электроники, 40% fashion, 30% остального — overall = 74%. Команда ждёт 85%, получает 74%. Это 10 п.п. разрыва между заявленной и реальной точностью, и весь price index в production деградирует.
Это не редкая проблема. Это типичный провал в LLM-classification evaluation на крупных платформах.
Что делать — stratified evaluation
Решение: не одна overall-цифра, а разбиение по сегментам. На каждом сегменте — своя precision, recall, sample size для оценки. Финальный отчёт:
«Precision электроники: 95% (CI 93-96%) на 400 эталонах. Precision fashion: 76% (CI 72-80%) на 300 эталонах. Precision food: 62% (CI 56-68%) на 200 эталонах. Precision long tail: 51% (CI 44-58%) на 100 эталонах.»
Из этого получается weighted overall под production distribution: переумножаем precision каждого сегмента на его долю в production. Это и есть «честная» цифра.
Симулятор ниже считает эту разницу. Параметры — distribution categories в golden vs production, accuracy per segment. Выход — naive overall vs production-weighted overall, и sample size per segment для целевой точности оценки.
Симулятор: stratified evaluation
Покрути параметры — доли категорий в golden set и в production, точность LLM на каждом сегменте. Симулятор покажет разницу между «naive overall» (overall на golden set) и «production-weighted» (как это работает в проде).
(на golden set)
(честная цифра)
Distribution: golden vs production
Доли категорий в эталонной выборке (зелёный) и в production (синий). Расхождение между ними — корень heterogeneous accuracy проблемы.
Precision per segment + sample size для CI ±3%
Точность LLM-классификатора по сегментам. Подпись — required N для CI ±3%. Если в текущем golden set по сегменту меньше — оценка недостаточно надёжна для rollout.
Что показывает симулятор
- При сбалансированном golden set naive overall = production-weighted. Это идеальный сценарий — редкий на практике.
- Типичный bias (overdrawn electronics в golden) даёт разрыв 5-10 п.п. Это незаметно при overall reporting, но это реальная цифра деградации в production.
- Per-segment sample sizes показывают где golden set «слабый». Если для fashion нужно 800 пар для CI ±3%, а в golden 200 — оценка fashion недостаточно надёжна для rollout decisions.
Главный takeaway: «85% accuracy» как cumulative число — самая частая ошибка в LLM-classification evaluation. Stratified evaluation per segment + production-weighted overall — это база, не optional.
Полный matching eval pipeline
Практическое — как настроить evaluation pipeline для category matching без сегментной слепоты.
Что должно быть в golden set
Не просто «1000 пар» — golden set должен быть stratified.
category_segment target_n
----------------- -------
electronics 300
fashion 300
food_fmcg 200
home_garden 150
long_tail 250
Total: 1200. Стратификация под production distribution — не равными долями, и не пропорционально объёму golden set который проще собрать (типичная ошибка).
Если production distribution неизвестен — собрать его сначала. Категории-фильтры на page views в течение недели, агрегация. Это первый шаг evaluation проекта, часто пропускается.
Что считать на уровне эксперимента
SQL-агрегация по логам матчинга:
SELECT
category_segment,
COUNT(*) AS n_pairs,
AVG(is_correct::INT) AS precision,
1.96 * SQRT(AVG(is_correct::INT) * (1 - AVG(is_correct::INT)) / COUNT(*)) AS ci_half_width,
AVG(llm_confidence) AS avg_confidence
FROM matching_eval
WHERE eval_id = 'price_index_v2'
GROUP BY category_segment
ORDER BY n_pairs DESC;
Получаем precision per segment + sample size + CI.
Weighted overall accuracy
Python-псевдокод:
def production_weighted_accuracy(per_segment_results,
production_distribution):
total = 0
for segment, weight in production_distribution.items():
total += per_segment_results[segment].precision * weight
return total
# Example:
# per_segment = {'electronics': 0.95, 'fashion': 0.76, ...}
# production_distribution = {'electronics': 0.30, 'fashion': 0.40, ...}
# production_weighted_accuracy(...) = 0.74
Сравнить с naive overall (просто average по pair_id):
SELECT AVG(is_correct::INT) FROM matching_eval
WHERE eval_id = 'price_index_v2';
Разница между ними = systematic bias of golden set distribution. Если разрыв > 5 п.п. — golden set нерепрезентативен, оценка ненадёжна.
Что писать в отчёт
В отчёте для команды:
- Per-segment precision + CI (не overall)
- Production-weighted overall (это «честная» цифра)
- Distribution gap между golden и production (если есть)
- Sample sizes per segment с обоснованием
Не писать «LLM-классификатор: precision 85%». Правильная форма: «На golden set precision 84% (overall). Production-weighted overall: 74%. Per-segment: electronics 95%, fashion 76%, food 62%, long tail 51%. Перед rollout требуется усилить evaluation на fashion и food, и дособрать выборку long tail для надёжной оценки.»
Что делать дальше
Минимальный checklist для аналитика, который запускает LLM-classification для category matching:
- Никогда не использовать overall accuracy без segment breakdown. Это всегда даёт оптимистическую оценку потому что golden set смещён в сторону «простых» сегментов где проще собирать эталоны.
- Собрать production distribution до golden set, не после. Знать что распределение в проде 30/40/30 (electronics/fashion/food) — критично для правильного стратифицирования.
- Sample size per segment, не на overall. Sample size для целевой точности оценки (CI ±3%) на fashion при precision 75% — около 800 пар. Если у вас 200 — CI ±6%, оценка fashion почти бесполезна.
- Long tail оценить отдельно. Это самая опасная категория — LLM может работать на 90% или 30% в зависимости от специфики данных, и golden set обычно содержит долю long tail непропорционально малую. Если в production long tail = 15%, в golden — 3%, при rollout вы откроете что эта часть стоила вам price index деградации.
- Re-eval после rollout. Production distribution меняется (новые категории, переименование, перестройки), и «хорошая» оценка через месяц может быть устаревшей. Plan a re-eval каждые 3-6 месяцев на свежем golden subsample.
- Confidence threshold для high-stakes решений. Если precision сегмента 60% — нельзя автоматизировать 100% matching там. Поставить confidence threshold: выше X — auto, ниже X — human-in-loop. Это балансирует throughput и quality.
Связь с курсом
Этот кейс — третий в направлении AI-evals на davydov.my. Связанные материалы:
- LLM A/B Test Simulator — sample size для сравнения LLM-моделей с поправкой на stochasticity
- LLM-as-Judge Position Bias — mirror correction для pairwise judgment
- Модуль 02: Типы метрик — классификация как основа evaluation
- Модуль 06: Кластерные эксперименты — heterogeneity и stratification