Agent Max Budget

Set a USD cap on agent spend via ExecutionConfig

Cap how much an agent can spend per run with ExecutionConfig(max_budget=...) — when the limit is hit, PraisonAI stops the run and raises BudgetExceededError.

python
from praisonaiagents import Agent, ExecutionConfig

agent = Agent(
    name="Researcher",
    instructions="You research topics thoroughly",
    execution=ExecutionConfig(max_budget=0.50),
)
agent.start("Summarise today's AI news")

The user sets a spend cap; the agent stops the run and raises BudgetExceededError once estimated cost exceeds the limit.

Diagram

Yes

No

User Prompt

Agent Run

Track Token Cost

Under Budget?

Continue

BudgetExceededError

Three ways to set it

Python, YAML, and the CLI all set the same ExecutionConfig.max_budget.

Python

python
from praisonaiagents import Agent, ExecutionConfig

agent = Agent(
    name="Researcher",
    instructions="You research topics thoroughly",
    execution=ExecutionConfig(max_budget=0.50),
)
agent.start("Summarise today's AI news")

YAML

yaml
process: workflow
roles:
  researcher:
    role: Researcher
    goal: Research topics thoroughly
    backstory: You research topics thoroughly
    execution:
      max_budget: 0.50
      on_budget_exceeded: stop
    tasks:
      t1:
        description: Summarise today's AI news
        expected_output: One paragraph

See YAML Reference → execution: block.

CLI

bash
praisonai loop "Summarise today's AI news" --max-budget 0.50

The cap covers the whole loop, not each iteration. Add --on-budget-exceeded warn to log and continue instead of stopping. See CLI Budget Handling.

Quick Start

  1. Set a simple USD cap
    python
    from praisonaiagents import Agent, ExecutionConfig
    
    agent = Agent(
        name="Researcher",
        instructions="You research topics thoroughly",
        execution=ExecutionConfig(max_budget=0.50),
    )
    
    agent.start("Research the history of AI")

    When spend reaches $0.50, the run stops with BudgetExceededError including agent name and totals.

  2. Async run with budget cap
    python
    import asyncio
    from praisonaiagents import Agent, ExecutionConfig
    
    agent = Agent(
        name="AsyncResearcher",
        instructions="Research topics asynchronously",
        execution=ExecutionConfig(max_budget=0.50),
    )
    
    async def main():
        try:
            await agent.astart("Research the history of AI")
        except Exception as e:
            if "BudgetExceeded" in type(e).__name__:
                print(f"Budget exceeded: {e}")
    
    asyncio.run(main())

    astart() raises BudgetExceededError the same way start() does — the async path now has identical pre-call guards and post-call cost accounting.

  3. Warn instead of stopping
    python
    from praisonaiagents import Agent, ExecutionConfig
    
    agent = Agent(
        name="Analyst",
        instructions="Analyse data carefully",
        execution=ExecutionConfig(
            max_budget=1.00,
            on_budget_exceeded="warn",
        ),
    )
    
    agent.start("Summarise this quarterly report")

    With on_budget_exceeded="warn", the agent logs a warning but continues. Default is "stop".

How It Works

Diagram
BudgetLLMAgentUserBudgetLLMAgentUseralt[stop mode AND total >= max_budget][warn/callable AND total >= max_budget]loop[Each LLM call]start(prompt)chat completionresponse + usagerecord actual costBudgetExceededErrortrigger warn / handlerresult

Every way of building the agent’s LLM is covered:

How the agent’s LLM is setmax_budget enforcedtotal_cost / cost_summary populated
llm="gpt-4o" and other OpenAI-style names✅✅
llm="anthropic/...", mistral/..., ollama/..., openrouter/...✅✅
llm={"model": "...", "base_url": "..."}✅✅
llm=LLM(...) model object✅✅
A turn answered by a fallback_models entry✅ priced as the model that answered✅

The cap is checked after each LLM call, including calls inside a tool loop:

python
from praisonaiagents import Agent, ExecutionConfig

def fetch_price(ticker: str) -> str:
    """Fetch the latest price for a ticker."""
    return f"{ticker}: 123.45"

agent = Agent(
    name="Analyst",
    instructions="Look up prices for the symbols the user names.",
    llm="anthropic/claude-3-5-sonnet-20240620",
    tools=[fetch_price],
    execution=ExecutionConfig(max_budget=0.10),
)

try:
    agent.start("Price AAPL, MSFT, and GOOG.")
except Exception as e:
    print(type(e).__name__, e)  # BudgetExceededError Agent 'Analyst' exceeded budget: ...

Budget tracking adds zero overhead when max_budget is None (the default).

Schedulers use the same brake — see Async Scheduler → Budget-aware Scheduling. Setting max_cost=0 on AsyncAgentScheduler is a real (zero) budget and short-circuits start() (returns False, no background task) when combined with run_immediately=True. As of PraisonAI PR #5766 the sync AgentScheduler matches this behavior on every entry point, including execute_once() (returns None) and start(run_immediately=True).

Configuration Options

OptionTypeDefaultDescription
max_budget`float \None`NoneHard USD limit per agent run. None disables tracking.
on_budget_exceeded`”stop” \“warn” \callable`"stop"Action when the cap is reached

Best Practices

Start with a conservative cap in production

Set max_budget on any agent that runs unattended or loops over tools. $0.25–$1.00 is a sensible starting range for research agents.

Use warn mode during development

on_budget_exceeded="warn" lets you see full output while still logging when you’d have been stopped in production.

Retrying after the cap sends no request

For a provider/model agent with on_budget_exceeded="stop", once it has crossed max_budget, every later chat() / achat() raises BudgetExceededError again before contacting the provider. Catching the error and retrying cannot spend more — create a new agent (or one with a higher cap) to continue.

Combine with rate limiting

Budget caps control spend; rate limiters control request frequency. Use both for cost-sensitive deployments.

See also: Autonomous run budget

ExecutionConfig.max_budget is one of two budget mechanisms. run_autonomous / run_autonomous_async have their own independent cap via AutonomyConfig — pick the one that matches your run type.

MechanismWhereOn limit hitResumable?
ExecutionConfig.max_budgetAny runRaises BudgetExceededErrorNo
AutonomyConfig.max_budget_usd / max_tokensrun_autonomous / run_autonomous_async onlyReturns AutonomyResult(completion_reason="budget_exhausted")Yes when budget_action="pause"

For autonomous runs, prefer the AutonomyConfig cap — it pauses recoverably instead of raising. See Autonomy Budget.

Related