Reasoning Effort

One graded knob (off → high) that maps to each provider's native reasoning control and persists across sessions

Set how hard the model thinks with one graded level; PraisonAI translates it to each provider’s native reasoning control.

python
from praisonaiagents import Agent

agent = Agent(
    instructions="Solve tricky problems step by step.",
    llm="openai/gpt-5",
    reasoning_effort="high",
)
agent.start("Design a load balancer for a spiky workload.")
Diagram

Reasoning Effort

📊 Level

🧠 PraisonAI Core

🤖 OpenAI/xAI
reasoning_effort

💭 Anthropic/Gemini
thinking budget

⚪ Others
no-op

Quick Start

  1. Enable with a level

    Pass a graded level to the agent.

    python
    from praisonaiagents import Agent
    
    agent = Agent(
        instructions="Solve tricky problems step by step.",
        llm="openai/gpt-5",
        reasoning_effort="high",
    )
    agent.start("Design a load balancer for a spiky workload.")
  2. Switch provider, same level

    The same level works on Anthropic and produces an extended-thinking budget under the hood.

    python
    from praisonaiagents import Agent
    
    agent = Agent(
        instructions="Solve tricky problems step by step.",
        llm="anthropic/claude-3-7-sonnet",
        reasoning_effort="high",
    )
    agent.start("Design a load balancer for a spiky workload.")
  3. Turn it off

    off is a zero-overhead no-op.

    python
    from praisonaiagents import Agent
    
    agent = Agent(
        instructions="Answer directly.",
        llm="openai/gpt-5",
        reasoning_effort="off",
    )
    agent.start("What is the capital of France?")
  4. Change it after construction

    The setter keeps a cached LLM in sync.

    python
    from praisonaiagents import Agent
    
    agent = Agent(instructions="Reason carefully.", llm="openai/gpt-5")
    agent.reasoning_effort = "low"
    agent.start("Summarise this in one line.")

    The setter also updates an already-built LLM in place, so a change after the instance materialises still lands on the next request.

    python
    from praisonaiagents import Agent
    
    agent = Agent(instructions="Reason carefully.", llm="openai/gpt-5")
    
    # Force the LLM to materialise (as `.start()` would).
    _ = agent.llm_instance
    
    # Change effort after materialisation — the very next request emits `high`.
    agent.reasoning_effort = "high"
    agent.start("Design a load balancer for a spiky workload.")

    The CLI --thinking <level> flag uses this same setter path internally, so the flag takes effect even when it is applied after the LLM has been built.


How It Works

Diagram
LLMProviderCoreAgentUserLLMProviderCoreAgentUserreasoning_effort=”high”resolve_reasoning_params(effort, model)native param (reasoning_effort / thinking)requestResponse
PhaseWhat happens
1. SetYou pass a graded level to the agent
2. ResolveCore maps the level to the model’s native control
3. RequestThe provider receives its native reasoning parameter

Streaming

start(stream=True) (and iter_stream()) honour reasoning_effort on both streaming branches.

Since PR #4780, streaming and non-streaming produce identical provider requests for reasoning-effort semantics. The same resolve_reasoning_params mapping runs on both paths, so "off" stays a zero-overhead no-op, unset stays absent, and a model without a native reasoning control is untouched. Tool follow-up turns inherit the knob.

python
from praisonaiagents import Agent

agent = Agent(
    instructions="Solve tricky problems step by step.",
    llm="o4-mini",
    reasoning_effort="high",
)

for chunk in agent.start("Design a load balancer for a spiky workload.", stream=True):
    print(chunk, end="", flush=True)

Levels

Each level maps to a native parameter per provider family.

LevelOpenAI/xAI requestAnthropic/Gemini requestNon-reasoning models
off———
minimalreasoning_effort="minimal"thinking={"type":"enabled","budget_tokens":2000}ignored
lowreasoning_effort="low"budget_tokens=4000ignored
mediumreasoning_effort="medium"budget_tokens=8000ignored
highreasoning_effort="high"budget_tokens=16000ignored

Provider Coverage

Which model families the level affects.

Model familyNative control
OpenAI o-series (o1, o3, o3-mini) and GPT‑5reasoning_effort
xAI Grok reasoning models (xai/grok-*)reasoning_effort
Anthropic Claude 3.7+ reasoning modelsextended-thinking thinking budget
Gemini 2.5+ reasoning modelsextended-thinking thinking budget
Everything else (e.g. gpt-4o, gpt-4o-mini)silently ignored

Which Level Should I Pick?

Match the level to the task.

Diagram

Quick lookup / one-liner

Simple reasoning

Default / balanced

Complex analysis / planning / long code

Not a reasoning task

What kind of task?

minimal

low

medium

high

off


Four Ways to Set It

The same level is available in Python, YAML, the CLI, and the Desktop app.

Python
from praisonaiagents import Agent

agent = Agent(instructions="Solve tricky problems.", llm="openai/gpt-5", reasoning_effort="high")
agent.start("Design a load balancer for a spiky workload.")
YAML
agent:
  reasoning_effort: high
CLI
praisonai run --thinking high "Design a load balancer for a spiky workload."

Desktop app: Open Settings → Models → Reasoning effort and pick a level. Off is the default and leaves the provider default in place; any other level is forwarded on the next turn (same rule as temperature / top_p). The choice round-trips through settings.json, so it persists across restarts. It is app-wide, not per-chat. See Desktop → Models & API Keys.


Session Persistence

The effort you were running is persisted on the session and restored on resume — you do not need to pass --thinking again.

bash
praisonai run --thinking high "start work"
# later:
praisonai run --continue "keep going"     # still runs at high

Backward Compatibility

thinking_budget remains a supported alias that folds into reasoning_effort.

python
from praisonaiagents import Agent

# Graded string alias.
agent = Agent(instructions="x", llm="openai/gpt-5", thinking_budget="high")

# Legacy int budget — normalised to the nearest level (8000 -> medium).
agent = Agent(instructions="x", llm="openai/gpt-5", thinking_budget=8000)

# Post-construction int still routes through the effort setter.
agent.thinking_budget = 16000

The graded value is what gets persisted, so the effort stays provider-portable.

agent.thinking_budget reads back the last integer budget that was set (or None); the graded string level always lives on agent.reasoning_effort. Assigning a graded string (agent.thinking_budget = "high") still routes through the effort setter, but agent.thinking_budget continues to report None in that case — read agent.reasoning_effort for the current level.


Best Practices

Match effort to task complexity

Start at medium and raise to high for planning, analysis, or long code.

Use off on non-reasoning models

reasoning_effort="off" is a no-op with no runtime cost.

Change effort mid-session

Assign agent.reasoning_effort at any time; the setter updates a cached LLM in place.

Prefer the graded level over the legacy int

Use a level (not a raw token budget) so the value stays provider-portable.

Works with stream=True

Since PR #4780, the graded level reaches the provider on the streaming path too — no need to disable streaming to get reasoning behaviour.


Related