Views
No views yet
Qwen/Qwen3.8-27B and quantized variants like unsloth/Qwen3.8-27B-NVFP4). The goal is reliable agentic tool calling on vLLM without drifting away from the format the model was trained on.| File | Use it when |
|---|---|
qwen3.8-enhanced.jinja | The recommended baseline. Official Qwen 3.8 template plus tool-calling and history-rendering fixes. |
qwen3.8-enhanced-extra.jinja | Everything in the baseline, plus extra tolerance for messy client-side history (malformed think tags, alternate field names). Renders byte-identical prompts for well-formed conversations. |
⚠️ vLLM only. These templates rely on thefrom_jsonfilter, which vLLM provides but plain Jinja2 and minijinja (llama.cpp, LM Studio, MLX) don't. If you need something engine-agnostic, use froggeric/Qwen-Fixed-Chat-Templates instead.
1vllm serve unsloth/Qwen3.8-27B-NVFP4 \
2 --chat-template qwen3.8-enhanced.jinja \
3 --enable-auto-tool-choice \
4 --tool-call-parser qwen3_xml \
5 --reasoning-parser qwen3--tool-call-parser qwen3_xml matches the XML format these templates emit (<tool_call> → <function=name> → <parameter=x>). Stuck on an older vLLM build? Fall back to qwen3_coder.--reasoning-parser qwen3 is required. The generation prompt pre-fills <think>\n, so the model's output starts mid-thought with no opening tag. This parser handles that case and splits reasoning_content from content, which is also what the template needs fed back to it on later turns.qwen3_xml leans on your tool JSON schemas for type coercion, so keep those parameters schemas honest. Loose schemas mean arguments come back as strings.qwen3.6-enhanced.jinja)tool_call.arguments is a mapping and dies with Can only get item pairs from a mapping when an OpenAI-style client echoes back stringified arguments, which most of them do. JSON strings are parsed here into proper <parameter> blocks, nested objects included, so multi-turn history always re-renders in the trained format.</think> closure. If echoed history contains a dangling <think> before a <tool_call>, the closing tag gets inserted where it belongs. Tool calls never end up trapped inside reasoning.<think>...</think> extraction. Some clients stuff reasoning into message.content instead of reasoning_content. Rather than double-wrapping it, the template pulls it out and re-renders it canonically.tojson(ensure_ascii=False) for tool definitions and argument values, so CJK text stays readable instead of turning into \uXXXX escapes.<IMPORTANT> block rather than replacing it: close </think> before tool calls, prefer tools over answering from memory, reuse ids with update_* tools, keep user-provided strings verbatim, write valid JSON for object and array parameters. There's a worked follow-up-update example too.developer role support. Leading system and developer messages are accepted and merged into a single system block. Harnesses like Codex won't work without this.reasoning_effort: "high" aliased to xhigh instead of throwing. OpenAI proxies routinely send "high".reasoning_effort steering (xhigh default, medium, low) with the official instruction wording, word for word.preserve_thinking defaults to true. Qwen 3.8 was trained with retained reasoning context; stripping it by default would fight the model.</tool_response><|im_end|> spacing and scalar argument rendering (true, null, 5 via tojson; strings verbatim).<think> blocks, even when reasoning is empty. That's the trained format, empty or not.-extra variant adds<thinking>...</thinking>, </ think>, </think >, content that starts with </think>, and bare reasoning followed by </think>. These are the artifacts you get when a client echoes raw output from the prefilled <think>\n generation prompt. Every variant gets normalized back to a clean <think>...</think> on re-render.message.thinking accepted as an alias of message.reasoning_content. A handful of clients use it; reasoning_content still wins when both are present.preserve_reasoning accepted as an alias of preserve_thinking, matching llama.cpp's --reasoning-preserve naming. Takes precedence if both are passed.error: 0 trips it) and puts the whole conversation off-distribution.max_tool_arg_chars / max_tool_response_chars). History truncation belongs in the client, where it can happen without silently corrupting replayed turns.<function> blocks teaches the model to imitate malformed history. These templates parse instead.<think> blocks. The official format always emits the wrapper for preserved turns, so these templates do too.tool_call_format="json". Qwen 3.8 is trained on the XML format. Use qwen3_xml.chat_template_kwargs (vLLM) or apply_chat_template(...):| Kwarg | Default | Description |
|---|---|---|
enable_thinking | true | false pre-fills <think>\n\n</think>\n\n to skip reasoning. |
reasoning_effort | "xhigh" | "xhigh", "medium", "low"; "high" is aliased to "xhigh". Injects the official steering instruction into the system block. |
preserve_thinking | true | false strips <think> blocks from assistant turns before the last real user query (saves tokens, breaks prefix-cache continuity for those turns). |
preserve_reasoning | n/a | (extra only) Alias of preserve_thinking; takes precedence if both are set. |
add_vision_id | false | Prefixes Picture N: / Video N: labels to vision inputs. |
| Role | Author |
|---|---|
| Qwen 3.8 models & official template | Alibaba Cloud (Qwen team) |
| Original enhanced-template lineage (3.5/3.6) | allanchan339 |
| Developer-role / effort-alias / tool-name fixes | Unsloth |
Robustness ideas adapted in the -extra variant | froggeric |
| Merge, testing & maintenance | nrrso |