-
Notifications
You must be signed in to change notification settings - Fork 6
Budget Controls
adham90 edited this page Feb 14, 2026
·
3 revisions
Set spending limits to prevent runaway LLM costs at global and per-agent levels.
# config/initializers/ruby_llm_agents.rb
RubyLLM::Agents.configure do |config|
config.budgets = {
global_daily: 100.0, # $100/day across all agents
global_monthly: 2000.0, # $2000/month across all agents
enforcement: :hard # Block when exceeded
}
endApply to all agents combined:
config.budgets = {
global_daily: 100.0, # Daily limit
global_monthly: 2000.0 # Monthly limit
}Set limits for specific agents:
config.budgets = {
per_agent_daily: {
"ExpensiveAgent" => 50.0, # $50/day
"CheapAgent" => 5.0 # $5/day
},
per_agent_monthly: {
"ExpensiveAgent" => 500.0 # $500/month
}
}Block requests when budget is exceeded:
config.budgets = {
global_daily: 100.0,
enforcement: :hard
}
# When exceeded:
MyAgent.call(query: "test")
# => Raises RubyLLM::Agents::BudgetExceededErrorAllow requests but log warnings:
config.budgets = {
global_daily: 100.0,
enforcement: :soft
}
# When exceeded:
MyAgent.call(query: "test")
# => Executes but logs warning# Global status
status = RubyLLM::Agents::BudgetTracker.status
# => {
# global_daily: {
# limit: 100.0,
# current: 45.50,
# remaining: 54.50,
# percentage_used: 45.5
# },
# global_monthly: {
# limit: 2000.0,
# current: 890.0,
# remaining: 1110.0,
# percentage_used: 44.5
# }
# }
# Per-agent status
status = RubyLLM::Agents::BudgetTracker.status(agent_type: "MyAgent")# Check remaining budget
remaining = RubyLLM::Agents::BudgetTracker.remaining_budget(:global, :daily)
# => 54.50
remaining = RubyLLM::Agents::BudgetTracker.remaining_budget(:per_agent, :daily, "MyAgent")
# => 25.00if RubyLLM::Agents::BudgetTracker.exceeded?(:global, :daily)
notify_admin("Daily budget exceeded!")
endGet notified before hitting hard limits:
config.budgets = {
global_daily: 100.0,
soft_cap_percentage: 80, # Alert at 80%
enforcement: :hard
}
config.on_alert = ->(event, payload) {
if event == :budget_soft_cap
Slack::Notifier.new(ENV['SLACK_WEBHOOK']).ping(
"Budget warning: $#{payload[:total_cost]} / $#{payload[:limit]}"
)
end
}Alert triggers at $80 (80% of $100).
RubyLLM::Agents.configure do |config|
config.budgets = {
# Global limits
global_daily: 100.0,
global_monthly: 2000.0,
# Per-agent limits
per_agent_daily: {
"ContentGeneratorAgent" => 50.0,
"SearchAgent" => 10.0,
"AnalyticsAgent" => 25.0
},
per_agent_monthly: {
"ContentGeneratorAgent" => 500.0
},
# Enforcement
enforcement: :hard,
# Soft cap (percentage of limit to trigger warning)
soft_cap_percentage: 80
}
endbegin
result = MyAgent.call(query: query)
rescue RubyLLM::Agents::BudgetExceededError => e
Rails.logger.error("Budget exceeded: #{e.message}")
# Option 1: Return cached/default response
cached_response
# Option 2: Queue for later
AgentJob.perform_later(query: query)
# Option 3: Notify user
render json: { error: "Service temporarily unavailable" }
end# Last 7 days of spending
RubyLLM::Agents::Execution
.where("created_at >= ?", 7.days.ago)
.group("DATE(created_at)")
.sum(:total_cost)
# => { "2024-01-08" => 85.20, "2024-01-09" => 92.10, ... }RubyLLM::Agents::Execution
.today
.group(:agent_type)
.sum(:total_cost)
# => { "SearchAgent" => 25.50, "ContentAgent" => 45.00 }RubyLLM::Agents::Execution
.this_month
.group(:model_id)
.sum(:total_cost)
# => { "gpt-4o" => 450.00, "gpt-4o-mini" => 50.00 }# Current daily run rate
daily_total = RubyLLM::Agents::Execution.today.sum(:total_cost)
hours_elapsed = (Time.current - Time.current.beginning_of_day) / 3600.0
hourly_rate = daily_total / hours_elapsed
projected_daily = hourly_rate * 24
# Monthly projection
days_in_month = Time.current.end_of_month.day
monthly_total = RubyLLM::Agents::Execution.this_month.sum(:total_cost)
daily_average = monthly_total / Time.current.day
projected_monthly = daily_average * days_in_monthThe dashboard shows:
- Current spending vs. limits
- Budget utilization charts
- Spending trends over time
- Per-agent cost breakdowns
# Start with soft enforcement to understand usage
config.budgets = {
global_daily: 100.0,
enforcement: :soft # Log warnings first
}# Base limits on historical usage + buffer
avg_daily = RubyLLM::Agents::Execution
.where("created_at >= ?", 30.days.ago)
.sum(:total_cost) / 30
# Set limit at 150% of average
config.budgets = {
global_daily: avg_daily * 1.5
}config.budgets = {
per_agent_daily: {
"ExpensiveGPT4Agent" => 20.0, # Strict limit
"CheapMiniAgent" => 50.0 # More lenient
}
}config.budgets = {
soft_cap_percentage: 75 # Early warning
}
config.on_alert = ->(event, payload) {
return unless event == :budget_soft_cap
percentage = (payload[:total_cost] / payload[:limit] * 100).round
if percentage >= 90
PagerDuty.alert("Critical: Budget at #{percentage}%")
else
Slack.notify("Budget warning: #{percentage}% used")
end
}# Weekly budget review
weekly_spending = RubyLLM::Agents::Execution
.where("created_at >= ?", 1.week.ago)
.sum(:total_cost)
weekly_limit = config.budgets[:global_daily] * 7
utilization = weekly_spending / weekly_limit
Rails.logger.info("Weekly budget utilization: #{(utilization * 100).round}%")Budget limits are different from API rate limits:
| Aspect | Budget Limits | Rate Limits |
|---|---|---|
| Metric | Cost (dollars) | Requests per time |
| Purpose | Cost control | API protection |
| Scope | Your application | Provider-imposed |
Handle both:
begin
result = MyAgent.call(query: query)
rescue RubyLLM::Agents::BudgetExceededError
# Budget exceeded - wait or use fallback
rescue Faraday::TooManyRequestsError
# Rate limited - retry with backoff
endFor multi-tenant applications, you can set per-tenant budget limits using the Tenant model.
# config/initializers/ruby_llm_agents.rb
RubyLLM::Agents.configure do |config|
config.multi_tenancy_enabled = true
config.tenant_resolver = -> { Current.tenant_id }
end# Create or update tenant budget
RubyLLM::Agents::Tenant.find_or_create_by(tenant_id: "tenant_123") do |tenant|
tenant.name = "Acme Corp"
tenant.daily_limit = 50.0
tenant.monthly_limit = 500.0
tenant.enforcement = :hard
end
# Update existing budget
tenant = RubyLLM::Agents::Tenant.find_by(tenant_id: "tenant_123")
tenant.update(daily_limit: 75.0)status = RubyLLM::Agents::BudgetTracker.status(tenant_id: "tenant_123")
# => {
# tenant_daily: { limit: 50.0, current: 25.0, remaining: 25.0 },
# tenant_monthly: { limit: 500.0, current: 150.0, remaining: 350.0 }
# }# Total spending for a tenant
RubyLLM::Agents::Execution
.by_tenant("tenant_123")
.this_month
.sum(:total_cost)
# Compare tenants
RubyLLM::Agents::Execution
.this_month
.group(:tenant_id)
.sum(:total_cost)See Multi-Tenancy for complete multi-tenancy documentation.
- Multi-Tenancy - Per-tenant configuration
- Alerts - Budget notifications
- Execution Tracking - Cost analytics
- Dashboard - Budget monitoring
- Configuration - Full setup guide