> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Reasoning Models

> How PraisonAI handles OpenAI o1/o3/o4/gpt-5.x reasoning models automatically

Reasoning models (OpenAI `o1`, `o3`, `o4`, `gpt-5.x`) accept a different set of parameters — PraisonAI detects them automatically and normalises your `Agent(...)` config so the same code just works.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "Reasoning Model Normalization"
        Agent[🤖 Agent] --> Detect{🔍 Reasoning<br/>model?}
        Detect -->|Yes| Normalize[🛠️ Rename max_tokens<br/>Drop sampling params]
        Detect -->|No| Passthrough[📤 Send as-is]
        Normalize --> LLM[💬 LLM Call]
        Passthrough --> LLM
    end

    classDef agent fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef check fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef process fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef llm fill:#10B981,stroke:#7C90A0,color:#fff
    class Agent agent
    class Detect check
    class Normalize,Passthrough process
    class LLM llm
```

## Quick Start

**1. Use a reasoning model**

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent

agent = Agent(
    name="Reasoner",
    instructions="Solve the problem step by step.",
    llm="gpt-5",   # or "o1", "o3-mini", "o4-mini", etc.
)
agent.start("Design a caching layer for a high-traffic API.")
```

No extra flags. PraisonAI detects reasoning models and normalises parameters for you.

**2. Cap the response length**

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent

agent = Agent(
    name="Reasoner",
    instructions="Solve the problem step by step.",
    llm="o3-mini",
    max_tokens=4000,  # Automatically sent as max_completion_tokens
)
agent.start("Explain the CAP theorem with an example.")
```

You can keep writing `max_tokens=...` — on reasoning models it is rewritten to `max_completion_tokens` before the request.

***

## How It Works

PraisonAI checks the model before every call and rewrites parameters only when the model is a reasoning model.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant Agent
    participant Native as openai_client<br/>_normalize_chat_params
    participant LiteLLMPath as llm.py<br/>_build_completion_params
    participant LLM as OpenAI / LiteLLM

    User->>Agent: agent.start("...")
    alt Native OpenAI client path
        Agent->>Native: build request params
        Native->>Native: omit temperature=None, max_tokens=None
        Native->>Native: reasoning? max_tokens → max_completion_tokens
        Native->>LLM: chat.completions.create(...)
    else LiteLLM path
        Agent->>LiteLLMPath: build request params
        LiteLLMPath->>LiteLLMPath: reasoning? max_tokens → max_completion_tokens
        LiteLLMPath->>LiteLLMPath: drop temperature, top_p, penalties, logit_bias
        LiteLLMPath->>LLM: completion(...)
    end
    LLM-->>Agent: response
    Agent-->>User: answer
```

| Step | Behaviour |
| - | - |
| Detection | `is_reasoning_model(model)` decides the path |
| Reasoning model | `max_tokens` renamed on both paths; sampling params dropped on the LiteLLM path |
| Chat model | Parameters sent unchanged |
| Responses API path | Already uses `max_output_tokens` — unchanged |

***

## Recognised Models

Detection uses two paths, in order:

1. **Primary:** `litellm.supports_reasoning(model=model_name)` when litellm is installed and exposes the helper.
2. **Fallback:** strip the provider prefix (e.g. `openai/`, `azure/`) and match the lowercase prefix — `o1`, `o3`, `o4`, or `gpt-5`.

Results are cached with `functools.lru_cache(maxsize=256)`.

| Model family | Example ids | Detection |
| - | - | - |
| OpenAI o1 | `o1`, `o1-mini`, `o1-preview` | prefix + litellm |
| OpenAI o3 | `o3`, `o3-mini` | prefix + litellm |
| OpenAI o4 | `o4-mini` | prefix + litellm |
| OpenAI gpt-5.x | `gpt-5`, `gpt-5-mini`, `gpt-5-nano`, `gpt-5.6-luna`, … | prefix + litellm |

> [!NOTE]
>
> Provider prefixes are stripped before matching: `openai/o3-mini` → `o3-mini`. Both the native OpenAI client path and the LiteLLM path use the same `is_reasoning_model()` check, so any model LiteLLM's `supports_reasoning()` recognises is normalised on either path, not only the prefix-matched families.

***

## Parameter Behaviour

> [!NOTE]
>
> Before PraisonAI [#5910](https://github.com/MervinPraison/PraisonAI/pull/5910) (merged 2026-10-19), `Agent(llm="o3-mini" | "gpt-5" | …)` could send a request body containing `"max_tokens": null`, which reasoning models rejected with `400 invalid_type` (`Invalid type for 'max_tokens': expected an unsupported value, but got null instead.`) and the agent returned an empty answer. The native OpenAI client path now omits unset `temperature`/`max_tokens` and maps an explicit `max_tokens` to `max_completion_tokens` for reasoning models — your `Agent(...)` code just works.

On a reasoning model, PraisonAI rewrites and drops parameters as follows. Which rules apply depends on the path the request takes.

| Rule | Native OpenAI client path | LiteLLM path |
| - | - | - |
| `max_tokens` → `max_completion_tokens` | Renamed | Renamed |
| `max_completion_tokens` (explicit) | Wins over `max_tokens` | Wins over `max_tokens` |
| `temperature` / `max_tokens` left unset | Omitted from the request | Omitted from the request |
| `temperature` set explicitly | Sent as-is — the provider decides | Dropped |
| `top_p`, `presence_penalty`, `frequency_penalty`, `logit_bias` | Sent as-is — the provider decides | Dropped |
| Chat models (non-reasoning) | Unchanged | Unchanged |
| Responses API path | Unchanged (already uses `max_output_tokens`) | — |

> [!WARNING]
>
> Reasoning models reject `temperature`, `top_p`, and penalty params. On the LiteLLM path PraisonAI drops them silently so your code keeps working — but the values have no effect. On the native OpenAI client path they are forwarded, so leave them unset. If you rely on deterministic sampling, use a chat model instead.

***

## Which Parameters Should I Set?

Pick your parameters based on the model you chose.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TB
    Start[🎯 I want to configure my model] --> Q1{Is my model<br/>o1/o3/o4/gpt-5.x?}
    Q1 -->|No| Chat[✅ Set temperature, top_p,<br/>max_tokens as usual]
    Q1 -->|Yes| Q2{Need to cap<br/>response length?}
    Q2 -->|Yes| Cap[✅ Set max_tokens<br/>auto-mapped to max_completion_tokens]
    Q2 -->|No| Nothing[✅ Just set llm=... — nothing else]

    classDef start fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef check fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef result fill:#10B981,stroke:#7C90A0,color:#fff
    class Start start
    class Q1,Q2 check
    class Chat,Cap,Nothing result
```

***

## Common Patterns

Mix reasoning and chat models in one team — each agent normalizes independently based on its own model.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent, Task, PraisonAIAgents

planner = Agent(name="Planner", instructions="Plan step by step.", llm="o3-mini")
writer = Agent(name="Writer", instructions="Write clearly.", llm="gpt-4o", temperature=0.7)

agents = PraisonAIAgents(
    agents=[planner, writer],
    tasks=[
        Task(description="Plan an article on vector databases.", agent=planner),
        Task(description="Write the article from the plan.", agent=writer),
    ],
)
agents.start()
```

Be explicit with `max_completion_tokens` when you want it to win over `max_tokens`.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent

agent = Agent(
    name="Reasoner",
    instructions="Solve the problem step by step.",
    llm="o3-mini",
    max_completion_tokens=2000,  # Wins; max_tokens (if set) is dropped
)
agent.start("Prove that the square root of 2 is irrational.")
```

Migrate from a chat model to a reasoning model with no code changes.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent

# Was: llm="gpt-4o" with temperature and max_tokens
agent = Agent(
    name="Reasoner",
    instructions="Solve the problem step by step.",
    llm="gpt-5",       # swap the model — sampling params are dropped automatically
    max_tokens=3000,   # still works, mapped to max_completion_tokens
)
agent.start("Compare quicksort and mergesort.")
```

***

## Best Practices

> [accordion] Don't set temperature or top\_p on reasoning models
>
> They have no useful effect — dropped on the LiteLLM path, forwarded to the provider on the native OpenAI client path. If you rely on determinism or creative sampling, prefer a chat model such as `gpt-4o`.

> [accordion] Prefer max\_completion\_tokens when you want to be explicit
>
> It always wins over `max_tokens` on reasoning models, so there is no ambiguity about which limit applies.

> [accordion] Test model swaps before deploying
>
> Swapping `gpt-4o` → `gpt-5` silently drops your sampling params. Behaviour differs even though no error is raised — verify output quality first.

> [accordion] Use LiteLLM's latest release when possible
>
> Detection prefers `litellm.supports_reasoning()`. The prefix fallback only covers the `o1`/`o3`/`o4`/`gpt-5` families, so newer models are recognised sooner with an up-to-date litellm.

***

## Related

> [card] [Reasoning](https://praison.ai/docs/features/reasoning.md)
>
> Step-by-step reasoning as a technique.

> [card] [Model Capabilities](https://praison.ai/docs/features/model-capabilities.md)
>
> Capability detection helpers, including `is_reasoning_model()`.

> [card] [Thinking Budgets](https://praison.ai/docs/features/thinking-budgets.md)
>
> Budget reasoning tokens for controllable cost.

> [card] [OpenAI Quickstart](https://praison.ai/docs/features/openai-quickstart.md)
>
> First-time setup with OpenAI models.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.