Qwen's Default System Prompt When None Is Provided
9 min read · updated August 11, 2026
Send Qwen2.5 a message list with no system entry and one appears anyway. It is not the API adding it and it is not the model imagining it — it is a literal string in the Jinja template shipped with the tokeniser, and you can read it in the repository.
The string
For the Qwen2 and Qwen2.5 instruct checkpoints, the template inserts:
You are Qwen, created by Alibaba Cloud. You are a helpful assistant.
Rendered into the prompt, that is a complete system turn ahead of your first user message:
<|im_start|>system You are Qwen, created by Alibaba Cloud. You are a helpful assistant.<|im_end|> <|im_start|>user What is the capital of Portugal?<|im_end|> <|im_start|>assistant
Roughly seventeen tokens, on every request that omits a system message. Not a large cost, but a constant one, and it is present in the token count you are billed for whether or not you knew about it.
Where it comes from
The insertion is done by the chat template, which lives in the chat_template field of tokenizer_config.json in the model repository. It is Jinja, and the relevant clause reads, in effect: if the first message is a system message, render it; otherwise render this fixed string as one.
Reading the template rather than trusting any description of it is a two-line habit worth having, because fine-tunes change this string and the description will not have been updated:
from transformers import AutoTokenizer
tok = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-7B-Instruct")
print(tok.chat_template)Because it lives in the template, the behaviour follows the template rather than the model. Serve the same weights through a stack that builds prompts its own way and there is no default system prompt at all; use apply_chat_template and there is. That is the whole mechanism, and it explains why two deployments of the same checkpoint can behave subtly differently on requests with no system message.
Qwen3 stopped inserting it
The Qwen3 chat template does not add a default system message. Send a message list with only a user turn and the rendered prompt begins with the user turn.
This is a deliberate change and it has a consequence people trip over when they port a working Qwen2.5 setup forward: prompts that implicitly relied on the assistant persona being established now have no persona at all. The model still behaves as an assistant — that is what post-training gave it — but the specific self-description is gone, and if you were, for instance, relying on it to answer “who are you” consistently, that behaviour is no longer anchored to anything.
The Qwen3 template does other work in that position instead, notably the empty <think> block it pre-fills when thinking is disabled. That mechanism is covered in the enable_thinking page. The useful generalisation is that a chat template is a small program that changes between generations, and diffing it is part of migrating between them.
The hosted API is a third answer
Everything above is about a template file you can open. Call Qwen through Alibaba’s hosted API instead and the templating happens on their side of the connection: you send a message list, the service renders it, and the rendered prompt is not in the response. Whether a default system message was injected — and if so, what it said — is not observable from the client.
This is not a criticism of the design; every hosted chat API works this way. It is a caution about inference. A hosted model that answers “I am Qwen, created by Alibaba Cloud” is not evidence that the string above was injected, because post-training alone makes that a likely answer. And a hosted model that does not say it is not evidence that nothing was injected. You cannot read the prompt off the behaviour.
What you can do is control the variable. Send an explicit system message on every request. It overrides whatever default exists in every implementation of this template, it costs you nothing beyond its own tokens, and it makes the behaviour identical across the open weights, the native endpoint and the OpenAI-compatible one. That is worth more than knowing the default, because it is the same answer regardless of which of the three you are on and regardless of whether Alibaba changes one of them.
What it changes
A short generic system prompt is not a neutral prefix, and there are three effects worth knowing about.
- Identity questions get a stable answer. Ask an unprompted Qwen2.5 who it is and the answer is anchored by the string rather than by whatever the training data happened to make likely. This is exactly the behaviour that disappears in Qwen3, and it is why a hosted deployment answering “I am Qwen” is evidence about the serving stack, not about the weights.
- The model is placed in the assistant distribution. “You are a helpful assistant” is not a magic phrase, but it does condition the model toward the register its instruction tuning used most heavily. Removing it entirely, rather than replacing it, measurably shifts tone toward the base distribution.
- Evaluations become non-comparable. If your harness sends no system message and your production code sends one, you are not evaluating the deployed configuration. This is the most common way a benchmark result stops predicting production behaviour, and it is invisible unless you print the rendered prompt.
Overriding and removing it
Overriding is trivial: include a system message and the template renders yours instead. There is no merging, no appending, and no residue of the default.
messages = [
{"role": "system", "content": "You are a terse assistant. Answer in one sentence."},
{"role": "user", "content": "What is the capital of Portugal?"},
]
print(tok.apply_chat_template(messages, tokenize=False, add_generation_prompt=True))Removing it entirely is the harder case, because the template offers no way to say “no system turn”. Passing an empty string still produces a system turn with empty content, which is not the same thing as no turn — it is four tokens of structure with nothing inside, and the model has seen very little training data shaped like that. If you genuinely need no system turn on a Qwen2.5 checkpoint, you have to supply your own template or build the prompt yourself, and the ChatML structure page has the exact byte sequence to reproduce.
In practice the better move is almost always to override rather than remove. Even a one-line system prompt that says what the model is for is worth more than the seventeen tokens it costs, and it makes the behaviour a decision recorded in your code rather than a default inherited from a template file you have never opened. Other families take a different view of the same question — Grok, for instance, ships a persona rather than a generic assistant string, which is covered in the Grok default persona page.