How to Prompt OpenAI's GPT Models
A practical, docs-grounded guide to prompting GPT-5.x: role hierarchy, structured outputs, tool calling, and reasoning-model differences.
GPT models are not one thing. A GPT-5.x flagship at low reasoning effort behaves like a fast instruction-follower; the same model at high effort behaves like a different animal. Most bad GPT prompts come from treating every request the same way — vague system messages, chain-of-thought scripts fed to a model that doesn't need them, JSON hoped for
instead of enforced. This guide covers what's specific to OpenAI's models, grounded in their own docs. It's part of a broader model-by-model series; for the underlying theory, start with the complete guide to prompt engineering.
The Current GPT Lineup, and How to Choose
As of this writing, OpenAI's frontier line is the GPT-5.x family. The naming has shifted across point releases — GPT-5 launched with Auto/Fast/Thinking (plus Pro) variants, GPT-5.1 introduced the Instant
label (GPT-5.1 Instant / GPT-5.1 Thinking), and later point releases kept mixing and matching (GPT-5.3 Instant paired with GPT-5.4 Thinking/Pro). The current generation, GPT-5.6, collapses that churn into a cleaner split: three model tiers (frontier capability, balanced mid-tier, and cost-efficient high-volume) crossed with a reasoning.effort parameter — none, low, medium, high, xhigh, or max — that controls how hard any tier thinks on a given request. A separate reasoning.mode: "pro" setting spends extra compute working a request multiple ways before returning one final answer, for the hardest problems.
That's the practical mental model regardless of exact version number by the time you read this: pick a tier for raw capability, pick an effort level for how much it should think. Two implications:
- Don't reach for a
smarter
model tier when the actual problem is that you set effort too low for a genuinely hard task, or too high for a simple one (which just burns latency and tokens). - OpenAI has been retiring the standalone o-series reasoning models (o1, o3, o4-mini) in favor of this unified GPT-5.x approach. If you're maintaining older code that hardcodes
o3oro4-mini, plan a migration — those models are on deprecation timelines.
Always check the live model list before committing to a specific ID in production code; point releases move fast. See OpenAI's model guidance and model index for what's current.
The Message Hierarchy: System, Developer, and User
OpenAI's prompt engineering guide defines an explicit priority order for message roles, and it's not symmetric — instructions don't just add up,
they override in one direction only. Developer messages (the API's modern name for what used to be the system role for o1-and-newer models — treat system as legacy going forward) carry the highest authority you control. User messages sit below that. Assistant messages (the model's own prior turns) carry the least authority. A user cannot instruct the model to ignore a developer-level rule; that's by design, not a bug to route around.
The functional distinction: developer messages are like a function definition — they set rules, persona, and business logic. User messages are like arguments to that function — the specific task or data the rules get applied to. Practically:
- Put anything that must hold true regardless of what the end user types — safety constraints, output format, persona, tool-use policy — in the developer/system message.
- Put the actual task, question, or user-supplied content in the user message.
- Use Markdown headers and lists, or XML-style tags, to give the model clear structural boundaries inside longer developer messages. GPT models parse structure reliably and it reduces instructions bleeding into each other.
developer:
# Identity
You are a support-ticket triage assistant for a B2B SaaS product.
# Rules
- Never promise refunds or SLA commitments.
- Classify every ticket into exactly one of: bug, billing, feature-request, other.
- If the ticket is ambiguous, ask one clarifying question instead of guessing.
# Output format
Return the classification and a one-sentence justification.
user:
"We were charged twice this month and the dashboard still shows the
old plan — can someone look at this?"
Note that if you're using the Responses API's separate instructions parameter, it takes priority over anything in the input/prompt, but only for that single response — it doesn't persist across turns chained with previous_response_id. Put anything that needs to survive a multi-turn conversation into an actual message instead.
Structured Outputs: Get Reliable JSON, Not Best-Effort JSON
OpenAI's structured outputs guide distinguishes two things people often conflate. JSON mode guarantees the output parses as valid JSON — it does not guarantee it matches any particular shape. Structured Outputs, using type: "json_schema" with strict: true, constrains generation so the response adheres to your exact schema — required fields, enums, nesting, all of it. Only the strict, schema-based mode gives you adherence guarantees; treat JSON mode as legacy unless you're on a model that predates Structured Outputs support (which starts at gpt-4o-mini and later).
{
"text": {
"format": {
"type": "json_schema",
"strict": true,
"schema": {
"type": "object",
"properties": {
"classification": {
"type": "string",
"enum": ["bug", "billing", "feature-request", "other"]
},
"justification": { "type": "string" }
},
"required": ["classification", "justification"],
"additionalProperties": false
}
}
}
}
Strict mode has real constraints: every object needs additionalProperties: false, every field in properties must be listed as required (model optional fields with a nullable type instead of omitting them), and the SDKs let you pass a Pydantic model or Zod schema directly rather than hand-writing JSON Schema. For the general theory of why constrained decoding beats ask nicely for JSON,
see getting reliable structured output from LLMs.
Tool and Function Calling
Function calling uses the same strict, schema-based machinery under the hood. A tool definition needs type: "function", a name, a description, and a parameters JSON Schema object — plus strict: true for the same adherence guarantee applied to the arguments the model generates.
Per OpenAI's function calling guide, the description field does more work than people give it credit for. Write it like documentation for a new engineer, not a label: state exactly when the tool should and shouldn't be called, and put policy about when to use which tool in the developer message rather than assuming the model will infer it from names alone. Other concrete guidance:
- Design parameters so invalid states are unrepresentable — use enums instead of free-text strings wherever the value space is known.
- Keep the active toolset small (OpenAI suggests under ~20 tools) for best selection accuracy; for larger toolsets, use tool search rather than dumping everything into context.
- Include edge cases and examples in the description when you see the model repeatedly mis-calling a tool — it's a prompting problem, not just a schema problem.
Prompting Reasoning Models Differently
This is where people most often carry over bad habits from non-reasoning GPT prompting. OpenAI's own framing: a non-reasoning GPT model is like a junior coworker
— it does best with explicit, spelled-out instructions and worked examples. A reasoning model does not want that. A scripted chain-of-thought (first do X, then check Y, then do Z
) can constrain it to a worse path than it would have found on its own.
Instead, per OpenAI's reasoning guide:
- State the goal, the hard constraints, and the required output format. Let the model plan the intermediate steps.
- For agentic or research-style tasks, define what
done
looks like and how the model should verify its own work — that's more valuable than telling it how to get there. - Use
reasoning.effortas a dial, not a fix: start atmedium, move up for genuinely hard, high-stakes tasks and down for latency-sensitive, low-ambiguity ones. Don't crank effort tomaxto paper over a vague prompt — fix the prompt. - Budget context accordingly. Reasoning tokens count against your output budget; leave real headroom (OpenAI suggests at least ~25,000 tokens) when experimenting with harder problems.
For the general pattern across reasoning models from multiple vendors, see how to prompt reasoning models without getting in their way.
Common GPT-Specific Mistakes
- Over-scripting reasoning models. Feeding step-by-step chain-of-thought to a high-effort GPT-5.x request fights the model's own planning instead of helping it.
- Everything in the user message. Stable rules belong in the developer/system message, where they can't be casually overridden by whatever the end user types next.
- Trusting JSON mode for anything that gets parsed downstream. If a schema violation would break your code, use Structured Outputs with
strict: true, not JSON mode. - Vague or overlapping tool descriptions. If two tools could plausibly apply to the same request, the model will sometimes pick wrong — disambiguate in the description and in developer-message policy, not after the fact.
- Ignoring
reasoning_effortandverbosity. Defaults are reasonable but generic; a lightweight extraction task run at default effort wastes latency, and a genuinely hard task run atminimal/loweffort will underperform. - Coding against models that are being retired. o3, o4-mini, and older GPT-4-era IDs are on deprecation paths — check the model list before you ship, not after a shutdown notice.
For the Anthropic-side equivalent, see how to prompt Claude Opus, Sonnet, and Haiku. If you're building a prompting practice rather than a one-off prompt, the complete guide to prompt engineering in 2026 and the top-models hub are the place to keep going.