Aperçu
Les agents IA qui utilisent des API de recherche peuvent accumuler rapidement des coûts si l'utilisation n'est pas surveillée. Ce workflow s'exécute le premier de chaque mois, interroge vos données d'utilisation Scavio, calcule les dépenses du mois précédent par agent ou projet, compare au budget et prévoit les coûts du mois suivant en fonction de la tendance d'utilisation. Il envoie un rapport budgétaire et des alertes si un projet a dépassé son allocation. À 0,005 $ par crédit, ce workflow vous aide à maîtriser les coûts de recherche des agents.
Déclencheur
Cron 1er du mois à 9h UTC
Planification
Mensuel 1er 9h
Étapes du workflow
Charger la configuration du budget
Lire les allocations budgétaires par projet et les seuils d'alerte depuis un fichier de configuration.
Agréger l'utilisation par projet
Lire les journaux d'utilisation du mois dernier et regrouper la consommation de crédits par projet ou ID d'agent.
Calculer les dépenses et comparer le budget
Multiplier les crédits par 0,005 $ pour obtenir les dépenses en dollars. Comparer chaque projet à son budget mensuel.
Prévision du mois prochain
Utiliser la tendance des 3 derniers mois pour projeter l'utilisation du mois prochain et signaler les projets susceptibles de dépasser le budget.
Générer le rapport budgétaire
Créer un rapport structuré avec les dépenses par projet, l'utilisation du budget et les prévisions.
Envoyer des alertes
Notifier les responsables de projet via Slack ou par e-mail s'ils ont dépassé le budget ou sont en voie de le faire.
Implémentation Python
import json, os
from pathlib import Path
from datetime import date, timedelta
COST_PER_CREDIT = 0.005
BUDGET_FILE = Path("search_budgets.json")
USAGE_LOG = Path("search_usage.jsonl")
REPORTS_DIR = Path("budget_reports")
REPORTS_DIR.mkdir(exist_ok=True)
def load_usage(month_str: str) -> dict:
"""Load usage from JSONL log, filtered to the given month."""
usage = {}
if not USAGE_LOG.exists():
return usage
for line in USAGE_LOG.read_text().strip().split("\n"):
if not line:
continue
entry = json.loads(line)
if entry.get("date", "").startswith(month_str):
project = entry.get("project", "default")
usage.setdefault(project, 0)
usage[project] += entry.get("credits", 0)
return usage
def load_history(months: int = 3) -> list:
"""Load usage for the last N months for forecasting."""
history = []
today = date.today()
for i in range(1, months + 1):
d = today.replace(day=1) - timedelta(days=30 * i)
month_str = d.strftime("%Y-%m")
history.append(load_usage(month_str))
return history
def forecast(history: list, project: str) -> float:
values = [h.get(project, 0) for h in history if project in h]
if not values:
return 0
return sum(values) / len(values)
def run():
budgets = json.loads(BUDGET_FILE.read_text())
last_month = (date.today().replace(day=1) - timedelta(days=1)).strftime("%Y-%m")
usage = load_usage(last_month)
history = load_history(3)
report = {"month": last_month, "projects": []}
alerts = []
for project, budget_credits in budgets.items():
credits_used = usage.get(project, 0)
spend = credits_used * COST_PER_CREDIT
budget_dollars = budget_credits * COST_PER_CREDIT
utilization = credits_used / max(budget_credits, 1) * 100
forecasted = forecast(history, project)
forecasted_spend = forecasted * COST_PER_CREDIT
entry = {
"project": project,
"credits_used": credits_used,
"spend_usd": round(spend, 2),
"budget_usd": round(budget_dollars, 2),
"utilization_pct": round(utilization, 1),
"forecast_credits": round(forecasted),
"forecast_usd": round(forecasted_spend, 2),
}
report["projects"].append(entry)
if utilization > 100:
alerts.append(f"OVER BUDGET: {project} used {utilization:.0f}% of budget")
if forecasted > budget_credits * 1.2:
alerts.append(f"FORECAST ALERT: {project} trending ${forecasted_spend:.2f} vs ${budget_dollars:.2f} budget")
out = REPORTS_DIR / f"budget_{last_month}.json"
out.write_text(json.dumps(report, indent=2))
print(f"Budget report for {last_month}:")
for p in report["projects"]:
print(f" {p['project']}: ${p['spend_usd']} / ${p['budget_usd']} ({p['utilization_pct']}%)")
for a in alerts:
print(f" ALERT: {a}")
run()Implémentation JavaScript
const fs = await import('fs');
const COST_PER_CREDIT = 0.005;
const budgets = JSON.parse(fs.readFileSync('search_budgets.json', 'utf8'));
const USAGE_LOG = 'search_usage.jsonl';
const REPORTS_DIR = 'budget_reports';
try { fs.mkdirSync(REPORTS_DIR); } catch {}
function loadUsage(monthStr) {
const usage = {};
try {
const lines = fs.readFileSync(USAGE_LOG, 'utf8').trim().split('\n');
for (const line of lines) {
if (!line) continue;
const entry = JSON.parse(line);
if ((entry.date||'').startsWith(monthStr)) {
const project = entry.project || 'default';
usage[project] = (usage[project]||0) + (entry.credits||0);
}
}
} catch {}
return usage;
}
function getLastMonth() {
const d = new Date();
d.setDate(0);
return d.toISOString().slice(0,7);
}
function loadHistory(months) {
const history = [];
const now = new Date();
for (let i = 1; i <= months; i++) {
const d = new Date(now.getFullYear(), now.getMonth()-i, 1);
history.push(loadUsage(d.toISOString().slice(0,7)));
}
return history;
}
const lastMonth = getLastMonth();
const usage = loadUsage(lastMonth);
const history = loadHistory(3);
const report = {month:lastMonth, projects:[]};
const alerts = [];
for (const [project, budgetCredits] of Object.entries(budgets)) {
const creditsUsed = usage[project]||0;
const spend = creditsUsed * COST_PER_CREDIT;
const budgetUsd = budgetCredits * COST_PER_CREDIT;
const utilization = creditsUsed / Math.max(budgetCredits,1) * 100;
const histVals = history.map(h=>h[project]||0).filter(v=>v>0);
const forecasted = histVals.length ? histVals.reduce((s,v)=>s+v,0)/histVals.length : 0;
report.projects.push({project, creditsUsed, spendUsd:Math.round(spend*100)/100, budgetUsd:Math.round(budgetUsd*100)/100, utilizationPct:Math.round(utilization*10)/10, forecastCredits:Math.round(forecasted), forecastUsd:Math.round(forecasted*COST_PER_CREDIT*100)/100});
if (utilization > 100) alerts.push('OVER BUDGET: '+project+' used '+Math.round(utilization)+'%');
if (forecasted > budgetCredits * 1.2) alerts.push('FORECAST: '+project+' trending $'+(forecasted*COST_PER_CREDIT).toFixed(2)+' vs $'+budgetUsd.toFixed(2));
}
fs.writeFileSync(REPORTS_DIR+'/budget_'+lastMonth+'.json', JSON.stringify(report, null, 2));
console.log('Budget report for '+lastMonth+':');
report.projects.forEach(p => console.log(' '+p.project+': $'+p.spendUsd+' / $'+p.budgetUsd+' ('+p.utilizationPct+'%)'));
alerts.forEach(a => console.log(' ALERT: '+a));Plateformes utilisées
Recherche web avec graphe de connaissances, PAA et aperçus IA