qwen3.6-35b-a3b 使用社区增强模板,拒绝 agent 死循环,获得中文思维链,动态开关思考模式
我用的是 Qwen3.6-35B-A3B-APEX-MTP-I-Quality.gguf 模型
用的 agent 是 QwenPaw 。在执行任务时,偶尔陷入死循环,无限调用同一个工具,无限失败,直到工具达到调用上限。
改模板的大佬,发现qwen的官方模板会修改过早的历史记录,会导致 kv缓存失效,出现极大的卡顿(重新prefill)。然后,发现官方模板会修改历史后,留下大量的 空思考块堆积在一起,会导致模型出现严重降智的现象。
同时,增加新的功能:
支持 developer 角色开发;
支持 <|think_off|> / <|think_on|> 命令动态开关思考模式;
同时,开关思考模式时,模型完全不会看到这个开关命令,避免污染模型上下文。
还有更稳定工具调用,内调用工具时自动预先闭合思考块,等等等等优化。
实测,更换模板后,测试了1天,没有出现之前容易遇到的 失败工具调用 死循环的现象。
支持中文思考链,是我在 开始后,强行加了一个 好, 字段。诱导中文思维链成功,98%以上概率出现中文思考链,并且中文思考链,平均每次回复能明显节省 20% 的 token (中文思考链回复1900 token vs 英文思考链回复 2400 token)
我当前使用的模板,微微改至 fakezeta 大佬的合并版,增加了中文思考链诱导,https://gist.github.com/fakezeta/9e8e039c60332fcb143c6e805558afe0




我的 qwen3.6 启动命令,额外加入了思考长度的限制,如果思考超过4096个token,其思考内容一般是没有什么价值了,与Deepseek 类模型不同,qwen3.6 的思维链虽然能推很长,但是前一小撮是有用的,后面都是不断重复自我校验,浪费token的。
$env:LLAMA_CHAT_TEMPLATE_KWARGS='{"preserve_thinking":true}'
llama-server.exe --model Qwen3.6-35B-A3B-APEX-MTP-I-Quality.gguf --mmproj mmproj-F16.gguf --top-p 0.95 --min-p 0.00 --top-k 30 --reasoning on --ctx-size 262144 --temp 0.6 --parallel 1 --reasoning-budget 4096 --reasoning-budget-message "...思考过久,提前回复" --spec-type draft-mtp --spec-draft-n-max 3 -fa on -np 1 --kv-unified --jinja --chat-template-file qwen3.6_merged_template_fakezeta.jinja --reasoning-format deepseek
取自 https://gist.github.com/fakezeta/9e8e039c60332fcb143c6e805558afe0 日期为 2026/5/19
我的qwen3.6 用的 jinja 模板全文,请保存到 qwen3.6_merged_template_fakezeta.jinja 文件中
{# =========================
Merged Qwen Multimodal Chat Template from
- https://github.com/allanchan339/vLLM-Qwen3-3.5-3.6-chat-template-fix
- https://huggingface.co/froggeric/Qwen-Fixed-Chat-Templates
Features:
- developer role supported (from froggeric)
- <|think_on|> / <|think_off|> toggles (from froggeric)
- Historical reasoning HIDDEN by default (from allanchan339)
- String-form tool arguments parsed as JSON (from allanchan339)
- Non-ASCII escaped in tools/args JSON (from froggeric)
- </thinking> recognized as well as </think> (from froggeric)
- Auto-close <think> before <tool_call> (from allanchan339)
- Same vision / tool_response structure
- Compact tool signatures (from froggeric)
- last_user_index historical-reasoning gating (from allanchan339)
========================= #}
{# Minja-compatible hybrid Qwen template
Trade-offs vs full Jinja2 version:
- String-form tool arguments are emitted verbatim (no JSON re-parse)
- <think> auto-close uses simple replace, not positional insertion
- Reasoning extraction uses split + trim instead of lstrip/rstrip with arg
#}
{%- set image_count = namespace(value=0) -%}
{%- set video_count = namespace(value=0) -%}
{%- macro render_tool_parameter(args_name, args_value) -%}
{{- '<parameter=' ~ args_name ~ '>\n' -}}
{%- if args_value is mapping or (args_value is iterable and args_value is not string) -%}
{{- args_value | tojson -}}
{%- else -%}
{{- args_value | string -}}
{%- endif -%}
{{- '\n</parameter>\n' -}}
{%- endmacro -%}
{%- macro render_tool_arguments(arguments) -%}
{%- if arguments is mapping -%}
{%- for args_name, args_value in arguments.items() -%}
{{- render_tool_parameter(args_name, args_value) -}}
{%- endfor -%}
{%- elif arguments is string -%}
{%- set trimmed = arguments | trim -%}
{%- if trimmed -%}
{{- trimmed -}}
{%- if not trimmed.endswith('\n') -%}{{- '\n' -}}{%- endif -%}
{%- endif -%}
{%- endif -%}
{%- endmacro -%}
{%- macro render_tool_signature(tool) -%}
{%- set fn = tool.function if tool.function is defined else tool -%}
{%- set props = {} -%}
{%- set req = [] -%}
{%- if fn.parameters is defined and fn.parameters is mapping -%}
{%- if fn.parameters.properties is defined -%}
{%- set props = fn.parameters.properties -%}
{%- endif -%}
{%- if fn.parameters.required is defined -%}
{%- set req = fn.parameters.required -%}
{%- endif -%}
{%- endif -%}
{%- set ns_p = namespace(sig='') -%}
{%- for pname in props -%}
{%- set pdef = props[pname] -%}
{%- set ptype = 'any' -%}
{%- if pdef.type is defined -%}
{%- if pdef.enum is defined and pdef.enum is iterable and pdef.enum is not string and pdef.enum is not mapping -%}
{%- set ptype = pdef.enum | join('|') -%}
{%- else -%}
{%- set ptype = pdef.type -%}
{%- endif -%}
{%- endif -%}
{%- set part = pname ~ ('' if pname in req else '?') ~ ': ' ~ ptype -%}
{%- if ns_p.sig -%}
{%- set ns_p.sig = ns_p.sig ~ ', ' ~ part -%}
{%- else -%}
{%- set ns_p.sig = part -%}
{%- endif -%}
{%- endfor -%}
{{- '\n- ' ~ fn.name ~ '(' ~ ns_p.sig ~ ')' -}}
{%- if fn.description is defined -%}
{{- ' — ' ~ fn.description -}}
{%- endif -%}
{%- for pname in props -%}
{%- set pdef = props[pname] -%}
{%- if pdef.type is defined and (pdef.type == 'array' or pdef.type == 'object') -%}
{{- '\n - ' ~ pname ~ ' schema: ' ~ pdef | tojson -}}
{%- endif -%}
{%- endfor -%}
{%- endmacro -%}
{%- macro render_content(content, do_vision_count, is_system_content=false) -%}
{%- if content is string -%}
{{- content -}}
{%- elif content is iterable and content is not mapping -%}
{%- for item in content -%}
{%- if 'image' in item or 'image_url' in item or item.type == 'image' -%}
{%- if is_system_content -%}{{- raise_exception('System message cannot contain images.') -}}{%- endif -%}
{%- if do_vision_count -%}{%- set image_count.value = image_count.value + 1 -%}{%- endif -%}
{%- if add_vision_id is defined and add_vision_id -%}{{- 'Picture ' ~ image_count.value ~ ': ' -}}{%- endif -%}
{{- '<|vision_start|><|image_pad|><|vision_end|>' -}}
{%- elif 'video' in item or item.type == 'video' -%}
{%- if is_system_content -%}{{- raise_exception('System message cannot contain videos.') -}}{%- endif -%}
{%- if do_vision_count -%}{%- set video_count.value = video_count.value + 1 -%}{%- endif -%}
{%- if add_vision_id is defined and add_vision_id -%}{{- 'Video ' ~ video_count.value ~ ': ' -}}{%- endif -%}
{{- '<|vision_start|><|video_pad|><|vision_end|>' -}}
{%- elif 'text' in item -%}
{{- item.text -}}
{%- endif -%}
{%- endfor -%}
{%- endif -%}
{%- endmacro -%}
{%- set ns_flags = namespace(enable_thinking=true) -%}
{%- if enable_thinking is defined -%}
{%- set ns_flags.enable_thinking = enable_thinking -%}
{%- endif -%}
{%- if not messages -%}{{- raise_exception('No messages provided.') -}}{%- endif -%}
{%- set has_system = false -%}
{%- set system_content = '' -%}
{%- if messages[0].role == 'system' or messages[0].role == 'developer' -%}
{%- set has_system = true -%}
{%- set sysc = render_content(messages[0].content, false, true) | trim -%}
{%- if '<|think_off|>' in sysc -%}
{%- set ns_flags.enable_thinking = false -%}
{%- set sysc = sysc | replace('<|think_off|>', '') -%}
{%- endif -%}
{%- if '<|think_on|>' in sysc -%}
{%- set ns_flags.enable_thinking = true -%}
{%- set sysc = sysc | replace('<|think_on|>', '') -%}
{%- endif -%}
{%- set system_content = sysc | trim -%}
{%- endif -%}
{%- if tools and tools is iterable and tools is not mapping -%}
{{- '<|im_start|>system\n' -}}
{{- '# Tools\n\nYou have access to the following functions:\n\n<tools>' -}}
{%- for tool in tools -%}
{{- render_tool_signature(tool) -}}
{%- endfor -%}
{{- '\n</tools>\n\n' -}}
{{- 'IMPORTANT: Always close any thinking with </think> BEFORE emitting <tool_call>. ' -}}
{{- 'Reasoning inside a <tool_call> or its parameters is forbidden. ' -}}
{{- 'When calling a tool, output one or more XML blocks in EXACTLY this format and nothing after the final </tool_call>:\n\n' -}}
{{- '<tool_call>\n<function=example_function_name>\n<parameter=example_parameter_1>\nvalue_1\n</parameter>\n<parameter=example_parameter_2>\nThis is the value for the second parameter\nthat can span\nmultiple lines\n</parameter>\n</function>\n</tool_call>\n\n' -}}
{{- 'Rules:\n' -}}
{{- '- Prefer a matching tool over answering from memory when applicable.\n' -}}
{{- '- If a prior tool response contains an id and the user is modifying that object, reuse the id with the matching update_* tool.\n' -}}
{{- '- Put any reasoning or natural language BEFORE the first <tool_call>, never after the last </tool_call>.\n' -}}
{{- '- Include every required parameter; preserve user strings verbatim for ids, names, titles, subjects, emails, and queries.\n' -}}
{{- '- For object/array parameter values, write valid JSON inside the parameter body.\n' -}}
{{- '- If no tool is needed, answer normally.' -}}
{%- if has_system and system_content -%}
{{- '\n\n' ~ system_content -}}
{%- endif -%}
{{- '<|im_end|>\n' -}}
{%- elif has_system and system_content -%}
{{- '<|im_start|>system\n' ~ system_content ~ '<|im_end|>\n' -}}
{%- endif -%}
{# Find last real user message (not a tool_response wrapper) #}
{%- set ns = namespace(last_user_index=-1) -%}
{%- for m in messages -%}
{%- if m.role == 'user' -%}
{%- set uc = render_content(m.content, false) | trim -%}
{%- if not (uc.startswith('<tool_response>') and uc.endswith('</tool_response>')) -%}
{%- set ns.last_user_index = loop.index0 -%}
{%- endif -%}
{%- endif -%}
{%- endfor -%}
{# Render messages #}
{%- for message in messages -%}
{%- set is_system = (message.role == 'system' or message.role == 'developer') -%}
{%- set content = render_content(message.content, true, is_system) | trim -%}
{%- if '<|think_off|>' in content -%}
{%- set ns_flags.enable_thinking = false -%}
{%- set content = content | replace('<|think_off|>', '') -%}
{%- endif -%}
{%- if '<|think_on|>' in content -%}
{%- set ns_flags.enable_thinking = true -%}
{%- set content = content | replace('<|think_on|>', '') -%}
{%- endif -%}
{%- set content = content | trim -%}
{%- if is_system -%}
{%- if not loop.first -%}
{{- raise_exception('System/developer message must be at the beginning.') -}}
{%- endif -%}
{%- elif message.role == 'user' -%}
{{- '<|im_start|>user\n' ~ content ~ '<|im_end|>\n' -}}
{%- elif message.role == 'assistant' -%}
{# Simple <think> auto-close: if there's a <tool_call> but no closing think tag, inject one #}
{%- if '<tool_call>' in content and '<think>' in content and '</think>' not in content and '</thinking>' not in content -%}
{%- set content = content | replace('<tool_call>', '</think>\n<tool_call>', 1) -%}
{%- endif -%}
{# Extract reasoning_content (split-based, minja-safe) #}
{%- set reasoning_content = '' -%}
{%- if message.reasoning_content is defined and message.reasoning_content is string -%}
{%- set reasoning_content = message.reasoning_content -%}
{%- elif '</think>' in content -%}
{%- set _parts = content.split('</think>') -%}
{%- set _before = _parts[0] -%}
{%- if '<think>' in _before -%}
{%- set reasoning_content = _before.split('<think>')[1] | trim -%}
{%- else -%}
{%- set reasoning_content = _before | trim -%}
{%- endif -%}
{%- set content = _parts[1] | trim -%}
{%- elif '</thinking>' in content -%}
{%- set _parts = content.split('</thinking>') -%}
{%- set _before = _parts[0] -%}
{%- if '<think>' in _before -%}
{%- set reasoning_content = _before.split('<think>')[1] | trim -%}
{%- else -%}
{%- set reasoning_content = _before | trim -%}
{%- endif -%}
{%- set content = _parts[1] | trim -%}
{%- elif '<think>' in content -%}
{%- set reasoning_content = content.split('<think>')[1] | trim -%}
{%- set content = '' -%}
{%- endif -%}
{%- set reasoning_content = reasoning_content | trim -%}
{%- set content = content | trim -%}
{# Show <think> only for turns AFTER the last real user query #}
{%- set show_think = false -%}
{%- if reasoning_content -%}
{%- if preserve_thinking is defined and preserve_thinking is true -%}
{%- set show_think = true -%}
{%- elif loop.index0 > ns.last_user_index -%}
{%- set show_think = true -%}
{%- endif -%}
{%- endif -%}
{%- if show_think -%}
{{- '<|im_start|>assistant\n<think>\n' ~ reasoning_content ~ '\n</think>\n\n' ~ content -}}
{%- else -%}
{{- '<|im_start|>assistant\n' ~ content -}}
{%- endif -%}
{%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping -%}
{%- for tool_call in message.tool_calls -%}
{%- if tool_call.function is defined -%}
{%- set tool_call = tool_call.function -%}
{%- endif -%}
{%- if loop.first -%}
{%- if content | trim -%}
{{- '\n\n<tool_call>\n<function=' ~ tool_call.name ~ '>\n' -}}
{%- else -%}
{{- '<tool_call>\n<function=' ~ tool_call.name ~ '>\n' -}}
{%- endif -%}
{%- else -%}
{{- '\n<tool_call>\n<function=' ~ tool_call.name ~ '>\n' -}}
{%- endif -%}
{{- render_tool_arguments(tool_call.arguments) -}}
{{- '</function>\n</tool_call>' -}}
{%- endfor -%}
{%- endif -%}
{{- '<|im_end|>\n' -}}
{%- elif message.role == 'tool' -%}
{%- if loop.index0 == 0 or messages[loop.index0 - 1].role != 'tool' -%}
{{- '<|im_start|>user' -}}
{%- endif -%}
{{- '\n<tool_response>\n' ~ content ~ '\n</tool_response>' -}}
{%- if loop.last or messages[loop.index0 + 1].role != 'tool' -%}
{{- '\n<|im_end|>\n' -}}
{%- endif -%}
{%- else -%}
{{- raise_exception('Unexpected message role.') -}}
{%- endif -%}
{%- endfor -%}
{%- if add_generation_prompt -%}
{{- '<|im_start|>assistant\n' -}}
{%- if ns_flags.enable_thinking is false -%}
{{- '<think>\n\n</think>\n\n' -}}
{%- else -%}
{{- '<think>\n好,' -}}
{%- endif -%}
{%- endif -%}
更多推荐


所有评论(0)