Usage, Quota & Spend Tracking (Français)
Vue d’ensemble
Section intitulée « Vue d’ensemble »Chaque requête transitant par OmniRoute génère un enregistrement d’utilisation qui contient :
- Identité : clé API, fournisseur, modèle et combinaison concernés
- Tokens : tokens de prompt, tokens de complétion, tokens mis en cache, total
- Coût : montant en USD (calculé à partir des données tarifaires)
- Temporalité : latence, horodatages de début et de fin
- Statut : succès, erreur, limitation de débit, etc.
Ces enregistrements sont agrégés en données analytiques, conservés sous forme d’instantanés de quota et utilisés pour appliquer des limites budgétaires par clé.
Requête ──▶ chatCore ──▶ usage.record() ──▶ SQLite │ ┌───────┼───────┐ ▼ ▼ ▼ analytique quota facturation (tableau de bord) (application) (exportation)Données enregistrées
Section intitulée « Données enregistrées »Le service usage.ts enregistre un événement d’utilisation pour chaque requête :
| Champ | Type | Source |
|---|---|---|
id |
string | UUID généré lors de l’enregistrement |
apiKeyId |
string | Clé API à l’origine de la requête |
provider |
string | ID du fournisseur (openai, anthropic, etc.) |
model |
string | ID du modèle (gpt-5, claude-opus-4-6, etc.) |
comboId |
string? | ID de la combinaison si le routage passe par une combinaison |
promptTokens |
number | Issu de la réponse du service en amont |
completionTokens |
number | Issu de la réponse du service en amont |
cachedTokens |
number | Tokens trouvés dans le cache (mise en cache des prompts Anthropic, etc.) |
totalTokens |
number | prompt + complétion |
costUsd |
number | Calculé à partir des données tarifaires |
latencyMs |
number | Durée totale de la requête |
status |
enum | success, error, rate_limited, timeout, cancelled |
errorClass |
string? | Classe d’erreur si le statut est différent de success |
timestamp |
string | ISO 8601 UTC |
metadata |
object | Données personnalisées injectées par un plugin |
Origine des tokens
Section intitulée « Origine des tokens »Les tokens sont extraits de la réponse du fournisseur en amont dans le gestionnaire de réponse :
// Extrait de open-sse/handlers/chatCore.tsconst response = await providerExecutor.execute(provider, request);const usage = response.usage || { prompt_tokens: 0, completion_tokens: 0, cached_tokens: 0,};Pour les fournisseurs qui ne renvoient pas de données d’utilisation (certains fournisseurs utilisant des cookies web), OmniRoute estime le nombre de tokens à l’aide d’une heuristique de ~4 caractères par token (voir open-sse/services/autoCombo/pipelineRouter.ts).
Tokens mis en cache
Section intitulée « Tokens mis en cache »OmniRoute suit cached_tokens séparément de prompt_tokens, car :
- La mise en cache des prompts Anthropic facture les tokens mis en cache à un tarif réduit (10 % du tarif normal)
- Certains fournisseurs renvoient
cache_read_input_tokens, qui doivent être facturés différemment - Les données analytiques peuvent afficher le taux d’accès au cache =
cached_tokens / prompt_tokens
Calcul du coût
Section intitulée « Calcul du coût »Les coûts sont calculés à partir des données tarifaires synchronisées depuis LiteLLM (src/lib/pricingSync.ts) :
| Modèle | Entrée $/1M | Sortie $/1M | Cache $/1M |
|---|---|---|---|
| gpt-5 | $2.50 | $10.00 | — |
| claude-opus-4-6 | $15.00 | $75.00 | $1.50 |
| claude-sonnet-4-5 | $3.00 | $15.00 | $0.30 |
| gemini-2.5-pro | $1.25 | $10.00 | — |
La formule de calcul du coût (src/lib/usage/costCalculator.ts) :
cost = (prompt_tokens - cached_tokens) * input_price + cached_tokens * cached_price + completion_tokens * output_price;Pourquoi soustraire les jetons mis en cache de ceux du prompt ? La partie mise en cache est facturée séparément ; appliquer le tarif d’entrée à l’ensemble du prompt entraînerait une surfacturation.
Synchronisation des tarifs
Section intitulée « Synchronisation des tarifs »Les données tarifaires sont automatiquement synchronisées depuis LiteLLM via le point de terminaison /api/pricing/sync (déclenché par la tâche cron intégrée, et non par une variable d’environnement destinée aux utilisateurs) :
# Déclenchement manuelcurl -X POST http://localhost:20128/api/pricing/syncPour les modèles dépourvus de données tarifaires, OmniRoute se rabat sur une estimation du coût à l’aide de tarifs moyens internes (provenant des données tarifaires de LiteLLM).
Agrégation par plage de dates
Section intitulée « Agrégation par plage de dates »Le module usageAnalytics.ts calcule les widgets du tableau de bord à partir des données brutes d’utilisation. Il prend en charge 7 plages temporelles :
| Plage | Période | Cas d’utilisation |
|---|---|---|
1d |
Les dernières 24 heures | Détection horaire des pics de coût |
7d |
Les 7 derniers jours | Revue hebdomadaire |
30d |
Les 30 derniers jours | Facturation mensuelle |
90d |
Les 90 derniers jours | Analyse trimestrielle |
ytd |
Depuis le 1er janvier de l’année en cours | Suivi du budget annuel |
all |
Depuis toujours | Statistiques cumulées |
custom |
Dates de début et de fin définies par l’utilisateur | Audits, requêtes ponctuelles |
Widgets calculés pour le tableau de bord
Section intitulée « Widgets calculés pour le tableau de bord »Pour toute plage de dates, la couche analytique calcule :
| Widget | Description |
|---|---|
| Cartes récapitulatives | Nombre total de requêtes, coût total, jetons totaux, taux de réussite |
| Graphique de tendance quotidienne | Coût + jetons par jour, empilés par modèle |
| Carte thermique d’activité | Grille heure de la journée × jour de la semaine, couleur = nombre de requêtes |
| Répartition par modèle | Diagramme circulaire du coût par modèle |
| Répartition par fournisseur | Diagramme à barres des requêtes par fournisseur |
| Principales clés API | Tableau des 10 principales clés par coût |
| Analyse des erreurs | Taux d’erreur au fil du temps, principales classes d’erreurs |
Accès programmatique
Section intitulée « Accès programmatique »import { computeAnalytics } from "@/lib/usageAnalytics";
const analytics = await computeAnalytics( history, // enregistrements de l'historique d'utilisation "7d", // plage temporelle : "1d" | "7d" | "30d" | "90d" | "ytd" | "all" | "custom" connectionMap, // table de correspondance des connexions fournisseur (connectionId → nom du compte) { startDate: "2025-01-01", // facultatif : pour la plage "custom" endDate: "2025-06-01", // facultatif : pour la plage "custom" });
console.log(analytics.summary.totalCost); // 12.34 (centimes)console.log(analytics.byModel[0]); // { model, cost, requests, promptTokens, completionTokens }
---
## Application des quotas
Le quota par clé d’API est appliqué à deux niveaux :
1. **Limite souple** (`quotaWarnAt`) : avertissement dans le tableau de bord lorsque l’utilisation dépasse le seuil2. **Limite stricte** (`quotaLimit`) : requête rejetée avec le code HTTP 429 lorsque la limite est dépassée
### Configuration
```ts// Par clé d’APIawait updateApiKey(keyId, { quotaWarnAt: 5_00, // 5,00 $ — afficher un avertissement quotaLimit: 10_00, // 10,00 $ — arrêt strict quotaWindow: "month", // "day" | "week" | "month" | "all"});Flux d’application
Section intitulée « Flux d’application »Requête ──▶ quotaCheck() │ ├── Dans la limite ? ──▶ autoriser │ └── Limite dépassée ? ──▶ 429 Trop de requêtes avec l’en-tête Retry-AfterInstantanés des quotas
Section intitulée « Instantanés des quotas »La table quotaSnapshots stocke l’état historique des quotas à des fins d’analyse des tendances :
| Champ | Description |
| ———– | –––––––––––––––––––– | —— | —–– |
| apiKeyId | La clé faisant l’objet du suivi |
| window | “day” | “week” | “month” |
| used | Coût utilisé dans cette fenêtre (cents) |
| limit | La limite (cents) |
| resetAt | Date de réinitialisation de la fenêtre |
| createdAt | Date de création de l’instantané |
Des instantanés sont créés à chaque requête dont le coût est supérieur à 0 et servent à :
- Afficher la barre de progression du quota dans le tableau de bord
- Afficher les graphiques de tendance des quotas sur 30 jours
- Déclencher des alertes lorsque l’utilisation approche de la limite
API REST
Section intitulée « API REST »Répertorier les enregistrements d’utilisation
Section intitulée « Répertorier les enregistrements d’utilisation »GET /api/usage?range=7d&limit=100GET /api/usage?apiKeyId=key-123&range=30dGET /api/usage?provider=openai&range=1dRéponse :
{ "records": [ { "id": "uuid", "apiKeyId": "key-123", "provider": "openai", "model": "gpt-5", "promptTokens": 1234, "completionTokens": 567, "totalTokens": 1801, "costUsd": 0.005, "latencyMs": 1234, "status": "success", "timestamp": "2026-06-08T12:00:00Z" } ], "total": 1234, "nextCursor": "..."}Obtenir le récapitulatif analytique
Section intitulée « Obtenir le récapitulatif analytique »GET /api/usage/analytics?range=7d&groupBy=modelRéponse :
{ "summary": { "totalCost": 12.34, "totalRequests": 5678, "totalTokens": 12345678, "successRate": 0.987, "avgLatencyMs": 1234 }, "models": [ { "model": "gpt-5", "cost": 8.5, "requests": 1234, "tokens": 4567890 }, { "model": "claude-opus-4-6", "cost": 3.84, "requests": 234, "tokens": 234567 } ], "daily": [ { "date": "2026-06-01", "cost": 1.5, "requests": 800 }, { "date": "2026-06-02", "cost": 2.0, "requests": 1000 } ]}Interroger les données analytiques d’utilisation
Section intitulée « Interroger les données analytiques d’utilisation »Les données d’utilisation sont accessibles via le tableau de bord ou les outils MCP, et non via des points de terminaison d’exportation REST directs. Données analytiques disponibles :
/api/usage/analytics— métriques d’utilisation agrégées (regroupées par modèle, fournisseur ou clé)/api/usage/quota— état actuel du quota pour chaque clé d’API/api/usage/history— journaux de l’historique des requêtes
Outils MCP
Section intitulée « Outils MCP »Deux outils MCP exposent les données d’utilisation aux agents (voir open-sse/mcp-server/tools/) :
| Outil | Description |
|---|---|
omniroute_cost_report |
Génère un rapport des coûts par clé pour une période donnée |
omniroute_check_quota |
Renvoie l’état actuel du quota pour une clé d’API |
Exemple d’appel par un agent :
{ "tool": "omniroute_cost_report", "args": { "period": "week" }}Conservation et nettoyage
Section intitulée « Conservation et nettoyage »Les données d’utilisation augmentent d’environ 1 à 10 Ko par requête. À grande échelle, cela peut devenir significatif.
Paramètres de conservation
Section intitulée « Paramètres de conservation »La durée de conservation de l’historique d’utilisation est configurée via les paramètres de base de données dans l’interface utilisateur ou via /api/settings/database.
Par défaut, l’historique d’utilisation est conservé pendant 90 jours.
Nettoyage
Section intitulée « Nettoyage »Les anciens enregistrements sont nettoyés par src/lib/db/cleanup.ts :
- Déclenché par le processus cron en arrière-plan
- Supprime les enregistrements de
usage_historyplus anciens que la durée de conservation configurée dans le paramètreusageHistory
Estimation du stockage
Section intitulée « Estimation du stockage »| Taux de requêtes | Stockage sur 30 jours | Stockage sur 90 jours |
|---|---|---|
| 100 requêtes/jour | ~3 Mo | ~9 Mo |
| 1 000 requêtes/jour | ~30 Mo | ~90 Mo |
| 10 000 requêtes/jour | ~300 Mo | ~900 Mo |
| 100 000 requêtes/jour | ~3 Go | ~9 Go |
Pour un trafic très élevé, envisagez les options suivantes :
- Réduire la durée de conservation via les paramètres de base de données
- Utiliser
aggregated_metricsau lieu des enregistrements bruts (uniquement pour l’analyse)
Conseils d’optimisation des coûts
Section intitulée « Conseils d’optimisation des coûts »1. Utiliser le modèle approprié
Section intitulée « 1. Utiliser le modèle approprié »# Réponse rapide — utiliser un modèle économique et rapidecurl -d '{"model":"auto/fast","messages":[...]}'
# Tâche complexe — privilégier la qualitécurl -d '{"model":"auto/smart","messages":[...]}'2. Activer la mise en cache
Section intitulée « 2. Activer la mise en cache »La mise en cache des prompts d’Anthropic permet d’économiser 90 % sur les contextes répétés :
// La mise en cache est automatique — il suffit d’inclure la même longue invite systèmeconst response = await openai.chat({ model: "claude-sonnet-4-5", system: longSystemPrompt, // Sera automatiquement mis en cache messages: [{ role: "user", content: "..." }],});3. Utiliser la compression
Section intitulée « 3. Utiliser la compression »La compression RTK + Caveman permet d’économiser 15 à 95 % sur les sessions utilisant beaucoup d’outils :
const config = { compression: { engine: "rtk", intensity: "aggressive", },};4. Définir des quotas par clé
Section intitulée « 4. Définir des quotas par clé »Définissez toujours quotaLimit afin d’éviter les coûts incontrôlés :
await updateApiKey(keyId, { quotaLimit: 10_00 }); // Plafond de 10 $/mois5. Auditer les principaux consommateurs
Section intitulée « 5. Auditer les principaux consommateurs »Utilisez le tableau de bord ou /api/usage/analytics pour regrouper les données par clé d’API et les trier par coût :
GET /api/usage/analytics?groupBy=apiKeyDépannage
Section intitulée « Dépannage »« Le coût est plus élevé que prévu »
Section intitulée « « Le coût est plus élevé que prévu » »- Consultez
/api/usage/analytics?groupBy=model— identifiez le modèle coûteux - Consultez
/api/usage/analytics?groupBy=apiKey— identifiez le principal consommateur - Vérifiez que les données tarifaires sont à jour :
POST /api/pricing/sync
« Des enregistrements sont manquants »
Section intitulée « « Des enregistrements sont manquants » »- Vérifiez les paramètres de conservation de la base de données sous Tableau de bord → Base de données → Nettoyage — les anciens enregistrements sont supprimés par la tâche de nettoyage périodique (
src/lib/db/cleanup.ts) - Recherchez les erreurs dans
src/lib/db/usage*.ts— les échecs d’écriture dans la base de données sont journalisés, mais ne sont pas signalés - Vérifiez que la requête a effectivement atteint
chatCore— contrôlez le routage combiné
« Le quota n’est pas appliqué »
Section intitulée « « Le quota n’est pas appliqué » »- Vérifiez le paramètre
quotaLimitde la clé - Vérifiez que
quotaWindowest correctement défini - Recherchez les enregistrements
quotaSnapshots— ils doivent être créés à chaque requête
Voir aussi
Section intitulée « Voir aussi »- DATABASE_GUIDE.md — Schéma des tables d’utilisation
- ENVIRONMENT.md — variables d’environnement pour la synchronisation des tarifs
- AUTO-COMBO.md — Comment
auto/fastetauto/cheapréduisent les coûts - API_REFERENCE.md — Référence complète de
/api/usage/* - Source :
open-sse/services/usage.ts,src/lib/usageAnalytics.ts,src/lib/db/usage*.ts
HagiCode
HagiCode est un espace de développement agentique qui associe workflows structurés, exécution multi-agent et vues Hero Dungeon.
Transformez vos idées en logiciels utiles grâce à un workflow agentique plus intelligent, rapide et agréable.

- SmartDes workflows structurés transforment une intention en parcours exécutable, de l’idée à la livraison.
- EfficientLes workflows multi-agents font avancer recherche, réalisation et revue en parallèle.
- FunHero Dungeon rend les longues sessions de code plus visuelles et collaboratives.