gpt-oss-20b
| Tier | Input | Output | Cached input |
|---|---|---|---|
PriorityLearn more | 16.2 | 75.6 | — |
FlexLearn more | 8.7 | 40.4 | — |
gpt-oss-20b is OpenAI's smaller open-weight reasoning model, and the one that fits on hardware you already own — 21 billion parameters with 3.6 billion active per token, loading in about 16 GB of memory. Reasoning effort is set in the system prompt as plain text rather than through a parameter, and the full chain of thought comes back unredacted, which makes debugging a model's mistakes possible in a way closed reasoning models do not allow. It ships under Apache 2.0 with no copyleft or patent conditions, is designed to be fine-tuned, and carries built-in support for browsing, Python execution, and function calling.

gpt-oss-20b
Twenty-one billion parameters. Three point six active. Sixteen gigabytes of memory. Apache 2.0.
OpenAI's smaller open-weight reasoning model, built for low latency, local deployment, and specialised use.
The Harmony Format Is Mandatory
Read this first, because ignoring it produces bad output rather than an error.
This model was trained exclusively on OpenAI's harmony response format, and the model card states the consequence three separate times: used without it, the model will not work correctly.
Not "works less well." Not "may degrade." Will not work correctly.
Through an API this is handled for you — the serving layer applies the format. It matters when you self-host:
Using the Transformers chat template applies harmony automatically.
Calling model.generate directly does not. You apply the format yourself, either through the
chat template or through OpenAI's openai-harmony package.
That distinction catches people who reach for the lowest-level generation call out of habit. The model runs, produces fluent text, and gets things subtly wrong — which is harder to diagnose than a crash.
Reasoning Effort Lives in the System Prompt
Unusual, and the most distinctive integration detail on this model.
Every other reasoning model in this catalogue takes effort as a request parameter. This one takes it as text in the system message:
messages = [
{"role": "system", "content": "Reasoning: high"},
{"role": "user", "content": "Explain why eigenvalues matter."},
]Three levels: low, medium, high.
Two consequences follow.
A request that sets reasoning_effort as a parameter and expects it to apply here is setting
something the model never reads. Depending on the serving layer it is ignored, rejected, or
translated — worth confirming which on your path.
And because effort is prompt text, it is composable with everything else in the system message. Role, constraints, and deliberation depth all live in one place.
The Chain of Thought Comes Back Whole
OpenAI ships this model with full, unredacted chain of thought, and names the reason: easier debugging and increased trust in output.
That is a genuine capability difference from closed reasoning models, where the trace is summarised or withheld. When this model reaches a wrong answer you can read exactly where it went wrong.
And OpenAI attaches a condition, stated plainly on the card: the chain of thought is not intended to be shown to end users.
Treat it as diagnostic output. Log it, inspect it, use it to fix prompts. Do not render it in a product interface — it is a working draft, it can explore abandoned branches, and it can contradict the answer that follows it.
Architecture
| Total parameters | 21B |
| Active per token | 3.6B |
| Experts | 32, top-4 routing |
| Quantisation | MXFP4 on MoE expert weights |
| Precision elsewhere | BF16 — attention, router, embeddings |
| Context extension | YaRN RoPE scaling, factor 32 — 4K native to 131K |
| Memory to load | ~16 GB |
The quantisation is selective, and that is the point. MXFP4 applies to the expert layers, which hold most of the parameters and are the least sensitive to precision loss. Attention, the router, and the embeddings stay in BF16 — the components where a rounding error propagates through everything downstream.
All published evaluations were run at this quantisation. That is worth noting because it is uncommon: many models are evaluated at full precision and shipped quantised, leaving you to guess what the quantisation cost. Here the benchmark numbers and the weights you download are the same configuration.
The 131K context comes from YaRN scaling, not from native long-context training — a factor-32 extension of a 4K base. Long-context behaviour at the far end of that window is worth measuring on your own data rather than assuming.
Specifications
| Model ID | openai/gpt-oss-20b |
| Context window | 131,072 tokens |
| Reasoning effort | low, medium, high — set in the system prompt |
| Chat format | Harmony — required |
| Input → output | Text → text |
| Fine-tuning | Supported |
| Licence | Apache 2.0 |
| Released | August 2025 |
Apache 2.0 with no copyleft and no patent conditions. OpenAI names commercial deployment, custom fine-tuning, and experimentation as intended uses. For an open-weight model from a lab whose other products are entirely closed, that licence is the release's most consequential property.
Capabilities
| Capability | Value |
|---|---|
input_types | text |
output_types | text |
image_input | Not supported |
context_window | 131072 |
reasoning | low, medium, high — via system prompt |
reasoning_visibility | Full chain of thought returned |
chat_format | Harmony — required |
streaming | Supported |
tool_calling | Supported |
structured_output | Supported |
built_in_tools | Browser, Python, function calling |
fine_tuning | Supported |
requires_prompt | Yes — text prompt required |
Built-In Tools
The model ships with native support for browsing, Python execution, and function calling — trained capabilities rather than prompting patterns layered on afterwards.
Through the responses interface these are available directly, including MCP. For self-hosted deployment the Python sandbox requires additional setup: Docker, or an explicit opt-in to running execution without one.
That opt-in flag is named dangerously_use_uv, which is as clear a warning as a parameter name gets.
Python execution without a sandbox means the model can run arbitrary code with your process's
permissions. Use the container.
Using gpt-oss-20b on DEVUP AI
Base URL: https://api.devupai.com/v1 · Model ID: openai/gpt-oss-20b
Python
Note where the reasoning level goes.
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["DEVUP_API_KEY"],
base_url="https://api.devupai.com/v1",
)
response = client.chat.completions.create(
model="openai/gpt-oss-20b",
messages=[
{"role": "system", "content": "Reasoning: high"},
{"role": "user", "content": "Explain why eigenvalues matter."},
],
max_tokens=4096,
)
print(response.choices[0].message.content)Node.js
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY,
});
async function main() {
const response = await client.chat.completions.create({
model: "openai/gpt-oss-20b",
messages: [
{ role: "system", content: "Reasoning: medium" },
{ role: "user", content: "Hello world!" },
],
max_tokens: 1024,
});
console.log(response.choices[0].message.content);
}
main();cURL
curl -X POST "https://api.devupai.com/v1/chat/completions" \
-H "Authorization: Bearer $DEVUP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-oss-20b",
"messages": [
{ "role": "system", "content": "Reasoning: low" },
{ "role": "user", "content": "Hello world!" }
],
"max_tokens": 1024
}'Combining Effort With Instructions
Because effort is prompt text, it composes with the rest of your system message rather than sitting beside it in a parameter object.
SYSTEM = (
"Reasoning: high\n\n"
"You are reviewing a database migration. Report only changes that could lose data or "
"cause downtime. For each, give the statement, the risk, and the smallest safe correction. "
"If the plan lacks the information needed to judge something, say so rather than assuming."
)
response = client.chat.completions.create(
model="openai/gpt-oss-20b",
messages=[
{"role": "system", "content": SYSTEM},
{"role": "user", "content": migration_plan},
],
max_tokens=8192,
)Keep the reasoning directive on its own line at the top. It is a control instruction, not part of the role description, and separating them makes both easier to change.
Reading the Trace
message = response.choices[0].message
trace = getattr(message, "reasoning_content", None)
if trace:
# Diagnostic output. Log it; do not render it.
logger.debug("chain of thought: %d characters", len(trace))
print(message.content)OpenAI's guidance is explicit that this content is not for end users. Logging it is exactly what it is for — when an answer is wrong, the trace shows you whether the model misread the prompt, reasoned from a bad premise, or reasoned correctly to a wrong conclusion. Those three failures need different fixes, and without the trace they look identical.
Fine-Tuning
Named by OpenAI as an intended use, and the practical argument for choosing an open model at this size.
Prompting adapts a model without training it, and costs input tokens on every call. A long system prompt with examples, repeated across a million requests, is a permanent tax. Fine-tuning moves that behaviour into the weights — it comes free thereafter, and the prompt shrinks to the actual input.
Worth it when the task is narrow, its definition is stable, you have a few hundred to a few thousand good examples, and volume is high enough that per-call savings compound.
Not worth it when the definition changes often, the examples are few, or a larger model simply solves the problem.
At 21 billion parameters with 3.6 billion active, this model sits in the range where fine-tuning is affordable on accessible hardware — which is not true of most models with comparable reasoning capability.
Running It Yourself
The design point. Sixteen gigabytes of memory covers it.
Hardware: data-centre GPUs, consumer cards with sufficient VRAM, AMD and Intel accelerators. Unusually broad support for a model of this capability, and a direct consequence of the selective MXFP4 quantisation.
The format requirement applies here. Use the chat template or the harmony package; do not call generation directly without applying the format.
Sandbox the Python tool. The flag that disables the container says what it is in its own name.
Reference implementation and quick-start instructions live in the project repository.
Where It Fits
Local and on-device reasoning, where the model has to live next to the application rather than behind a network call.
Latency-sensitive paths, where 3.6 billion active parameters and a low effort setting keep response time short.
Specialised deployments built by fine-tuning rather than prompting.
Anywhere the data cannot leave your infrastructure. Open weights and a permissive licence make this workable in a way no closed model is at any price.
Debugging-heavy work, where reading the model's actual reasoning is worth more than a marginally better answer from something opaque.
Less suited to the hardest reasoning problems — the larger model in this pair exists for those — and to anything needing image input, which this model does not accept.
Practical Notes
Put Reasoning: low|medium|high in the system prompt. A parameter of the same name is not what this
model reads.
Never show the chain of thought to users. OpenAI says so directly.
Log the trace instead. It is the fastest route from a wrong answer to the reason for it.
Do not bypass the harmony format when self-hosting. Wrong output is harder to notice than no output.
Measure long-context behaviour on your own data — 131K comes from RoPE scaling rather than native training.
Sandbox Python execution.
Consider fine-tuning if your task is narrow, stable, and high-volume.
Limitations
Harmony format is required. Without it the model does not work correctly, and the failure is silent.
Reasoning effort is prompt text, not a parameter. Integrations written against a parameter control it nothing here.
The chain of thought is not for display. OpenAI states this explicitly; it can be unpolished and can contradict the final answer.
Text only. No image, audio, or video input, and no image generation.
131K context comes from YaRN scaling at factor 32 over a 4K base — verify behaviour at the far end rather than assuming.
The smaller of two. A larger sibling exists for harder reasoning at production scale; this one trades capability for latency and footprint.
Python execution needs a sandbox. The flag that removes it names the risk.
Standard foundation-model limitations apply. Ground factual work and validate anything that will act on a system of record.