AI-evals · Category Matching Eval
← Симуляторы

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» (как это работает в проде).

Naive overall
(на golden set)
Production-weighted
(честная цифра)
Gap

Distribution: golden vs production

Доли категорий в эталонной выборке (зелёный) и в production (синий). Расхождение между ними — корень heterogeneous accuracy проблемы.

Precision per segment + sample size для CI ±3%

Точность LLM-классификатора по сегментам. Подпись — required N для CI ±3%. Если в текущем golden set по сегменту меньше — оценка недостаточно надёжна для rollout.

Что показывает симулятор

  1. При сбалансированном golden set naive overall = production-weighted. Это идеальный сценарий — редкий на практике.
  2. Типичный bias (overdrawn electronics в golden) даёт разрыв 5-10 п.п. Это незаметно при overall reporting, но это реальная цифра деградации в production.
  3. 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 нерепрезентативен, оценка ненадёжна.

Что писать в отчёт

В отчёте для команды:

Не писать «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:

Связь с курсом

Этот кейс — третий в направлении AI-evals на davydov.my. Связанные материалы: