Главная / Статьи

Рабочие процессы преподавателей музыкальных инструментов с автоматическим записыванием через PostHog и пользовательскими событиями

Разместите функции автозахвата PostHog, события исходов, воспроизведения сессий и временные линии пользователей так, чтобы продукты обучения с использованием ИИ могли отслеживать завершённые задания, а не только количество кликов.

Издатель: REACTAPP.TOP4 мин чтения1031 слов

Источники: **Instrumenting User Behaviour on KaushalSaathi with PostHog**

KaushalSaathi — это образовательная платформа, ориентированная на использование ИИ и предназначенная для учителей. Она может составлять планы уроков, направлять процесс обучения в режиме «Учить», формировать расписания и предоставлять возможность чат-консультаций. Поскольку значительная часть ценности продукта достигается за счёт асинхронной генерации контента, а не простого перехода между страницами, стратегия сбора данных требовала рассматривать завершённые задачи как важные сигналы — а не только клики и изменения маршрутов.

Разработка новых функций без анализа реального использования — это распространённая ловушка. Дополнительные экраны не обязательно приводят к лучшим результатам. Прежде чем добавлять новую функцию, команде необходимы доказательства того, с чем уже работают учителя, где они сталкиваются с трудностями и какие инструменты они вообще не используют. Возможность наблюдения за поведением пользователей превращает выбор функций из процесса угадывания в основанные на реальных данных решения. Именно эту проблему и было предложено решить с помощью PostHog: как на самом деле учителя используют уже существующий продукт?

Автозахват как бесплатная базовая функция

Автозахват обрабатывает действия на уровне DOM без необходимости настройки — клики, $pageview, $pageleave и изменения состояния сессии. Безусловное использование этого инструмента и рассмотрение отсутствия API-ключа как сигнала о выключении функций позволяют избежать необходимости настройки учётных записей и использования веток типа if (enabled) в процессе локальной разработки и работы с форками:

const POSTHOG_KEY = import.meta.env.VITE_POSTHOG_KEY ?? "phc_disabled_no_key_set";
const ENABLED = POSTHOG_KEY !== "phc_disabled_no_key_set";
<PostHogProvider
apiKey={POSTHOG_KEY}
options={{
api_host: POSTHOG_HOST,
autocapture: ENABLED,
capture_pageview: ENABLED,
session_recording: { maskAllInputs: true },
loaded: (ph) => { if (!ENABLED) ph.opt_out_capturing(); },
}}

Автозахват позволяет определить, куда произошло навигационное действие. Однако он не показывает, что именно было завершено. Обработчики кликов в DOM никогда не узнают о завершении асинхронных операций — например, о генерации учебного плана, окончании периода в режиме обучения или успешном экспорте PDF. Ни одно из этих завершений не приводит к событию клика в DOM, к которому можно было бы подключиться, поэтому автозахват по своей конструкции не может их обнаружить. Именно из-за этой проблемы существует второй уровень обработки.

Персонализированные события, превращающиеся в метрики

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

export function captureEvent(name: string, props?: Record<string, unknown>) {
if (!posthog.__loaded) return;
posthog.capture(name, props);
}

Два правила обеспечивают полезность этих событий при последующих запросах.

Передавайте события при успешном выполнении, а не при попытке. Обработка сбора данных происходит по асинхронному пути успешного завершения, а не внутри обработчика кнопки, поэтому графики отражают завершённую работу:

const plan = await generateLessonPlan(payload); // resolves only on success
captureEvent("lesson_plan_generated", {
grade: plan.grade, sector: plan.sector, language: plan.language,
});

Присоединяйте свойства, которые будут использоваться в разбивке по критериям. Поля такие как grade, language, sector и periodNumber передаются вместе с событием момент его отправки. В PostHog они превращаются в фильтры и элементы разбивки без дополнительных операций — одно событие может ответить на вопросы о разбивке по уровням, языкам или секторам.

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

posthog.identify(user.id,
{ role: user.role, grade: user.grade, school: user.school });
// on logout: posthog.reset() ← must run before the redirect, or events leak to the next id

Порядок вызовов при выходе из системы имеет значение. Перенаправление до вызова reset() на общем устройстве может привести к тому, что следующая сессия будет ассоциироваться с предыдущей идентичностью. Сначала выполните сброс, затем переходите к другим действиям.

Каждое событие позволяет получить сохраненную информацию. Обычно используется подсчет событий с разбивкой по имени пользователя:

  • lesson_plan_generated во всем окне, сгруппированный по часам, позволяет получить временную серию с указанием когда, а также таблицу с детальными результатами в порядке ранжирования, показывающую кто. Этот единый вид представления выявляет активных пользователей, случайные регистрации и места наибольшей интенсивности использования. По умолчанию лимит строк в разбивке составляет 25; его можно увеличить до 50, когда важна информация о редких случаях использования.
  • chat_message_sent, ограниченный временными рамками прошлого дня и сгруппированный по часам, использует ту же самую запись с узкими временными рамками — например, пик активности днем около 15:00, связанный с одним учителем.

Одно и то же определение события, но разный диапазон дат и способ разбивки. Новый вопрос превращается в новый сохраненный вид представления, а не в новый код приложения.

Повторная отрисовка сессии для выяснения причин

Показатели отражают что и как часто, но не почему. Запись ведётся по умолчанию при настройке maskAllInputs: true, поскольку учителя вводят персональные данные учащихся и школы. Клики, навигация, глубина прокрутки и моменты заминок остаются видимыми; значения введённых данных маскируются при сохранении.

Ситуации, когда возможность перепросмотра оправдана:

  • Локализация утечек в процессе работы. Когда срабатывает параметр lesson_plan_generated, но не pdf_exported для определённой группы, показатели выявляют утечку, а перепросмотр показывает точный этап экспорта, на котором происходит сбой.
  • Беззвучные многократные сбои. Режим преподавания может работать некорректно без видимых сигналов; пользователи просто прекращают работу. Перепросмотр позволяет отделить сбой интерфейса от неоднозначных меток или медленной обработки, вызывающей тайм-аут.

Графики активности каждого пользователя

Как только идентификатор связывает записи действий с конкретным аккаунтом, экран с данными пользователя в PostHog отображается в виде временной шкалы для данного педагога: какие события произошли, какие функции были использованы, какие сессии сохранены. Практические применения включают проверку того, что после сигнала registration_completed следует первый сигнал lesson_plan_generated (для оценки успешности адаптации), просмотр временной шкалы активного пользователя перед разработкой решений с учетом его действий или воссоздание сообщенной ошибки на основе конкретной сессии вместо опоры на память.

Собирание всех компонентов воедино

Функция автоматического захвата предоставляет базовый сигнал бесплатно. Пользовательские события и метрики превращают результаты работы функций в ранжированные временные ряды с разбивкой по свойствам. Возможность воспроизведения сессий позволяет увидеть причинно-следственные связи, лежащие в основе тех или иных трендов на графиках. Линейные диаграммы, отражающие деятельность пользователей, позволяют увеличивать масштаб от общих данных до информации о конкретном преподавателе. Все эти элементы в совокупности позволяют определять, что следует разработать на основе наблюдаемого поведения, а не на основе предположений о том, как продукт «должен» использоваться.