Aller au contenu
OmniRoute source

Usage, Quota & Spend Tracking (Français)

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)

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

Les tokens sont extraits de la réponse du fournisseur en amont dans le gestionnaire de réponse :

// Extrait de open-sse/handlers/chatCore.ts
const 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).

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

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.

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) :

Fenêtre de terminal
# Déclenchement manuel
curl -X POST http://localhost:20128/api/pricing/sync

Pour 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).


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

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
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 seuil
2. **Limite stricte** (`quotaLimit`) : requête rejetée avec le code HTTP 429 lorsque la limite est dépassée
### Configuration
```ts
// Par clé d’API
await updateApiKey(keyId, {
quotaWarnAt: 5_00, // 5,00 $ — afficher un avertissement
quotaLimit: 10_00, // 10,00 $ — arrêt strict
quotaWindow: "month", // "day" | "week" | "month" | "all"
});
Requête ──▶ quotaCheck()
│
├── Dans la limite ? ──▶ autoriser
│
└── Limite dépassée ? ──▶ 429 Trop de requêtes
avec l’en-tête Retry-After

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

Fenêtre de terminal
GET /api/usage?range=7d&limit=100
GET /api/usage?apiKeyId=key-123&range=30d
GET /api/usage?provider=openai&range=1d

Ré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": "..."
}
Fenêtre de terminal
GET /api/usage/analytics?range=7d&groupBy=model

Ré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

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" }
}

Les données d’utilisation augmentent d’environ 1 à 10 Ko par requête. À grande échelle, cela peut devenir significatif.

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.

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_history plus anciens que la durée de conservation configurée dans le paramètre usageHistory
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_metrics au lieu des enregistrements bruts (uniquement pour l’analyse)

Fenêtre de terminal
# Réponse rapide — utiliser un modèle économique et rapide
curl -d '{"model":"auto/fast","messages":[...]}'
# Tâche complexe — privilégier la qualité
curl -d '{"model":"auto/smart","messages":[...]}'

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ème
const response = await openai.chat({
model: "claude-sonnet-4-5",
system: longSystemPrompt, // Sera automatiquement mis en cache
messages: [{ role: "user", content: "..." }],
});

La compression RTK + Caveman permet d’économiser 15 à 95 % sur les sessions utilisant beaucoup d’outils :

const config = {
compression: {
engine: "rtk",
intensity: "aggressive",
},
};

Définissez toujours quotaLimit afin d’éviter les coûts incontrôlés :

await updateApiKey(keyId, { quotaLimit: 10_00 }); // Plafond de 10 $/mois

Utilisez le tableau de bord ou /api/usage/analytics pour regrouper les données par clé d’API et les trier par coût :

Fenêtre de terminal
GET /api/usage/analytics?groupBy=apiKey

  1. Consultez /api/usage/analytics?groupBy=model — identifiez le modèle coûteux
  2. Consultez /api/usage/analytics?groupBy=apiKey — identifiez le principal consommateur
  3. Vérifiez que les données tarifaires sont à jour : POST /api/pricing/sync
  • 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é
  • Vérifiez le paramètre quotaLimit de la clé
  • Vérifiez que quotaWindow est correctement défini
  • Recherchez les enregistrements quotaSnapshots — ils doivent être créés à chaque requête

  • DATABASE_GUIDE.md — Schéma des tables d’utilisation
  • ENVIRONMENT.md — variables d’environnement pour la synchronisation des tarifs
  • AUTO-COMBO.md — Comment auto/fast et auto/cheap ré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

Code source d’OmniRoute (a58000c7685f)

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.

Interface principale de HagiCode en thème clair
  • 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.
Visiter HagiCode