exploring-llm-costs

Par posthog · skills

Analysez les dépenses LLM dans PostHog — coût total dans le temps, coût par modèle, fournisseur, utilisateur, trace ou dimension personnalisée, économie des tokens et des cache-hits, et régressions de coûts. À utiliser quand l'utilisateur demande « combien dépensons-nous en LLM ? », « quel modèle / utilisateur / feature est le plus coûteux ? », « pourquoi le coût a-t-il soudainement augmenté ? », souhaite construire un dashboard de coûts ou une alerte, ou colle une URL de trace pour en connaître le coût.

npx skills add https://github.com/posthog/skills --skill exploring-llm-costs

Explorer les coûts des LLM

PostHog ajoute des métadonnées de coût par appel à chaque événement $ai_generation et $ai_embedding au moment de l'ingestion. Toute question sur les coûts se réduit à une agrégation sur ces deux types d'événements — la variation intéressante porte seulement sur la façon dont vous groupez, filtrez et comparez.

Cette skill couvre les investigations de coûts courantes : dépense totale, ventilations (modèle, fournisseur, utilisateur, trace, propriété personnalisée), analyse des tokens et des cache-hit, debugging de régression, et matérialisation des résultats sous forme d'insights, de tableaux de bord ou d'alertes.

Outils

Outil Objectif
posthog:execute-sql HogQL ad-hoc pour toute agrégation de coût — l'outil principal de cette skill
posthog:query-llm-traces-list Lister les traces avec les métriques de coût, tokens et erreurs récapitulés
posthog:query-llm-trace Ventilation des coûts d'une seule trace sur tous ses événements
posthog:read-data-schema Découvrir quelles propriétés personnalisées existent pour les ventilations
posthog:insight-create Matérialiser un graphique de coût en tant qu'insight sauvegardé
posthog:dashboard-create Regrouper des insights de coût dans un tableau de bord
posthog:alert-create Alerter quand le coût dépasse un seuil

Règles fondamentales

Trois règles couvrent la plupart des erreurs :

  • Additionnez $ai_total_cost_usd pour les rollups, jamais les composants. Les composants omettent les frais de requête et de recherche web. Les cellules de coût de l'interface additionnent $ai_total_cost_usd sur event IN ('$ai_generation', '$ai_embedding'); faites de même. Schéma complet et justification dans propriétés de coût.
  • Incluez toujours $ai_generation et $ai_embedding dans les requêtes de coût, sauf si le projet ne démontre clairement qu'il n'utilise pas les embeddings — les omettre sous-compte silencieusement. $ai_trace et $ai_span ne portent aucun coût de rollup; certains wrappers SDK dupliquent $ai_total_cost_usd sur $ai_trace, donc ne l'incluez pas dans les rollups ou vous doublerez le comptage.
  • Définissez toujours une plage horaire. Les requêtes de coût sans plage horaire scannent la table complète des événements.

$ai_total_cost_usd est défini à l'ingestion via l'un des trois chemins (passthrough, tarification personnalisée, lookup automatique). Quand un coût semble incorrect, lisez d'abord $ai_cost_model_source — consultez sources de coût pour les règles de priorité et une requête diagnostique.

Les mathématiques du cache-hit dépendent du fait que le fournisseur rapporte les tokens du cache inclusivement ou exclusivement à $ai_input_tokens. Branchchez toujours sur le drapeau par événement $ai_cache_reporting_exclusive, jamais sur le nom du fournisseur — consultez comptabilité du cache pour la formule exclusive vs inclusive.

distinct_id est la dimension utilisateur canonique. Les clients attachent souvent des propriétés personnalisées (feature, tenant_id, workflow_name) — découvrez-les avec posthog:read-data-schema avant de grouper. Ne devinez pas les noms.

Workflow : dépense totale dans une fenêtre

posthog:execute-sql
SELECT round(sum(toFloat(properties.$ai_total_cost_usd)), 4) AS total_cost_usd
FROM events
WHERE event IN ('$ai_generation', '$ai_embedding')
    AND timestamp >= now() - INTERVAL 30 DAY

Workflow : ventilations de coûts

Chaque question sur les coûts est une variation du même modèle — grouper par une dimension, agréger $ai_total_cost_usd. Consultez modèles de ventilation pour des recettes prêtes à l'exécution :

  • Coût au fil du temps (quotidien)
  • Coût par modèle
  • Coût par utilisateur (gros dépensiers)
  • Coût par trace (traces les plus onéreuses)
  • Coût par dimension personnalisée
  • Distribution du coût par appel
  • Économies entrée vs sortie vs cache

Workflow : inspecter le coût d'une seule trace

Quand l'utilisateur colle une URL de trace et pose une question sur son coût, récupérez la trace et affichez la ventilation par événement :

posthog:query-llm-trace
{ "traceId": "<trace_id>", "dateRange": {"date_from": "-30d"} }

Additionnez $ai_total_cost_usd sur les événements retournés, groupés par nom de span ou modèle, pour montrer quelles étapes ont généré le coût. La réponse de trace inclut déjà totalCost par commodité.

Workflow : déboguer une régression de coûts

« Notre facture LLM a explosé — pourquoi ? » est presque toujours l'un de : plus d'appels, prompts plus grands, un nouveau modèle, ou un changement du taux de cache-hit. Parcourez-les dans l'ordre — consultez debugging de régression pour le playbook en 5 étapes.

Workflow : matérialiser en insight, tableau de bord ou alerte

Après que les requêtes ad-hoc répondent à la question, persistez-les en tant qu'insights, regroupez-les dans un tableau de bord, ou configurez les alertes. Consultez matérialisation pour du JSON prêt à l'exécution pour posthog:insight-create, posthog:dashboard-create, et posthog:alert-create.

Construction de liens d'interface

  • Tableau de bord : https://app.posthog.com/llm-analytics/dashboard
  • Liste des traces (triée par coût) : https://app.posthog.com/llm-analytics/traces
  • Liste des générations : https://app.posthog.com/llm-analytics/generations
  • Liste des utilisateurs (coût par utilisateur) : https://app.posthog.com/llm-analytics/users
  • Trace unique : https://app.posthog.com/llm-analytics/traces/<trace_id>?timestamp=<url_encoded_iso>

Affichez toujours un lien d'interface pour que l'utilisateur puisse vérifier visuellement.

Maintenir cette skill à jour

Le comportement de rapport des fournisseurs (quels tokens sont inclusifs vs exclusifs, où les coûts apparaissent) change au fil du temps et peut différer entre les versions du SDK pour le même fournisseur. Pour éviter la pourriture :

  • Branchchez sur les drapeaux au niveau de l'événement ($ai_cache_reporting_exclusive, $ai_cost_model_source) plutôt que sur des noms de fournisseur ou modèle codés en dur. Ces drapeaux sont la réponse résolue de l'ingestion pour l'événement spécifique et sont la source de vérité appropriée.
  • $ai_total_cost_usd est toujours autoritaire pour les rollups — privilégiez-le par rapport à l'addition des composants, qui peuvent diverger à mesure que de nouvelles catégories de coût sont ajoutées.
  • Pour tout ce qui n'est pas couvert ici (nouvelles catégories de coût, modifications de la lookup de tarification, ajouts de fournisseurs), exécutez posthog:docs-search pour « calculating costs » ou « llm analytics » d'abord plutôt que de faire confiance à une règle codée en dur dans ce fichier.
  • Si vous trouvez cette skill contredisant l'interface, faites confiance à l'interface et signalez la skill pour une mise à jour.

Conseils

  • Définissez toujours une plage horaire — les requêtes de coût sans plage horaire scannent la table complète des événements
  • Incluez toujours $ai_embedding aux côtés de $ai_generation lors de la sommation des coûts; les embeddings sont bon marché par appel mais s'accumulent à l'échelle
  • Les coûts sont écrits à l'ingestion (consultez Calculating LLM costs) — si $ai_total_cost_usd manque ou est zéro, lisez d'abord $ai_cost_model_source : passthrough signifie que le SDK a fourni les coûts; custom signifie tarification personnalisée des tokens; openrouter / manual signifient lookup automatique; manquant signifie que le modèle n'a pas été trouvé (modèle personnalisé inhabituel, fine-tune). Grep : countIf(properties.$ai_total_cost_usd IS NULL) par (model, source)
  • La tarification personnalisée utilise des prix par token, pas par million — si un modèle à prix personnalisé semble ~1M× trop cher ou trop bon marché, c'est presque toujours le bug
  • Excluez les appels en erreur des totaux de coûts uniquement quand explicitement demandé — les fournisseurs facturent toujours de nombreux modes d'erreur, et les inclure donne la facture véridique
  • Pour les totaux par utilisateur, excluez les lignes où distinct_id = properties.$ai_trace_id — certains SDK définissent par défaut distinct_id à l'ID de trace quand aucun utilisateur n'est défini
  • Le coût est additif dans les événements $ai_generation + $ai_embedding dans une trace; la sommation sur $ai_span donne zéro. $ai_trace peut porter $ai_total_cost_usd de certains wrappers SDK — ne l'incluez pas dans les rollups ou vous doublerez le comptage. Les événements $ai_evaluation portent aussi un coût mais ne font pas partie des rollups de l'interface standard; incluez-les uniquement quand l'utilisateur veut explicitement la dépense d'évaluation dans le total
  • Le taux de cache-hit dépend de $ai_cache_reporting_exclusive — branchchez sur le drapeau au niveau de l'événement plutôt que sur le nom du fournisseur ou du modèle. Le comportement des fournisseurs et les versions du SDK changent; le drapeau est la réponse résolue de l'ingestion pour cet événement spécifique
  • Quand vous répondez à « pourquoi X est-il cher? », affichez le coût et la répartition des tokens — l'utilisateur veut presque toujours savoir s'il faut réduire les prompts, réduire les sorties, ou changer de modèle
  • Avant de construire un tableau de bord personnalisé, vérifiez si les tuiles /llm-analytics/dashboard standard répondent déjà à la question — les recréer est du churn
  • Pour les grands tenants, matérialisez les requêtes de coût courantes en tant qu'insights et réutilisez via insight-query; SQL ad-hoc est bon pour les one-offs mais le réexécuter à chaque chargement de tableau de bord est coûteux

Références

Skills similaires