ModelsQwenQwen3-32B
providerQwen /

Qwen3-32B

28 DZD in 98 DZD out/ 1M tokens
Service tier pricing, in DZD per 1M tokens
TierInputOutputCached input
PriorityLearn more
43.2151.2—
23.180.7—
Prices in DZD per 1M tokens

Qwen3-32B is the largest dense model in its generation, and the deliberate counterpart to a sparse sibling of almost identical total size. Where that model activates three billion parameters per token, this one activates all 32.8 billion — every layer, every weight, every time. Sixty-four layers with sixty-four query heads against eight key-value heads, and the same two-mode design as the rest of the family: reasoning and direct answering, switchable by writing a tag into the conversation. Tool calling is documented on both sides, which makes a two-speed agent a real option rather than a compromise.

Publicfp8JSONStreamingApache-2.0
Qwen3-32B
Capabilities
ToolsReasoningStructured output
ArchitectureTransformer
Context Window40K

Qwen3-32B

The largest dense model in its generation — and the deliberate opposite of its sparse sibling.


Dense, and Why That Is the Choice

Qwen3 shipped both architectures at almost the same size, which makes this the clearest comparison available between them.

Qwen3-32BQwen3-30B-A3B
Total parameters32.8B30.5B
Active per token32.8B3.3B
Layers6448
Query heads6432
KV heads84
Experts—128, 8 active

Nearly the same size on disk. Ten times the compute per token.

What dense means in practice. Every parameter participates in every token. No router deciding which experts see your input, no possibility that a token is sent to a specialist that handles it poorly, no variance in which part of the model answered.

What sparse buys instead is throughput — 3.3 billion parameters of work per token means far more requests per second on the same hardware.

Neither is better. They are different points on a curve, and the choice is workload-shaped:

Choose dense when per-request quality matters more than per-request cost, when consistency across inputs is the requirement, or when you want the model's full capacity applied to every token.

Choose sparse when volume is the constraint — classification, routing, extraction at scale, or an agent making hundreds of cheap calls.

And the layer count is the other half of the comparison. Sixty-four layers against forty-eight. Deeper as well as denser, which is where sequential reasoning lives.


Two Modes, One Model

The Qwen3 design, and it is the same at every size in the generation.

Soft switches written into the conversation:

CODE
/no_think

Which department owns this ticket?
CODE
/think

Prove whether this retry schedule can starve a single tenant under sustained load.

They work in a user prompt or in a system message — which matters, because placing them in the system message makes the mode a property of your application rather than something a user can change.

enable_thinking works as a parameter too, for when your code should decide.

Two cautions. Soft switches are text the model reads, so input sanitisation that rewrites user messages can strip them silently. And a switch in a user turn is visible to the user.


Tool Calling in Both Modes

Stated on the card, and uncommon:

precise integration with external tools in both thinking and unthinking modes

Most switchable models degrade tool use on the fast path. Reasoning is where a model works out which tool to call and with what arguments; remove it and the calls get sloppier.

Here both are documented capabilities, which makes a two-speed agent a design rather than a compromise — mechanical steps at full speed and full tool reliability, with reasoning invoked only for the step that needs a decision.


Architecture

Total parameters32.8B
Non-embedding31.2B
Layers64
Query heads64
Key-value heads8
Native context32,768
Extended context131,072 with YaRN
Languages100+

Sixty-four query heads against eight key-value heads — an 8:1 grouped-query ratio, cutting the key-value cache to an eighth of what full multi-head attention would need.

On a dense 64-layer model that ratio carries more weight than on a sparse one, because every layer builds a cache. Eight-to-one is what keeps a 32,768-token context affordable on a model where nothing is skipped.


32K Is Native. 128K Is Extension.

32,768 tokens is what the model was trained at.

131,072 comes from YaRN, applied at inference — a real capability, and a different thing from training at that length.

And static YaRN, which most serving frameworks implement, holds the scaling factor constant regardless of input length. Enabling it affects short prompts too.

The rule that follows: leave the extension off unless you actually serve long inputs. Turning it on permanently to handle occasional long documents degrades every short request in between.


Specifications

Model IDQwen/Qwen3-32B
TypeCausal language model, dense
Parameters32.8B (31.2B non-embedding)
Layers64
AttentionGQA — 64 Q heads, 8 KV heads
Native context32,768 tokens
Extended context131,072 with YaRN
ModesThinking, non-thinking
Mode controlenable_thinking, or /think · /no_think in a message
Languages100+
LicenceApache 2.0
Minimum transformers4.51.0
DeveloperQwen Team, Alibaba

Transformers below 4.51.0 raises KeyError: 'qwen3'.

Official builds cover the standard weights, FP8, and GGUF at q4_K_M, q5_0, q5_K_M, q6_K, and q8_0 — published by Qwen rather than converted by the community. AWQ and NVFP4 builds exist alongside.


Capabilities

CapabilityValue
input_typestext
output_typestext
image_inputNot supported
context_window40960
reasoningTwo modes — switchable
mode_switchParameter or in-prompt soft switch
streamingSupported
tool_callingSupported in both modes
structured_outputSupported
requires_promptYes — text prompt required

Recommended Sampling

From Qwen's reference command, and the values differ by mode.

ParameterThinkingNon-thinking
temperature0.60.7
top_p0.950.80
top_k2020
min_p00
presence_penalty1.51.5

Switching mode means switching sampling. Temperature and top-p both change, and leaving them at the other mode's values costs quality in a way that is hard to trace back to configuration.

The presence penalty at 1.5 is high, and it appears in Qwen's own command. On a reasoning model repetition inside a long trace is a real failure mode, and that value exists to suppress it.

Support varies by serving stack — top_k, min_p, and presence_penalty are not universally honoured through an OpenAI-compatible interface.


What the Reference Command Says About Budgets

Qwen's llama.cpp invocation is worth reading as advice rather than as a snippet:

CODE
-c 40960 -n 32768 --no-context-shift

A 40,960-token context with 32,768 available for generation — four fifths of the window reserved for output.

On a model whose native context is 32,768, that allocation says what a thinking model costs. The reasoning trace can consume the great majority of what you allocate.

Copy the proportion. A thinking-mode request needs most of its budget available for output; a budget sized for the answer produces a trace and nothing else.

--no-context-shift is the other half. Silently dropping old tokens to make room is worse than failing, because the model keeps answering from a history that quietly lost its beginning.


Using Qwen3-32B on DEVUP AI

Base URL: https://api.devupai.com/v1 · Model ID: Qwen/Qwen3-32B

Python

PYTHON
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="Qwen/Qwen3-32B",
    messages=[
        {"role": "user", "content": "Hello world!"}
    ],
    max_tokens=1024,
)

print(response.choices[0].message.content)

Node.js

JAVASCRIPT
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: "Qwen/Qwen3-32B",
    messages: [{ role: "user", content: "Hello world!" }],
    max_tokens: 1024,
  });

  console.log(response.choices[0].message.content);
}

main();

cURL

BASH
curl -X POST "https://api.devupai.com/v1/chat/completions" \
  -H "Authorization: Bearer $DEVUP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen3-32B",
    "messages": [
      { "role": "user", "content": "Hello world!" }
    ],
    "max_tokens": 1024
  }'

Switching Modes, With the Sampling

PYTHON
conversation = []

SETTINGS = {
    True:  {"temperature": 0.6, "top_p": 0.95, "max_tokens": 16384},
    False: {"temperature": 0.7, "top_p": 0.80, "max_tokens": 1024},
}


def ask(text: str, *, think: bool) -> str:
    """Send one turn at the requested mode, switching sampling and budget with it."""
    marker = "/think" if think else "/no_think"
    conversation.append({"role": "user", "content": f"{marker}\n\n{text}"})

    response = client.chat.completions.create(
        model="Qwen/Qwen3-32B",
        messages=conversation,
        extra_body={"top_k": 20, "min_p": 0, "presence_penalty": 1.5},
        **SETTINGS[think],
    )

    choice = response.choices[0]

    if choice.finish_reason == "length":
        trace = getattr(choice.message, "reasoning_content", "") or ""
        raise ValueError(
            f"hit the ceiling at {response.usage.completion_tokens:,} tokens "
            f"with {len(trace):,} characters of reasoning"
        )

    conversation.append(choice.message)
    return choice.message.content


ask("List the tables in this schema.", think=False)
ask("Which of them could produce a duplicate row under concurrent inserts, and why?", think=True)
ask("Give me the CREATE INDEX statement for the fix.", think=False)

The SETTINGS table is the part worth copying. Mode, sampling, and budget change together — one lookup rather than four parameters you might update inconsistently.

The finish_reason check earns its place on a 32,768-token native window. Reasoning shares the budget, and the window is modest by current standards.


Comparing Dense Against Sparse On Your Own Work

The experiment that settles the choice, using the two models in the same generation.

PYTHON
import time

DENSE = "Qwen/Qwen3-32B"
SPARSE = "Qwen/Qwen3-30B-A3B"


def measure(model: str, prompt: str, *, think: bool = False) -> tuple[str, float, int]:
    """Return the answer, wall-clock seconds, and completion tokens."""
    marker = "/think" if think else "/no_think"
    start = time.monotonic()

    response = client.chat.completions.create(
        model=model,
        messages=[{"role": "user", "content": f"{marker}\n\n{prompt}"}],
        temperature=0.6 if think else 0.7,
        top_p=0.95 if think else 0.80,
        max_tokens=16384 if think else 2048,
    )

    elapsed = time.monotonic() - start
    return response.choices[0].message.content, elapsed, response.usage.completion_tokens


for model in (DENSE, SPARSE):
    answer, seconds, tokens = measure(model, your_prompt)
    print(f"{model:<24} {seconds:>6.2f}s  {tokens:>6,} tokens  correct={check(answer)}")

Run it across twenty real prompts, not one. The dense model applies ten times the compute per token; whether that shows on your workload is an empirical question with a cheap answer.

Compare correctness first, then latency. If both are correct on most of your prompts, the sparse model is the better choice and the comparison saved you real money. If the dense model is correct where the sparse one is not, you now know where — and whether those cases matter.


A Two-Speed Agent

PYTHON
import json

TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "read_file",
            "description": "Read a file relative to the repository root.",
            "parameters": {
                "type": "object",
                "properties": {"path": {"type": "string"}},
                "required": ["path"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "run_tests",
            "description": "Run the test suite and return pass/fail counts with failure output.",
            "parameters": {"type": "object", "properties": {}},
        },
    },
]


def read_file(path: str) -> dict:
    """Replace with your real, sandboxed file access."""
    raise NotImplementedError


def run_tests() -> dict:
    """Replace with your real, sandboxed test runner."""
    raise NotImplementedError


HANDLERS = {"read_file": read_file, "run_tests": run_tests}

session = [
    {
        "role": "system",
        "content": (
            "/no_think\n\n"
            "You are working inside a git repository. Make the smallest change that fixes the "
            "problem and run the tests after each edit. When a failure is not obviously explained "
            "by your last change, say so and stop."
        ),
    },
    {"role": "user", "content": "The DZD invoice test fails on totals ending in .005. Fix it."},
]

CEILING = 30

for step in range(CEILING):
    response = client.chat.completions.create(
        model="Qwen/Qwen3-32B",
        messages=session,
        tools=TOOLS,
        temperature=0.7,
        top_p=0.80,
        max_tokens=4096,
    )

    message = response.choices[0].message
    session.append(message)

    if not message.tool_calls:
        print(message.content)
        break

    for call in message.tool_calls:
        handler = HANDLERS.get(call.function.name)
        if handler is None:
            outcome = {"error": "unknown tool", "name": call.function.name}
        else:
            try:
                outcome = handler(**json.loads(call.function.arguments or "{}"))
            except Exception as exc:
                outcome = {"error": type(exc).__name__, "detail": str(exc)}

        session.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(outcome)})
else:
    print(f"Stopped at the {CEILING}-step ceiling.")

The switch is in the system message, which makes non-thinking a property of the loop rather than something a tool result could accidentally change.

"Say so and stop" is the escape hatch. On a fast-path model, handing an unclear failure to a person beats guessing at it — and it is cheaper than switching the whole loop to thinking mode for one confusing step.

To escalate selectively, append a /think user turn when a step fails twice and let the model reason through that one before continuing.


Self-Hosting

Transformers 4.51.0 minimum, or the model class is not found.

Official formats: standard weights, FP8, and GGUF at five quantisations — from Qwen rather than the community, which is uncommon at this size.

A DFlash speculative decoding draft model is published for the FP8 build: five draft layers, 3.2 billion parameters, taking hidden states from five target layers and predicting a block of sixteen tokens in parallel. On a dense 32-billion-parameter model — where every token costs full compute — that acceleration matters more than it would on a sparse one.

Qwen-Agent is the recommended agent framework, and the reason is practical: it encapsulates tool-calling templates and parsers internally, removing the class of silent failure where a parser mismatch turns tool calls into prose.

Set --no-context-shift or its equivalent so truncation fails loudly.


Where It Fits

Quality-sensitive work at moderate volume, where full compute per token is worth its cost.

Consistency-critical applications, where every input gets the same model rather than whichever experts a router selected.

Two-speed agents, with tool calling documented on both sides.

Creative and conversational work — role-play, multi-turn dialogue, and human preference alignment are named strengths of this generation.

Multilingual work across 100+ languages, with translation called out.

Self-hosted deployment with official builds across three formats and a published speculative decoding draft.

Less suited to high-volume mechanical work, where the sparse sibling does the same job for a fraction of the compute — and to long-document processing beyond 32K without measuring the extension.


Practical Notes

Compare it against the sparse sibling on your own prompts before committing. The comparison is cheap and the difference in cost is not.

Change sampling when you change mode.

Reserve most of your budget for output in thinking mode.

Put soft switches in the system message when the mode is your decision rather than the user's.

Verify soft switches survive input sanitisation.

Leave YaRN off unless you serve long inputs.

Check finish_reason on thinking-mode requests — 32,768 native is tight.

If self-hosting, pair the FP8 build with the published DFlash draft.

Disable context shifting so truncation fails loudly.


Limitations

Native context is 32,768. The 131,072 figure comes from positional extension, and static YaRN degrades short prompts when left enabled.

Dense means full compute on every token. That is the design, and it is the reason this model costs more per request than its sparse sibling of nearly identical size.

Text only. No image, audio, or video input.

Soft switches are prompt text — vulnerable to input rewriting, and visible to the user in a user turn.

Thinking mode consumes output tokens against a window that is modest by current standards.

Sampling parameter support varies by serving stack.

Transformers 4.51.0 or later is required for self-hosting.

Thirty-two billion parameters. The largest dense model in this generation, and smaller than the sparse flagships that sit above it.

Reasoning traces are working notes. Unpolished, sometimes exploring abandoned branches, and occasionally contradicting the answer that follows.