Skip to main content
Lesson 16 of 25 · Building OpenAI Agents

Reasoning Agents (GPT-5.6 Sol, high to max effort)

Lesson 16 of 25 Updated November 2, 2026 Developer
On this page
  1. Reasoning Agents (GPT-5.6, high to max effort)
  2. When to enable reasoning in an agent
  3. Sol + high/xhigh effort: deep reasoning
  4. Terra + medium effort: fast reasoning
  5. Pattern: configuration router
  6. Streaming behavior with reasoning enabled
  7. Optimizing costs
  8. Key takeaways

Updated November 2, 2026 — models. o3, o3-pro, and legacy GPT-5 snapshots will be removed from the API on December 11, 2026, and o4-mini has long been superseded. For new agents, start with the GPT-6 family: GPT-6.1 Sol for balance, GPT-6 Astra for the most demanding tasks.

Reasoning Agents (GPT-5.6, high to max effort)

With the GPT-5.6 family (available since July 2026), reasoning is no longer handled by separate models as in the previous generation (o3-pro, o4-mini): it is now a per-request setting (none, low, medium, high, xhigh, max) applicable to every model. An agent that truly needs to think—exploring multiple paths before answering—will typically use GPT-5.6 Sol with high or xhigh effort. Integrated into your agents, this reasoning capability unlocks tasks that demand genuine deliberation.

When to enable reasoning in an agent

Deep reasoning shines in specific situations, and experience shows they all share a common trait: comparing possible paths before making a decision. This applies to complex planning, where you break a task into optimal steps, and mathematical analysis—calculations, statistics, optimization—where one wrong step invalidates the rest. It also applies to debugging, which involves tracing a symptom back to its root cause, and decision-making, where you must evaluate several options and choose the best one. Code review falls into the same category: finding a subtle bug requires mentally simulating executions that linear reading won’t reveal.

For simple tasks (answering a question, formatting text), GPT-5.6 Terra or Luna with low effort (or even none) is faster and cheaper. Paying for reasoning to rephrase a paragraph is like idling a race car in traffic.

Sol + high/xhigh effort: deep reasoning

GPT-5.6 Sol with high reasoning effort replaces what o3-pro used to do. The agent takes more time but produces deeper analyses. The example below is typical: a strategic question with three options, where the right answer depends on trade-offs between risk, cost, and time horizon. Note that the instructions explicitly define the dimensions to consider—reasoning always benefits from clear constraints.

from agents import Agent, Runner, ModelSettings
from openai.types.shared import Reasoning

strategic_advisor = Agent(
    name="Strategic Advisor",
    instructions="""You are a business strategy consultant.
    Analyze deeply before recommending.
    Always consider: risks, opportunities,
    costs, and alternatives.""",
    model="gpt-5.6-sol",
    model_settings=ModelSettings(reasoning=Reasoning(effort="high")),
)

result = Runner.run_sync(
    strategic_advisor,
    """Our SaaS startup has 500 clients, €2M MRR, and is growing 15% per month.
    We are debating:
    A) Raise a Series B (€20M) and accelerate in the US
    B) Stay bootstrapped and consolidate in Europe
    C) Seek a strategic acquirer
    Which strategy do you recommend and why?"""
)
print(result.final_output)

For the most critical analyses, ramp up to xhigh or max. There is also an ultra setting (announced in July 2026) that coordinates 4 agents in parallel by default (up to 16 on certain evaluations) for the heaviest tasks—powerful, but with significantly higher token consumption: reserve it for problems that justify the cost.

Terra + medium effort: fast reasoning

Between no reasoning and deep analysis lies a sweet spot widely used in production. GPT-5.6 Terra with medium effort offers a good compromise between reasoning capability and speed—the equivalent of the former o4-mini. Ideal for agents that need to reason quickly, like this diagnostic agent that reads server metrics and must link memory saturation to a spike in 5xx errors within seconds, while the site is experiencing an incident.

from agents import Agent, Runner, ModelSettings, function_tool
from openai.types.shared import Reasoning

@function_tool
def get_server_metrics(server: str) -> str:
    """Retrieves metrics for a server."""
    import json
    metrics = {
        "cpu": 87.5,
        "ram": 92.1,
        "disk": 65.3,
        "requests_per_second": 1250,
        "response_time_p99": 450,
        "errors_5xx": 23,
    }
    return json.dumps(metrics)

diagnostic_agent = Agent(
    name="Diagnostic Agent",
    instructions="""You diagnose infrastructure problems.
    Analyze the metrics and identify the probable cause.
    Propose immediate and long-term corrective actions.""",
    model="gpt-5.6-terra",
    model_settings=ModelSettings(reasoning=Reasoning(effort="medium")),
    tools=[get_server_metrics],
)

result = Runner.run_sync(
    diagnostic_agent,
    "The site has been slow for 30 minutes. Diagnose server web-prod-01."
)

Pattern: configuration router

You don’t have to pick one configuration forever. Use a lightweight configuration for routing and the appropriate one for execution: a first agent reads the task, returns a typed object indicating which model and effort to use, then you instantiate the execution agent with that decision. The reason field isn’t decorative—it lets you, when reviewing your logs, verify that the router isn’t systematically over-provisioning.

from pydantic import BaseModel
from typing import Literal

class ConfigDecision(BaseModel):
    model: Literal["gpt-5.6-luna", "gpt-5.6-terra", "gpt-5.6-sol"]
    effort: Literal["none", "low", "medium", "high", "xhigh"]
    reason: str

router_agent = Agent(
    name="Smart Router",
    instructions="""Analyze the task and decide which configuration to use:
    - gpt-5.6-luna, effort none/low: simple tasks (summaries, rephrasing, factual answers)
    - gpt-5.6-terra, effort medium: fast reasoning (classification, diagnostics)
    - gpt-5.6-sol, effort high/xhigh: complex tasks (strategic planning, deep analysis, math)""",
    model="gpt-5.6-terra",
    model_settings=ModelSettings(reasoning=Reasoning(effort="medium")),
    output_type=ConfigDecision,
)

async def process_with_optimal_config(task: str):
    # Step 1: choose the configuration
    decision = await Runner.run(router_agent, task)
    config = decision.final_output
    print(f"Configuration: {config.model} / effort {config.effort} ({config.reason})")

    # Step 2: execute with the right configuration
    execution_agent = Agent(
        name="Execution Agent",
        instructions="Accomplish the requested task with precision.",
        model=config.model,
        model_settings=ModelSettings(reasoning=Reasoning(effort=config.effort)),
    )
    result = await Runner.run(execution_agent, task)
    return result.final_output

Streaming behavior with reasoning enabled

When reasoning is enabled, streaming has a quirk: the model’s internal thought process is not streamed in plain text. Your interface therefore receives tokens for the final answer, but nothing during the reasoning phase.

agent = Agent(
    name="Analyst",
    instructions="Analyze the data deeply.",
    model="gpt-5.6-sol",
    model_settings=ModelSettings(reasoning=Reasoning(effort="high")),
)

# Streaming delivers the final answer, not the intermediate reasoning
result = Runner.run_streamed(agent, "Analyze this complex problem.")
async for event in result.stream_events():
    if event.type == "raw_response_event":
        if hasattr(event.data, "delta") and event.data.delta:
            print(event.data.delta, end="", flush=True)

Account for this latency in your UX: with high effort or higher, the first tokens may arrive after a significant thinking time. An explicit waiting indicator prevents users from thinking the app has frozen and refreshing the page at the worst moment.

Optimizing costs

Reasoning consumes additional tokens (internal thinking is billed). Two levers help contain costs: lower the default effort and only ramp up when needed, then separate decision from execution—that is, reason to decide but execute without reasoning. The hybrid workflow below applies the second principle—Terra at medium establishes the approach, Luna carries it out with tools.

# Pattern: hybrid reasoning
# Terra + medium for decision, Luna without reasoning for execution

decision_agent = Agent(
    name="Decider",
    instructions="Decide on the optimal approach.",
    model="gpt-5.6-terra",
    model_settings=ModelSettings(reasoning=Reasoning(effort="medium")),
)

executor_agent = Agent(
    name="Executor",
    instructions="Execute the decided plan.",
    model="gpt-5.6-luna",  # Cheaper for execution
    tools=[search_crm, generate_report],
)

async def hybrid_workflow(task: str):
    plan = await Runner.run(decision_agent, f"How to handle: {task}")
    result = await Runner.run(executor_agent, plan.final_output)
    return result.final_output

Key takeaways

  • Reasoning is a per-request setting on every GPT-5.6 model (none → max), no longer separate models like o3-pro/o4-mini
  • GPT-5.6 Sol with high/xhigh effort: strategic planning, complex analysis, mathematics
  • GPT-5.6 Terra with medium effort: fast reasoning for diagnostics and routing
  • The ultra setting coordinates multiple agents in parallel for the heaviest tasks—significantly higher token cost
  • The router pattern dynamically selects the model + effort combination and optimizes costs
  • Reason to decide, execute without reasoning: the best quality-to-price ratio