How to Turn Off or Minimize Reasoning in GPT-5-Nano
Original question: Turn off gpt-5-nano reasoning

To turn off or minimize reasoning in GPT-5-Nano, you cannot set reasoning=None or reasoning={"effort": "none"} because the model does not accept a "none" effort value. Instead, use reasoning={"effort": "minimal"} in your API call. This reduces the reasoning tokens to a negligible amount, effectively giving you a fast, direct response without the overhead of full reasoning. If you need absolutely no reasoning at all, you must switch to a non-reasoning model like GPT-4o-mini, but that will be slower and more expensive.
The Full Answer

Understanding Reasoning in GPT-5-Nano
GPT-5-Nano is a reasoning model. This means that by default, it spends some of its output tokens on internal reasoning steps before generating the final answer. For tasks like name/gender inference, where you want a quick, direct JSON output, this reasoning overhead can be problematic. It can consume tokens, slow down responses, and even cause the model to run out of token budget before producing any visible output.
The official OpenAI documentation explains that for reasoning models like GPT-5 or o4-mini, any reasoning items returned in model responses with tool calls must also be passed back with tool call outputs. This indicates that reasoning is a first-class concept in these models, not something you can simply disable with a boolean flag.
The Problem with reasoning=None
A user on Stack Overflow reported that setting reasoning=None in the API call to GPT-5-Nano did not turn off reasoning. The model still consumed tokens on reasoning, and in some cases, returned an empty response because all completion tokens were used for reasoning before any visible output could be generated.
Here is the problematic code from the Stack Overflow question:
def infer_gender_batch(client, people, logger):
"""
Infer gender for a batch of people using ChatGPT API (gpt-5-nano).
Args:
client: OpenAI client instance
people: List of dicts with 'display_name', 'country_name', 'author_id'
logger: Logger instance
Returns:
tuple: (list of dicts with gender predictions, total_tokens)
"""
# Build input lines with full display names and country context
lines = [f"{i+1}. {p['display_name']} | Country: {p.get('country_name', 'unknown')}"
for i, p in enumerate(people)]
payload = "\n".join(lines)
prompt = (
"You are a linguistic name etymology analyzer. Based on historical naming patterns across cultures, "
"analyze the statistical gender association of these names from a scientific publication database.\n\n"
"For each name, determine the predominant gender association based on:\n"
"- Name etymology and linguistic roots\n"
"- Cultural naming traditions in the specified country\n"
"- Historical usage patterns in academic literature\n\n"
"Names:\n" + payload + "\n\n"
"Return a JSON array with this structure:\n"
'[{"name": "Full Name", "gender": "male", "probability": 0.95}, ...]\n\n'
'Where gender is "male", "female", or "unknown" and probability is 0-1.\n\n'
"Respond with ONLY the JSON array:"
)
try:
response = client.chat.completions.create(
model="gpt-5-nano",
messages=[{"role": "user", "content": prompt}],
reasoning=None,
max_completion_tokens=10000 # Increased to allow for reasoning + output but I still get zero output for 10 names supplied
)
if not response.choices or len(response.choices) == 0:
logger.error("No choices in response")
return None, 0
text = response.choices[0].message.content
# Log token usage
usage = response.usage
logger.info(f"API Response - prompt_tokens: {usage.prompt_tokens}, completion_tokens: {usage.completion_tokens}, total: {usage.total_tokens}")
# Check for reasoning tokens (if present)
if hasattr(usage, 'completion_tokens_details'):
logger.info(f"Completion tokens details: {usage.completion_tokens_details}")
# Log finish reason
finish_reason = response.choices[0].finish_reason
logger.info(f"Finish reason: {finish_reason}")
# Log content preview
logger.info(f"Content preview: {repr(text[:200] if text else '(empty)')}")
# Parse JSON response
if not text or not text.strip():
logger.error("Empty response from API - all tokens may have been used for reasoning")
return None, 0
# Strip markdown code fences if present (```json ... ```)
text = text.strip()
if text.startswith('```'):
# Remove opening code fence
lines_list = text.split('\n')
if lines_list[0].startswith('```'):
lines_list = lines_list[1:]
# Remove closing code fence
if lines_list and lines_list[-1].strip() == '```':
lines_list = lines_list[:-1]
text = '\n'.join(lines_list)
results = json.loads(text)
# Ensure results is a list
if not isinstance(results, list):
logger.error(f"Expected JSON array, got: {type(results)}")
return None, 0
return results, usage.total_tokens
except json.JSONDecodeError as e:
logger.error(f"Failed to parse JSON response: {e}")
logger.error(f"Response text: {text if 'text' in locals() else '(no response)'}")
return None, 0
except Exception as e:
logger.error(f"API call failed: {e}")
return None, 0
Notice the line reasoning=None. The user expected this to disable reasoning entirely. Instead, the model still reasoned, and for batches of 10 names, the response was often empty because all 10,000 completion tokens were consumed by reasoning before any JSON output could be produced.
The Accepted Solution: Use reasoning={"effort": "minimal"}
The accepted answer on Stack Overflow, provided by Matt Pitkin (score 4), explains that the reasoning parameter actually takes a dictionary, not a boolean or string. The dictionary has an "effort" key that accepts one of three string values: "none", "minimal", or "high".
However, the user who asked the question noted that GPT-5-Nano does not accept "none". When you try reasoning={"effort": "none"}, the API either returns an error or ignores the setting. But "minimal" works and achieves the desired effect of reducing reasoning to a negligible amount.
Here is the corrected code:
response = client.chat.completions.create(
model="gpt-5-nano",
messages=[{"role": "user", "content": prompt}],
reasoning={"effort": "minimal"},
max_completion_tokens=10000
)
This tells the model to use the minimum possible reasoning effort. For simple tasks like name/gender inference, this should produce a direct response with little to no visible reasoning tokens.
Why "minimal" Works and "none" Does Not
According to the Stack Overflow discussion, the GPT-5-Nano model is a reasoning model at its core. The architecture requires at least some reasoning to function. The "none" effort value would theoretically disable reasoning entirely, but the model does not support it. The "minimal" effort value is the lowest supported setting. It reduces reasoning to a bare minimum, often resulting in no visible reasoning tokens in the output, while still allowing the model to generate a response.
This is consistent with how other reasoning models in the GPT-5 family behave. The official documentation for function calling mentions that for reasoning models like GPT-5 or o4-mini, any reasoning items returned in model responses with tool calls must also be passed back with tool call outputs. This confirms that reasoning is an integral part of these models, not an optional feature that can be completely disabled.
Alternative Approach: Switch to a Non-Reasoning Model
If you absolutely cannot tolerate any reasoning overhead, the only reliable option is to use a non-reasoning model. The Stack Overflow user mentioned that GPT-4o-mini works for their use case, but it is slower and more expensive. Here is a comparison:
| Model | Reasoning | Speed | Cost (per 1M input tokens) | Cost (per 1M output tokens) |
|---|---|---|---|---|
| GPT-5-Nano (minimal) | Minimal | Fast | Low | Low |
| GPT-5-Nano (default) | Full | Moderate | Low | Low |
| GPT-4o-mini | None | Moderate | Higher | Higher |
| GPT-4o | None | Slower | Highest | Highest |
If you switch to GPT-4o-mini, you can remove the reasoning parameter entirely, as it is not a reasoning model. Here is an example:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
max_tokens=10000 # Note: use max_tokens, not max_completion_tokens for non-reasoning models
)
Note that for non-reasoning models, the parameter is max_tokens, not max_completion_tokens. Using max_completion_tokens on a non-reasoning model may cause an error or be ignored.
Step-by-Step Guide to Minimizing Reasoning in GPT-5-Nano
-
Identify your use case. If your task is simple and direct (like extracting structured data, answering factual questions, or generating JSON), you likely do not need full reasoning.
-
Set the reasoning effort to "minimal". In your API call, include the parameter:
reasoning={"effort": "minimal"} -
Set an appropriate token limit. Use
max_completion_tokensto cap the total output (reasoning + visible content). For a batch of 10 names, 10,000 tokens is generous. You may be able to reduce it to 2,000-5,000 tokens for faster responses. -
Monitor token usage. After each call, check
response.usage.completion_tokens_detailsto see how many tokens were used for reasoning vs. visible output. This will help you tune the token limit.usage = response.usage if hasattr(usage, 'completion_tokens_details'): print(f"Reasoning tokens: {usage.completion_tokens_details.reasoning_tokens}") print(f"Visible tokens: {usage.completion_tokens_details.visible_tokens}") -
Handle empty responses. If you still get empty responses, increase
max_completion_tokensor reduce the batch size. The model may need more tokens for reasoning than you expect. -
Fall back to a non-reasoning model if needed. If
"minimal"effort still causes problems, switch to GPT-4o-mini or another non-reasoning model.
Complete Working Example
Here is a corrected version of the infer_gender_batch function that uses reasoning={"effort": "minimal"}:
import json
from openai import OpenAI
def infer_gender_batch(client, people, logger):
"""
Infer gender for a batch of people using ChatGPT API (gpt-5-nano) with minimal reasoning.
Args:
client: OpenAI client instance
people: List of dicts with 'display_name', 'country_name', 'author_id'
logger: Logger instance
Returns:
tuple: (list of dicts with gender predictions, total_tokens)
"""
# Build input lines with full display names and country context
lines = [f"{i+1}. {p['display_name']} | Country: {p.get('country_name', 'unknown')}"
for i, p in enumerate(people)]
payload = "\n".join(lines)
prompt = (
"You are a linguistic name etymology analyzer. Based on historical naming patterns across cultures, "
"analyze the statistical gender association of these names from a scientific publication database.\n\n"
"For each name, determine the predominant gender association based on:\n"
"- Name etymology and linguistic roots\n"
"- Cultural naming traditions in the specified country\n"
"- Historical usage patterns in academic literature\n\n"
"Names:\n" + payload + "\n\n"
"Return a JSON array with this structure:\n"
'[{"name": "Full Name", "gender": "male", "probability": 0.95}, ...]\n\n'
'Where gender is "male", "female", or "unknown" and probability is 0-1.\n\n'
"Respond with ONLY the JSON array:"
)
try:
response = client.chat.completions.create(
model="gpt-5-nano",
messages=[{"role": "user", "content": prompt}],
reasoning={"effort": "minimal"},
max_completion_tokens=10000
)
if not response.choices or len(response.choices) == 0:
logger.error("No choices in response")
return None, 0
text = response.choices[0].message.content
# Log token usage
usage = response.usage
logger.info(f"API Response - prompt_tokens: {usage.prompt_tokens}, completion_tokens: {usage.completion_tokens}, total: {usage.total_tokens}")
# Check for reasoning tokens (if present)
if hasattr(usage, 'completion_tokens_details'):
logger.info(f"Completion tokens details: {usage.completion_tokens_details}")
# Log finish reason
finish_reason = response.choices[0].finish_reason
logger.info(f"Finish reason: {finish_reason}")
# Log content preview
logger.info(f"Content preview: {repr(text[:200] if text else '(empty)')}")
# Parse JSON response
if not text or not text.strip():
logger.error("Empty response from API - all tokens may have been used for reasoning")
return None, 0
# Strip markdown code fences if present (```json ... ```)
text = text.strip()
if text.startswith('```'):
lines_list = text.split('\n')
if lines_list[0].startswith('```'):
lines_list = lines_list[1:]
if lines_list and lines_list[-1].strip() == '```':
lines_list = lines_list[:-1]
text = '\n'.join(lines_list)
results = json.loads(text)
if not isinstance(results, list):
logger.error(f"Expected JSON array, got: {type(results)}")
return None, 0
return results, usage.total_tokens
except json.JSONDecodeError as e:
logger.error(f"Failed to parse JSON response: {e}")
logger.error(f"Response text: {text if 'text' in locals() else '(no response)'}")
return None, 0
except Exception as e:
logger.error(f"API call failed: {e}")
return None, 0
Using the Responses API (Alternative SDK Method)
If you are using the newer Responses API instead of the Chat Completions API, the approach is similar. The official documentation shows how to use tools with reasoning models. Here is an example adapted from the function calling guide:
from openai import OpenAI
import json
client = OpenAI()
# Define a simple tool
tools = [
{
"type": "function",
"name": "get_horoscope",
"description": "Get today's horoscope for an astrological sign.",
"parameters": {
"type": "object",
"properties": {
"sign": {
"type": "string",
"description": "An astrological sign like Taurus or Aquarius",
},
},
"required": ["sign"],
"additionalProperties": False,
},
"strict": True,
},
]
def get_horoscope(sign):
return f"{sign}: Next Tuesday you will befriend a baby otter."
# Create a running input list
input_list = [
{"role": "user", "content": "What is my horoscope? I am an Aquarius."}
]
# Prompt the model with tools defined
response = client.responses.create(
model="gpt-5.6",
tools=tools,
input=input_list,
reasoning={"effort": "minimal"}, # Add this to minimize reasoning
)
# Save function call outputs for subsequent requests
input_list += response.output
for item in response.output:
if item.type == "function_call":
if item.name == "get_horoscope":
sign = json.loads(item.arguments)["sign"]
horoscope = get_horoscope(sign)
input_list.append({
"type": "function_call_output",
"call_id": item.call_id,
"output": horoscope,
})
response = client.responses.create(
model="gpt-5.6",
instructions="Respond only with a horoscope generated by a tool.",
tools=tools,
input=input_list,
reasoning={"effort": "minimal"}, # Add this to minimize reasoning
)
print(response.output_text)
Note that the official documentation uses model "gpt-5.6" in its examples, but the same principles apply to "gpt-5-nano".
Common Pitfalls
1. Using reasoning=None Instead of a Dictionary
The most common mistake is passing reasoning=None or reasoning="minimal" as a string. The parameter must be a dictionary with an "effort" key. The correct format is:
reasoning={"effort": "minimal"}
Passing None is silently ignored by the API, and the model uses its default reasoning effort (which is "high" or "medium").
2. Trying to Use reasoning={"effort": "none"}
As confirmed by the Stack Overflow user, GPT-5-Nano does not accept "none" as a valid effort value. If you try it, the API may return an error or ignore the setting. Stick with "minimal".
3. Empty Responses Due to Token Limits
A community-reported issue on Stack Overflow: when using GPT-5-Nano with a batch of names, the response was empty because all completion tokens were consumed by reasoning. The user set max_completion_tokens=10000 but still got empty responses for 10 names. This happened because the model was using full reasoning (default effort). Switching to reasoning={"effort": "minimal"} solved the problem.
If you still get empty responses even with minimal effort, try increasing max_completion_tokens further or reducing the batch size. Each name in the batch adds to the reasoning overhead.
4. Confusing max_tokens with max_completion_tokens
For reasoning models like GPT-5-Nano, use max_completion_tokens to set the total output token limit (reasoning + visible content). For non-reasoning models like GPT-4o-mini, use max_tokens. Using the wrong parameter can cause errors or unexpected behavior.
5. Not Logging Token Details
If you are debugging empty responses, always log usage.completion_tokens_details to see how many tokens were used for reasoning vs. visible output. This information is critical for tuning your token limits. The Stack Overflow user included this logging in their original code, which helped them identify the problem.
if hasattr(usage, 'completion_tokens_details'):
logger.info(f"Completion tokens details: {usage.completion_tokens_details}")
6. Assuming All GPT-5 Models Behave the Same
The official documentation notes that only gpt-5.4 and later models support tool_search. Similarly, reasoning behavior may vary between GPT-5-Nano and other GPT-5 models. Always test with your specific model version.
7. Markdown Code Fences in Responses
When you ask the model to return JSON, it may wrap the output in markdown code fences (json ... ). The Stack Overflow user included code to strip these fences. This is a good practice to include in your parsing logic.
# Strip markdown code fences if present (```json ... ```)
text = text.strip()
if text.startswith('```'):
lines_list = text.split('\n')
if lines_list[0].startswith('```'):
lines_list = lines_list[1:]
if lines_list and lines_list[-1].strip() == '```':
lines_list = lines_list[:-1]
text = '\n'.join(lines_list)
Related Questions
How do I check how many reasoning tokens GPT-5-Nano used?
After making an API call, inspect the response.usage object. For reasoning models, the completion_tokens_details attribute contains a reasoning_tokens field. You can access it like this: response.usage.completion_tokens_details.reasoning_tokens. If the attribute does not exist, the model did not use any reasoning tokens (or you are using a non-reasoning model). This is useful for debugging and for tuning your token limits.
What is the difference between max_tokens and max_completion_tokens?
max_tokens is the legacy parameter that sets the maximum number of tokens the model can generate in the completion. It applies to non-reasoning models. max_completion_tokens is the newer parameter designed for reasoning models. It sets the total token budget for both reasoning and visible output. If you use max_completion_tokens on a non-reasoning model, the API may ignore it or return an error. Always use the parameter appropriate for your model type.
Can I use GPT-5-Nano for structured data extraction without reasoning?
Yes, but you must set reasoning={"effort": "minimal"} to reduce reasoning overhead. For simple tasks like extracting names, dates, or categories from text, minimal reasoning is usually sufficient. If you need absolutely no reasoning, you must switch to a non-reasoning model like GPT-4o-mini. However, GPT-5-Nano with minimal reasoning is faster and cheaper for high-volume batch processing.
Why does GPT-5-Nano return empty responses for large batches?
This is a community-reported issue on Stack Overflow. When processing a batch of names (e.g., 10 or more), the model may consume all its completion tokens on reasoning before generating any visible output. This happens because the default reasoning effort is high, and each name in the batch adds to the reasoning complexity. The fix is to set reasoning={"effort": "minimal"} and ensure max_completion_tokens is large enough (e.g., 10,000 or more). If the problem persists, reduce the batch size or switch to a non-reasoning model.
The #1 Chatgpt Newsletter
The most important chatgpt updates, guides, and fixes — one weekly email.
No spam, unsubscribe anytime. Privacy policy
Sources & References
This page was researched from 4 independent sources, combined and verified for completeness.
- 1.OpenAI Documentation — Function CallingOfficial documentation · primary source
- 2.OpenAI Documentation — EmbeddingsOfficial documentation
- 3.Turn off gpt-5-nano reasoningStack Overflow
- 4.Answer by Matt Pitkin (score 4, accepted)Stack Overflow
Keep exploring ChatGPT
ChatGPT resources
Latest error solutions
Skip the manual work
Ready-made AI workflows and automation templates — import and run instead of building from scratch.