200 отзывов → 5 JTBD за 2 часа: AI-синтез user research

Что такое Jobs-to-be-Done (JTBD)?

Jobs-to-be-Done (JTBD) — это фреймворк для продуктового исследования, который фокусируется на том, чего пользователь пытается достичь в конкретной ситуации, а не на том, что он явно просит. JTBD формулируется по шаблону: «Когда [ситуация], я хочу [мотивация], чтобы [ожидаемый результат]» — это захватывает контекст и цель, а не запрос на конкретную функцию.

TL;DR

  • -Ручной анализ 200+ отзывов занимает 2–3 недели; LLM-пайплайн сжимает это до 2 часов
  • -Оптимальный объём одного цикла — 150–300 отзывов: достаточно для статистически значимых кластеров
  • -Четыре этапа: извлечение сигналов → кластеризация → формулировка JTBD → валидация с оценкой уверенности
  • -Каждый JTBD привязан к конкретным review ID — результаты воспроизводимы и проверяемы, а не основаны на интуиции
  • -Формула JTBD захватывает ситуацию + мотивацию + ожидаемый результат, открывая несколько путей решения вместо одной фичи

95% пользовательских отзывов никогда не превращаются в product decisions. Причина банальна: ручной анализ 200+ ревью занимает 2–3 недели, и к моменту завершения приоритеты уже сменились. Команда читает отзывы, выписывает цитаты на стикеры, группирует по интуиции. Результат субъективен, не воспроизводим и не масштабируем.

Статья о том, как за 2 часа пройти путь от сырых отзывов до пяти конкретных Jobs-to-be-Done, используя LLM для каждого этапа: извлечение сигналов, кластеризация, формулировка JTBD, валидация.

Почему JTBD, а не просто “боли пользователей”

Jobs-to-be-Done фреймворк фокусируется не на том, что пользователь говорит, а на том, чего он пытается достичь. Отзыв “приложение тормозит” — это не боль. Боль в том, что человек пытался быстро найти маршрут перед выходом из отеля и не смог. Контекст, мотивация и ожидаемый результат важнее конкретной жалобы.

Формула JTBD:

Когда [ситуация], я хочу [мотивация], чтобы [ожидаемый результат]

Пример из реального анализа travel-приложения:

  • Отзыв: “Почему нельзя скачать маршрут оффлайн? В горах нет интернета!”
  • JTBD: Когда путешествую в зонах без связи, хочу иметь доступ к маршруту оффлайн, чтобы не терять ориентацию и не срывать планы.

Разница принципиальная. Отзыв указывает на фичу (оффлайн-режим). JTBD указывает на job (навигация без связи) и outcome (не срывать планы). Второе позволяет найти несколько решений: оффлайн-карты, предзагрузка, SMS-fallback, печатная версия маршрута.

Откуда брать отзывы

Источники для анализа:

  • App Store и Google Play — отзывы с оценками, дают корреляцию между sentiment и конкретными проблемами
  • Zendesk/Intercom — тикеты поддержки, самые детальные описания проблем
  • Typeform/Google Forms — ответы на опросы, структурированные данные
  • Reddit/Twitter — органические упоминания, без bias опросника
  • Записи интервью — транскрипты custdev, самый богатый контекст

Формат для загрузки в LLM — простой CSV или JSON:

[
  {
    "id": "review_001",
    "source": "google_play",
    "rating": 2,
    "text": "Планировал поездку в Бали, приложение предложило...",
    "date": "2026-02-15"
  }
]

Важно сохранять id и source для трассировки. Каждый кластер и каждый JTBD должны ссылаться на конкретные отзывы, иначе результат нельзя проверить.

Оптимальный объём для одного цикла: 150–300 отзывов. Меньше — недостаточно для статистически значимых кластеров. Больше — нужно разбивать на батчи (об этом ниже).

Шаг 1: Извлечение сигналов

Первый проход LLM извлекает из каждого отзыва структурированные сигналы. Не классификацию, не sentiment, а именно сигналы: что человек пытался сделать, что пошло не так, какой результат ожидал.

Промпт для извлечения сигналов

Ты - исследователь пользовательского опыта. Для каждого отзыва извлеки:

1. **situation** - контекст и ситуация использования (что происходило)
2. **intent** - что пользователь пытался сделать
3. **outcome_expected** - какой результат ожидал
4. **outcome_actual** - что получил в реальности
5. **emotion** - эмоциональный фон (frustration/disappointment/anger/neutral/satisfaction)
6. **signal_strength** - насколько явно выражена потребность (1-5)

Если информации недостаточно для поля - ставь null.
Отвечай строго в JSON. Не додумывай того, чего нет в тексте.

Отзывы:
{reviews_batch}

Пример output

{
  "review_id": "review_042",
  "situation": "Планирование семейной поездки с детьми на выходные",
  "intent": "Найти маршрут с учётом детских интересов",
  "outcome_expected": "Маршрут с детскими площадками и кафе с детским меню",
  "outcome_actual": "Стандартный туристический маршрут без учёта детей",
  "emotion": "disappointment",
  "signal_strength": 4
}

Батчинг

200 отзывов не влезут в один промпт. Оптимальный размер батча — 15–25 отзывов за вызов, в зависимости от длины текстов. При контексте в 128K токенов можно увеличить до 40–50, но качество извлечения падает: LLM начинает пропускать нюансы в отзывах из середины списка.

Разбивка на батчи автоматизируется скриптом на 20 строк. Общее время обработки 200 отзывов при 20 штук на батч: 10 вызовов, примерно 5–7 минут.

Подробнее о выборе модели и мониторинге LLM-вызовов — в гайде по LLM observability с Langfuse.

Шаг 2: Кластеризация сигналов

После извлечения получается 200 структурированных записей. Следующий шаг — найти повторяющиеся паттерны.

Два подхода:

Подход A: LLM-кластеризация (быстро, хорошо для < 200 записей)

Передать все извлечённые сигналы в LLM и попросить сгруппировать:

У тебя 200 извлечённых сигналов из пользовательских отзывов.
Каждый сигнал содержит: situation, intent, outcome_expected, outcome_actual.

Задача:
1. Сгруппируй сигналы по похожим intent + situation (не по словам, а по смыслу)
2. Каждый кластер назови коротко и описательно
3. Для каждого кластера укажи:
   - название кластера
   - количество сигналов в нём
   - список review_id
   - общий паттерн: типичная ситуация + типичное намерение
   - средний signal_strength

Не создавай кластеры меньше 3 сигналов - это шум.
Допускается, что один сигнал попадёт в два кластера.

Формат: JSON.

Подход B: Embeddings + HDBSCAN (точно, масштабируется)

Для датасетов больше 200 записей LLM-кластеризация теряет точность. Альтернатива: преобразовать каждый сигнал в embedding, затем кластеризовать алгоритмом HDBSCAN.

from sentence_transformers import SentenceTransformer
import hdbscan

model = SentenceTransformer('all-MiniLM-L6-v2')

# Конкатенация ключевых полей для embedding
texts = [
    f"{s['situation']} {s['intent']} {s['outcome_expected']}"
    for s in signals
]
embeddings = model.encode(texts)

clusterer = hdbscan.HDBSCAN(min_cluster_size=5, min_samples=3)
labels = clusterer.fit_predict(embeddings)

HDBSCAN не требует заранее указывать количество кластеров. Он сам определяет плотные зоны и выделяет шум (label = -1). Для 200 записей типично получить 8–15 кластеров и 10–20% шума.

Пример результата кластеризации

#КластерСигналовСредний strengthTop review_ids
1Оффлайн-доступ к маршруту344.2042, 089, 156…
2Персонализация под состав группы283.8017, 033, 091…
3Интеграция с бронированием223.5005, 067, 134…
4Навигация внутри маршрута193.9023, 078, 145…
5Бюджетный контроль поездки173.3011, 056, 112…
6Социальное планирование (совместный доступ)153.6028, 073, 167…
7Локальные рекомендации vs туристические144.0009, 048, 133…
8Адаптация маршрута в реальном времени123.7036, 082, 159…

8 кластеров. Из них нужно вывести 5 JTBD.

Шаг 3: Формулировка JTBD из кластеров

Каждый кластер содержит повторяющийся паттерн “ситуация + намерение + ожидание”. Задача LLM на этом шаге — преобразовать паттерн в формулировку JTBD.

Промпт для формулировки JTBD

Ты - product strategist. Перед тобой результаты кластеризации
пользовательских отзывов. Для каждого кластера сформулируй JTBD.

Формат JTBD:
"Когда [ситуация], я хочу [действие/возможность],
чтобы [ожидаемый результат]."

Правила:
1. Ситуация должна быть конкретной, не абстрактной
2. Действие формулируется от лица пользователя
3. Результат описывает конечную ценность, не фичу
4. Если два кластера описывают один job - объедини
5. Ранжируй по: (количество сигналов * средний signal_strength)

Кластеры:
{clusters_json}

Для каждого JTBD укажи:
- Формулировка JTBD
- Score (количество * strength)
- Источники: кластеры и review_ids
- Текущее состояние: как пользователь решает эту задачу сейчас
- Возможные решения (2-3 варианта, от простого к сложному)

Пример output: 5 JTBD

JTBD #1 (Score: 142.8) Когда нахожусь в поездке без стабильного интернета, хочу иметь полный доступ к запланированному маршруту, чтобы не зависеть от связи и следовать плану.

  • Кластеры: 1, 4
  • Текущее решение: скриншоты Google Maps, заметки в Notes
  • Варианты: оффлайн-кэш маршрута → предзагрузка карт + POI → полный оффлайн-режим с синхронизацией

JTBD #2 (Score: 106.4) Когда планирую поездку с семьёй или друзьями, хочу учесть интересы и ограничения каждого участника, чтобы маршрут подходил всем.

  • Кластеры: 2, 6
  • Текущее решение: Google Docs со списком пожеланий, голосование в чате
  • Варианты: фильтры по составу группы → профили участников с предпочтениями → AI-оптимизация маршрута под всех

JTBD #3 (Score: 77.0) Когда выбираю места для посещения, хочу получать рекомендации от локалов, а не стандартные туристические списки, чтобы увидеть настоящий город.

  • Кластеры: 7
  • Текущее решение: Reddit, блоги экспатов, вопросы в Telegram-чатах
  • Варианты: метка “local pick” на POI → партнёрство с локальными гидами → AI-курирование на основе нетуристических источников

JTBD #4 (Score: 77.0) Когда бронирую отели и билеты, хочу делать это прямо из маршрута, чтобы не переключаться между приложениями и не терять контекст.

  • Кластеры: 3
  • Текущее решение: копирование названий из приложения в Booking/Aviasales
  • Варианты: deep links на booking-платформы → встроенное сравнение цен → одна кнопка бронирования

JTBD #5 (Score: 56.1) Когда в поездке что-то идёт не по плану (закрыто, погода, задержка), хочу быстро адаптировать маршрут, чтобы не тратить время на ручное перепланирование.

  • Кластеры: 8
  • Текущее решение: поиск альтернатив в Google Maps на месте
  • Варианты: кнопка “предложить замену” → автодетект закрытых мест → real-time rerouting с учётом контекста

Шаг 4: Валидация результатов

JTBD, полученные через LLM, требуют проверки. Три метода валидации:

Обратная трассировка

Каждый JTBD должен прослеживаться до конкретных отзывов. Если нельзя найти 5+ отзывов, которые явно описывают этот job, формулировка может быть галлюцинацией модели.

Промпт для проверки:

Вот JTBD: "{jtbd_statement}"
Вот 10 отзывов, которые якобы относятся к этому JTBD:
{reviews}

Для каждого отзыва ответь:
- Релевантен ли он этому JTBD? (да/нет/частично)
- Какая именно фраза в отзыве подтверждает связь?

Итого: сколько из 10 действительно релевантны?

Порог: минимум 70% релевантных. Ниже — JTBD нужно переформулировать или он основан на слабых сигналах.

Тест на overlap

Два JTBD не должны описывать один и тот же job разными словами. Проверка:

Вот 5 JTBD. Проверь каждую пару на overlap:
- Описывают ли они одну и ту же ситуацию?
- Описывают ли одно и то же намерение?
- Можно ли их объединить без потери смысла?

Для каждой пары: overlap score от 0 (полностью разные) до 1 (дубликат).

Overlap выше 0.6 — кандидаты на объединение.

Тест на actionability

JTBD бесполезен, если из него не следует ни одного решения. Для каждого JTBD нужно ответить на вопрос: “Можно ли за 2 недели сделать минимальное решение для этого job?” Если нет — JTBD слишком абстрактный и нужна декомпозиция.

Полный workflow: 2 часа

ЭтапВремяЧто делать
Сбор и подготовка данных30 минЭкспорт отзывов, приведение к единому формату, дедупликация
Извлечение сигналов (Шаг 1)20 мин10 батчей по 20 отзывов, параллельные вызовы LLM
Кластеризация (Шаг 2)20 минLLM-кластеризация или embeddings + HDBSCAN
Формулировка JTBD (Шаг 3)15 минОдин вызов LLM на базе кластеров
Валидация (Шаг 4)25 минОбратная трассировка, overlap, actionability
Оформление результата10 минДокумент с JTBD, scores, ссылками на отзывы

Общее время: ~2 часа. Ручной аналог: 2–3 недели.

Ключевое отличие от ручного процесса — воспроизводимость. Один и тот же датасет при повторном прогоне даёт совпадение JTBD на 85–90% (тестировалось на трёх прогонах с temperature 0.3). Ручной анализ двумя аналитиками даёт совпадение 40–60%.

Выбор модели и стоимость

Для каждого шага подходит разная модель:

ШагРекомендуемая модельПочему
Извлечение сигналовClaude Sonnet, GPT-4oНужно точное следование формату + извлечение нюансов
КластеризацияClaude Opus, o3Нужно мышление, понимание семантической близости
Формулировка JTBDClaude Opus, o3Стратегическое мышление, синтез
ВалидацияClaude Sonnet, GPT-4oСравнение и верификация, не нужен глубокий анализ

Стоимость обработки 200 отзывов (примерная):

  • Извлечение: ~150K input tokens, ~80K output tokens → $1.5–3
  • Кластеризация: ~100K input, ~20K output → $1–2
  • Формулировка + валидация: ~50K input, ~15K output → $0.5–1

Итого: $3–6 за полный цикл. Для сравнения: один день работы product-аналитика обходится в $300–500.

Настройка context engineering для промптов критически важна. Чем точнее системный промпт описывает ожидаемый формат и ограничения, тем меньше итераций на исправление.

Типичные ошибки

Анализ без контекста продукта. LLM не знает, что приложение уже умеет делать. Без описания текущей функциональности модель генерирует JTBD для фич, которые уже существуют. Решение: добавить в системный промпт краткое описание продукта и его текущих возможностей.

Слишком абстрактные JTBD. “Когда планирую поездку, хочу удобный инструмент, чтобы всё было просто” — это не JTBD, а wish. Решение: в промпте указать минимальный уровень конкретности ситуации.

Игнорирование позитивных отзывов. Из пятизвёздочных отзывов тоже извлекаются JTBD — те, которые продукт уже закрывает. Это валидация текущей стратегии. Фильтровать только негативные отзывы — терять половину картины.

Кластеризация по словам, а не по смыслу. “Карта тормозит” и “маршрут не загружается оффлайн” — разные слова, один кластер (доступ к маршруту). LLM-кластеризация справляется лучше keyword-matching, но иногда группирует по поверхностному сходству. Ручная проверка топ-3 кластеров обязательна.

С чего начать

  1. Собрать 100–200 отзывов из основного канала (App Store, Zendesk, любой источник с наибольшим объёмом)
  2. Привести к формату JSON с полями id, source, text, rating, date
  3. Прогнать Шаг 1 (извлечение сигналов) на 20 отзывах вручную. Проверить качество extraction
  4. Если качество устраивает — автоматизировать батчинг и прогнать весь датасет
  5. Выполнить кластеризацию (для первого раза LLM-кластеризация проще)
  6. Сформулировать JTBD и провалидировать обратной трассировкой

Минимальный стек: один LLM API (Claude или GPT-4o), Python-скрипт для батчинга, Google Sheets для финального результата. Никаких специализированных инструментов не нужно.

Результат: документ с 5–8 ранжированными JTBD, каждый со score, source reviews и вариантами решений. Это основа для product roadmap, которую можно обновлять каждый месяц при поступлении новых отзывов.