Budget & limites
Ongrid impose un plafond de tokens global par jour UTC à travers chaque provider. Le défaut est illimité ; une variable d'env l'active :
ONGRID_LLM_DAILY_TOKEN_LIMIT=2000000 # 2 million tokens per UTC day<=0 désactive le plafond. Valeur unique, pas par provider — c'est le scope MVP. Quand les tenants atterrissent, ça passe aux settings par org ; ce bouton reste comme plafond global de filet de sécurité.
Comment c'est câblé
Trois pièces, dans internal/pkg/llm/ :
// 1. The interface
type BudgetChecker interface {
Check(ctx context.Context, userID uint64, estPromptTokens int) error
Record(ctx context.Context, userID uint64, usage Usage) error
}
// 2. The MVP implementation
budget := llm.NewInMemoryBudget(cfg.LLM.DailyTokenLimit)
// 3. The eino callback that bridges to the graph kernel
handler := llm.NewBudgetCallbackHandler(budget, userID)Le runtime graph-kernel installe le callback handler dans sa chaîne de callbacks eino. À chaque OnStart de ChatModel :
- Estimer les tokens de prompt :
len(text)/4(conservateur). BudgetChecker.Check(ctx, userID, estPromptTokens).- Au rejet — stocker
ErrBudgetExceededdans le contexte pour que le nœud en aval puisse court-circuiter ; le code subséquent le fait surfacer.
À OnEnd, le Usage.TotalTokens réel est enregistré contre le bucket du jour UTC courant.
ErrBudgetExceeded
// internal/pkg/llm/budget.go:37
func (b *InMemoryBudget) Check(ctx context.Context, userID uint64, estPromptTokens int) error {
if b.dailyLimit <= 0 {
return nil
}
b.mu.Lock()
defer b.mu.Unlock()
key := b.dayKey()
if b.used[key]+estPromptTokens > b.dailyLimit {
return ErrBudgetExceeded
}
return nil
}L'erreur propage vers :
- L'endpoint d'envoi de chat — renvoie HTTP 429 avec un body
{ "error": "budget_exceeded", "message": "..." }que l'UI de chat rend in-line. - Le worker investigator RCA — la ligne de rapport atterrit comme
status=failedavecstatus_reason="budget_exceeded". - Le chemin translate — retombe sur « translation unavailable (budget exceeded) » et le texte original est affiché.
Caveats InMemoryBudget
L'implémentation MVP est in-memory :
type InMemoryBudget struct {
mu sync.Mutex
dailyLimit int // tokens per UTC day; <=0 means unlimited
used map[string]int // key = "YYYY-MM-DD" (UTC)
now func() time.Time
}Conséquences :
- Pas de persistance — un redémarrage du manager reset le compteur du jour. Si vous voulez vraiment un plafond quotidien dur qui survit aux redémarrages, swappez l'implémentation. L'interface
BudgetCheckerest le seam. - Mono-processus — si vous exécutez plusieurs managers derrière un load balancer (vous ne devriez pas encore, mais bon), chacun a son propre compteur.
- Global, pas par utilisateur —
userIDcoule à travers l'interface pour qu'une future table MySQLusage_dailysoit un drop-in, mais aujourd'hui le plafond est le même chiffre pour tout le monde.
Le pivot vers le mono-tenant a différé le backend par utilisateur ; l'interface est forward-compatible pour quand le multi-utilisateur reviendra.
Estimation de tokens
BudgetCallbackHandler.OnStart estime les tokens de prompt par compte de caractères / 4. C'est intentionnellement conservateur — la tokenisation réelle varie par provider / modèle, et le budget est censé pencher du côté de refuser les appels borderline plutôt que de dépasser.
À OnEnd, le Usage.TotalTokens réel renvoyé par le provider est enregistré — donc le budget track la vérité terrain même quand l'estimation était fausse.
Si le provider ne renvoie pas de comptes de tokens (certains endpoints custom ne le font pas), le callback retombe sur une heuristique response-meta ; voir OnEndUsesResponseMetaFallback dans les tests.
Observer le budget
curl -s localhost:9100/metrics | grep llm_budget
# llm_budget_daily_limit_tokens 2000000
# llm_budget_used_tokens_today 412847
# llm_budget_rejections_total 3Les métriques sont câblées par BudgetCallbackHandler.Stats(). Le dashboard Prom self-obs les rend comme graphe de dépense quotidienne plus une alerte à 80% du plafond.
Désactiver pour une charge de travail
Il n'y a pas de bouton « disable budget for the investigator ». Si le RCA touche le plafond et que vous préférez qu'il continue à tourner plutôt que le chat, montez le plafond — c'est à ça qu'il sert. L'alternative (quotas par workload) est parquée avec le multi-tenancy.
Voir aussi
- Aperçu des modèles.
- Routing — orthogonal au budget ; le plafond s'applique par appel peu importe quel provider a été choisi.
- Variables d'environnement — boutons
ONGRID_LLM_*.