Créer des scanners Replay Vision
Un scanner est une sonde LLM permanente sur des enregistrements de session. Une fois créé et activé, il s'exécute selon
un calendrier temporel qui balaie toutes les 5 minutes, en appliquant son prompt à chaque nouvel enregistrement correspondant et
en enregistrant le résultat comme une observation (un événement $recording_observed interrogeable). Chaque observation compte
dans un quota mensuel de l'organisation (un nombre fixe d'observations par mois calendaire).
C'est précisément ce calendrier qui rend nécessaire une vérification : un scanner avec une requête permissive et un échantillonnage complet commence immédiatement à consommer le quota et peut épuiser tout le budget du mois dans ses premiers balayages. La création elle-même ne vérifie pas le quota — cette protection ne s'active qu'au moment de l'observation, à quel point le budget peut déjà être épuisé.
Principe fondamental : dimensionner avant de déployer
Ne créez jamais un scanner activé à l'aveugle. Estimez son volume, vérifiez le quota restant, et — quand le volume projeté représente une part significative de ce qui reste — affichez les chiffres à l'utilisateur et obtenez une confirmation avant de créer. C'est le cœur du skill ; le reste est du détail de support.
Le flux
Étape 1 : Que doit faire le scanner ?
Choisissez un scanner_type et écrivez sa scanner_config. Chaque type nécessite un prompt ; le reste est spécifique au type :
| Type | Ce qu'il produit | Forme de scanner_config |
|---|---|---|
monitor |
Observation open-ended contre un prompt (ex: "signaler les clics ragés") | {"prompt": "..."} |
classifier |
Assigne des tags d'un ensemble d'étiquettes fixe | {"prompt": "...", "tags": ["tag-a", "tag-b"]} — tags nécessite ≥1 entrée ; "multi_label": true, "allow_freeform_tags": false optionnels |
scorer |
Score numérique sur une rubrique | {"prompt": "...", "scale": {"min": 1, "max": 5, "label": "frustration"}} — min < max ; label optionnel |
summarizer |
Résumé en texte libre ; embeddings de facettes optionnels pour la recherche | {"prompt": "..."}; optionnels "length": "short" \| "medium" \| "long" (défaut "medium"), "emits_embeddings": false |
scanner_type est verrouillé après création — pour le changer vous devez supprimer et recréer, donc confirmez que le type est
correct d'emblée, et que la forme scanner_config est correcte (une mauvaise forme est une erreur de création, pas une valeur par défaut silencieuse).
Si l'intention de l'utilisateur rend le type et le prompt évidents, procédez simplement — ne l'interrogez pas.
Étape 2 : Quelles sessions ?
query est une forme RecordingsQuery qui sélectionne quels enregistrements le scanner surveille. date_from et
date_to sont ignorés (le calendrier contrôle le temps), ne vous embêtez donc pas à les définir. Rétrécissez la requête aux
sessions qui comptent réellement — par événement, URL, propriété de personne, durée, etc. Une requête étroite est le levier
unique le plus important sur le coût.
sampling_rate (0..1, défaut 1.0) est un sous-échantillonnage aléatoire appliqué après que la requête trouve des correspondances. Réduisez-le pour
échanger la couverture contre le budget.
Étape 3 : Le dimensionner — la vérification (ne pas sauter)
Avant de créer, exécutez les deux vérifications et raisonnez à leur sujet ensemble :
- Estimez le volume — appelez
vision-scanners-estimate-createavec laquery+sampling_rateproposées. Elle retournematched_sessions_in_window, lawindow_daysmesurée, etestimated_observations_per_month. - Vérifiez le budget — appelez
vision-quota-retrievepourremainingetexhaustedpar rapport aumonthly_quotamensuel de l'organisation.
Décidez ensuite :
- Si
estimated_observations_per_months'adapte confortablement dansremaining, procédez. - Si c'est une large fraction de (ou dépasse)
remaining, arrêtez-vous et dites à l'utilisateur les chiffres concrets — ex: "Ce scanner est projeté de produire ~X observations/mois ; vous en avez Y de Z restant ce mois." — et confirmez avant de créer, ou suggérez de resserrer laqueryou de réduire d'abordsampling_rate. - Si l'organisation est déjà
exhausted, dites-le — un nouveau scanner activé ne produira rien jusqu'à ce que le quota soit réinitialisé, et ses observations seront silencieusement ignorées.
La confirmation ici est une étape de conversation, pas une capacité API — mettez en évidence le compromis et laissez l'utilisateur choisir. Quand le volume projeté est clairement petit par rapport au budget, vous n'avez pas besoin de demander.
Étape 4 : Créer
Appelez vision-scanners-create. Exemple minimal :
{
"name": "Rage click monitor",
"scanner_type": "monitor",
"scanner_config": { "prompt": "Flag sessions where the user repeatedly clicks the same element in frustration." },
"query": { "kind": "RecordingsQuery", "events": [{ "id": "$rageclick", "type": "events" }] },
"sampling_rate": 1.0,
"model": "gemini-3-flash-preview",
"enabled": true
}
name doit être unique dans l'équipe. Définissez enabled: false si l'utilisateur veut le créer en pause (pas de
calendrier, pas de consommation de quota) et l'activer plus tard.
Après la création
- Affichez l'URL PostHog du scanner depuis la réponse pour que l'utilisateur puisse l'examiner dans l'interface.
- Les résultats prennent quelques minutes à apparaître (rastérisation de l'enregistrement en vidéo + l'appel LLM sont lents). Inspectez-les
avec
vision-scanners-observations-listpour un scanner dans le temps, ouvision-observations-list(nécessitesession_id) pour les résultats de chaque scanner sur une seule session. Pour approfondir un enregistrement, passez le au skillinvestigating-replay.
Mettre à jour un scanner existant
vision-scanners-update est une mise à jour partielle — envoyez uniquement les champs modifiés. Relancez la vérification de l'étape 3
chaque fois que vous élargissez la portée : une query plus large ou un sampling_rate plus élevé augmentent le volume de balayage comme
le ferait un nouveau scanner large. Basculer enabled, ajuster le prompt, ou rétrécir la requête ne nécessitent pas une
ré-estimation. Éditer la config augmente scanner_version ; les observations passées conservent un instantané de l'ancienne config.
Pièges
- Une observation par (scanner, session). Relancer un scanner sur une session qu'il a déjà observée — même une échouée ou inéligible — est un no-op et ne produira pas un nouveau scan.
- Inéligible ≠ échoué. Les observations peuvent arriver
ineligible(ex:too_short,no_recording) — une issue terminale non-erreur. Vérifiezerror_reasonquand vous triez pourquoi un scanner n'a rien produit. - Provider/model sont Google/Gemini uniquement dans la version actuelle.