开源项目 Hugging Face Models 2026-07-08T12:01 正文 ok 2664 words

Qwen 3.5 与 3.6 版 Jinja 对话模板修复(v21)

英文标题:🤗 froggeric/Qwen-Fixed-Chat-Templates

该项目提供针对 Qwen 3.5 和 3.6 官方对话模板的即插即用修复,解决了 Agent 循环停滞、KV 缓存失效、令牌浪费等关键问题,并支持 LM Studio、llama.cpp、vLLM 等主流推理引擎。模板通过空思考毒化消除、缓存安全优化、原生 XML 工具调用格式恢复等手段,显著提升了多轮对话的性能和稳定性。开发者可直接替换模板文件使用,还可利用内联思考开关、有效负载截断和 JSON 格式覆盖等特性灵活控制行为。该修复对本地部署及 Agent 应用开发者具有重要价值。
打开原文相关 1.6 · 机会 2
media4.5 KB media9.8 KB media412.5 KB

中文

Qwen 3.5 与 3.6 修复版 Jinja 对话模板 (v21)

这是一个即插即用的 Jinja 模板,修复了官方 Qwen 对话模板中的渲染错误、KV 缓存失效、令牌浪费以及致命的 Agent 停滞问题。

它适用于 LM Studio、llama.cpp、vLLM、MLX、oMLX,以及任何支持 HuggingFace Jinja 模板的引擎。你只需仓库根目录下的单个 chat_template.jinja 文件,即可用于所有 Qwen 3.5 和 3.6 变体。


快速安装

根据你的环境选择并更新模板:

LM Studio

  1. 在右侧面板中打开你的 Qwen 模型。
  2. 向下滚动到 Prompt Template。
  3. 用 chat_template.jinja 的内容替换原有模板。
  4. 点击 Save。

llama.cpp / koboldcpp

在启动命令中直接使用该文件:

--jinja --chat-template-file chat_template.jinja

vLLM

将 tokenizer_config.json 中的 "chat_template" 字符串替换为该文件的原始内容。使用 qwen3_coder 工具解析器:

--tool-call-parser qwen3_coder

oMLX

覆盖本地模型目录中的 chat_template.jinja。使用 --jinja 加载。移除任何 chat_template_kwargs 覆盖项,因为模板内部已处理所有逻辑。


为什么你需要它

官方 Qwen 模板包含限制和 Python 特定的 Jinja 逻辑,这会破坏在许多推理引擎和 Agent 框架上的使用。

已修复的关键问题

领域 问题 修复
Agent 循环 模型在组合对话与工具调用时中止本轮。 消除“空思考”毒化。
Agent 循环 模型卡在重复生成相同的失败工具调用。 加入两级错误升级机制以强制纠正。
Agent 循环 模型在获取数据后陷入恐慌并争论内部规则。 扩展 <think> 指令以允许综合思考。
Agent 循环 包含“error”一词的 API 返回触发虚假循环。 用严格的结构守卫替代宽泛的匹配。
性能 被篡改的历史轮次不断破坏前缀缓存。 强制按时间顺序排列历史记录,实现 100% 的 KV 缓存命中率。
性能 深度 Jinja 嵌套使 llama.cpp 速度下降 80%。 扁平化 AST 架构以最大化吞吐量。
兼容性 Python 特有的过滤器导致 C++ 推理引擎崩溃。 重写所有过滤器为 100% minijinja 安全。
兼容性 Qwen 原生解析器(如 vLLM)在 JSON 格式化时崩溃。 保持规范的 Qwen XML 格式为默认。
兼容性 较旧的 API 设置和封装器在原生 XML 上崩溃。 添加了 tool_call_format="json" 可选覆盖。
兼容性 Anthropic 的 message.thinking 负载被拒绝。 添加了对 Anthropic 推理的原生支持。
稳定性 大量工具数据返回导致上下文窗口溢出。 实现了动态负载截断限制。
稳定性 对话中段的系统提示导致模板崩溃。 添加了对任意系统消息的原生支持。
稳定性 模型调用工具时未关闭推理标签。 在工具边界前自动注入闭合标签。
边缘情况 流式生成中偶尔出现文本重复。 恢复生成提示的规范间距。
边缘情况 禁用思考后模型幻觉生成推理标签。 注入严格边界以强制绕过推理。

自定义与使用

思考开关

你可以控制模型的推理行为。在系统或用户提示的任意位置插入 <|think_on|> 或 <|think_off|>。模板会拦截该标记,将其从最终上下文中移除,使模型看不到,并即时切换推理模式。

快速回答,无推理:

System: 你是一个编程助手。<|think_off|> User: 2+2 是多少?

深度推理:

System: 你是一个编程助手。<|think_on|> User: 用 Rust 实现一棵红黑树。

(该标记语法使用了 Qwen 的控制标记分隔符,保证绝不会与合法文本或文件路径冲突,这不同于早期社区模板使用的 /think)

令牌节省(移除历史思考)

默认情况下,本模板会保留对话历史中所有过往的 <think> 块。这可以防止模型在复杂的 Agent 循环中出现“失忆停滞”,并能在本地推理引擎上数学保障 100% 的前缀 KV 缓存命中率。

如果你在硬件资源受限的环境下运行且需要节省上下文令牌,可以在引擎的模板 kwargs 中显式禁用此功能来自动移除过往思考:

{ "preserve_thinking": false }

(注意:将此设置为 false 会降低多轮对话中的 KV 缓存命中率,因为提示字符串会动态改变。)

工具调用格式覆盖(JSON 与 XML)

Qwen 模型原生训练输出 XML 格式的工具调用(<function=name>)。默认情况下,本模板使用此原生 XML 格式以最大化模型的智能和可靠性。

对于大多数用户(包括使用 vLLM 或 llama.cpp / llama-server 的用户),你无需做出任何更改。 现代推理引擎原生理解 Qwen 的 XML,并会自动将其转换为标准 OpenAI API 响应给你的下游客户端。

何时使用 JSON 覆盖: 如果你使用的自定义封装器、较旧的引擎版本,或者特定框架(如 ik_llama)严格要求模型自身输出 Hermes JSON({"name": "...", "arguments": {...}})并在遇到 XML 时崩溃,你可以通过传递以下 kwarg 强制模板使用 JSON:

{ "tool_call_format": "json" }

当选择 JSON 格式时,模板会显式禁用 max_tool_arg_chars 截断功能。截断 JSON 字符串会在结构上破坏其语法,这将毒化模型的历史记录并导致下游解析器崩溃。


运行测试套件

python3 scripts/test_v21.py

测试覆盖了 auto_disable_thinking_with_tools、负载截断逻辑、并行工具间距、对话中段系统消息渲染、深度 Agent 回退、XML 工具格式、<|think_off|> / <|think_on|> 内联覆盖,以及所有旧版回归测试。


作者

角色 作者
原始模型 阿里云(Qwen 团队)
模板修复 froggeric
C++ AST 优化 barubary / spiritbuun

许可证

Apache-2.0,继承自 Qwen。


关键修复技术细节

1. “空思考”毒化与逻辑陷阱修复

之前的版本试图通过用空的 <think>\n</think> 块替换过往思考,并配合要求工具在 </think> 后立即调用的绝对系统提示来节省令牌。这创造了一种有害的学习模式:模型将空思考与工具关联,将完整思考与禁止的对话文本关联,导致 80% 以上的过早 <|im_end|> 停滞率。我们废除了空思考注入,并重写了 <IMPORTANT> 指令,明确授权在思考块后进行对话综合。

2. KV 缓存安全与自回归标准化

Llama.cpp 和 vLLM 利用前缀 KV 缓存来加速生成。由于本模板现在默认按时间顺序保留历史思考,渲染的历史记录与缓存的生成令牌完美同步。结合在自回归边界处的严格单 \n 标准化,在多轮循环中实现了 100% 的 KV 缓存命中率。

3. 原生 XML 工具调用格式

模型以 Qwen3-Coder 使用的 XML 工具调用格式进行训练。我们原生恢复了此格式,使其兼容所有解析器,同时通过使用 C++ 安全的键迭代(for args_name in tool_call.arguments)绕过了 |items 崩溃。

4. 两级 Agent 错误升级

当工具调用反复验证失败时,模型可能进入退化的推理螺旋。本模板利用由前向跟踪的 consecutive_failures 计数器驱动的两级升级系统。第一次错误时,生成提示前缀会更改,以在不同的令牌位置播种推理,打破缓存的吸引子状态。第二次连续错误时,思考块被完全绕过,一条紧急带外指令强制立即进行修正操作,并安全地封装在用户 tool_response 块中。

5. 智能误报检测

与其使用宽泛的子串匹配,触发成功返回的数据库中包含“error”等词的虚假重试循环,本模板采用严格的结构守卫,查找 Exception:、"error":、Traceback 和 command not found,并结合长度门控和 Shell 回显排除($ )。

6. minijinja 兼容性约束

仅限 Python 的 Jinja2 特性在 minijinja(llama.cpp、LM Studio 和 MLX 使用的 C++ 运行时)上会崩溃或行为异常。所有实例均已重构以实现通用支持:

  • content | replace('<|think_on|>', '') 变为 content.split('<|think_on|>') | join('')(修复了当被替换的字符串位于索引 0 时 minja 静默丢弃整个文本负载的错误)。
  • \| items 变为 for key in mapping
  • loop.previtem 变为 messages[loop.index0 - 1]
  • map('string') 变为 join('|')
  • \| first 变为 '$ ' in content

7. 面向 C++ 吞吐量的 AST 扁平化

深度嵌套的 Jinja 循环和宏会在 C++ 推理引擎中造成严重的解析瓶颈。我们扁平化了 AST 架构,通过流线化 ns_state 跟踪和历史记录渲染循环的评估方式,有效解决了 llama.cpp 上 80% 的推理吞吐量下降问题。

8. 动态负载截断

海量 API 或数据库返回可能瞬间撑爆模型的上下文窗口。我们实现了 max_tool_arg_chars 和 max_tool_response_chars 限制器,安全地切割超大的负载。至关重要的是,当激活 tool_call_format="json" 覆盖时,此截断会自动禁用,因为切割序列化的 JSON 字符串会在结构上破坏数据并导致下游解析器崩溃。

9. 推理绕过幻觉缓解

当思考被禁用时,Qwen 模型由于训练偏差经常会幻觉生成推理标签。我们注入了安全边界,并调整了 <IMPORTANT> 系统块,在定义工具调用行为时移除了对 </think> 的显式提及。这成功阻止了模型在非推理状态下尝试调用工具时幻觉生成闭合标签。

更新历史与变更日志

2026-07-02 更新 (v21.3):可选的 JSON 工具格式 Kwarg。 为 chat_template_kwargs 添加了可选 tool_call_format="json" 覆盖。这为特定配置的用户(如自定义封装器或仅支持 Hermes JSON 解析的旧引擎)提供了一个逃生出口,同时不破坏规范的 XML 默认设置,也不会降低模型的主要训练分布。在 JSON 模式下安全地跳过 max_tool_arg_chars 截断以防语法损坏。

2026-07-02 更新 (v21.2):推理绕过幻觉修复。 调整了 <IMPORTANT> 块指令,在定义工具调用行为时移除了对 </think> 的显式提及。这阻止了模型在推理被明确禁用时将 </think> 标签作为前缀进行幻觉生成。

2026-07-02 更新 (v21.1):可靠性大修与 XML 回退。 解决了关键错误和兼容性问题,特别是前缀缓存效率方面。(1) 工具调用 XML 格式回退: 回退了 PR 45,恢复原生 XML 格式,因为 JSON 从根本上破坏了 vLLM 的原生 qwen3_coder 解析器。(2) 前缀缓存修复: 将 preserve_thinking 默认值恢复为 true,并移除了破坏缓存的额外换行。(3) 提示注入防护: 不受信任的工具响应中的 <|think_off|> 标签现在可以正确被忽略。(4) 引号内标签错误修复: 当助手引用 </think> 时,模板不再损坏历史记录。(5) Anthropic message.thinking: 添加了对 Anthropic 推理内容的支持。(6) 误报工具错误: 将错误检测范围缩减到响应的前 80 个字符,以防误报。(7) 规范的生成提示: 为无推理的生成提示恢复了规范的 \n\n 间距,以修复流式传输下的答案重复问题。(衷心感谢 Moore2877、choongng 以及社区的卓越贡献!)

2026-06-05 更新 (v20):架构师补丁。 针对 Agent 循环和 C++ 推理引擎的重大结构更新。(1) Minja AST 扁平化: 优化了 Jinja 嵌套,修复了导致 llama.cpp 推理吞吐量下降 80% 的解析瓶颈。(2) Minja 替换错误修复(热修复): 绕过了 llama.cpp 中一个 C++ 解析错误——当在用户提示的索引 0 处使用 replace 过滤器时,会静默丢弃整个文本负载。内联思考切换现在用 split 和 join 实现稳健清除。(3) 自动禁用思考: 引入 auto_disable_thinking_with_tools kwarg(默认 false),允许用户在工具使用期间立即关闭推理模块。(4) 深度 Agent 回退: 解决了由对话中段系统提示或缺少人类 user 消息的循环触发的异常。(5) 负载截断: 实现了 max_tool_arg_chars 和 max_tool_response_chars 配置,彻底阻止海量数据返回导致上下文窗口爆炸。(衷心感谢 barubary / spiritbuun 对这些 C++ 架构优化的贡献!)

2026-05-18 更新 (v19):Agent 循环修复。 (1) 废除“空思考”毒化: 重写了 AST 历史记录……

English / 原文

Fixed jinja chat templates for Qwen 3.5 & 3.6 (v21)

This is a drop-in Jinja template that fixes rendering errors, KV cache invalidation, token waste, and fatal agentic stalling in the official Qwen chat templates.

It works across LM Studio, llama.cpp, vLLM, MLX, oMLX, and any engine that supports HuggingFace Jinja templates. You only need the single chat_template.jinja file at the root of the repository for all Qwen 3.5 and 3.6 variants.


Quick Install

Choose your environment and update the template:

LM Studio

  1. Open your Qwen model in the right side panel.
  2. Scroll down to Prompt Template.
  3. Replace the template with the contents of chat_template.jinja.
  4. Click Save.

llama.cpp / koboldcpp

Use the file directly in your launch command:

--jinja --chat-template-file chat_template.jinja

vLLM

Replace the "chat_template" string in your tokenizer_config.json with the raw file contents. Use the qwen3_coder tool parser:

--tool-call-parser qwen3_coder

oMLX

Overwrite chat_template.jinja in your local model directory. Load with --jinja. Remove any chat_template_kwargs overrides because the template handles everything internally.


Why you need this

The official Qwen templates contain restrictions and Python-specific Jinja logic that break usage on many inference engines and agent frameworks.

Critical Issues Fixed

Area Issue The Fix
Agentic Loop Model aborts turn when combining chat and a tool call. Cured "Empty Think" poisoning.
Agentic Loop Model gets stuck emitting the identical failing tool call. Added two-tier error escalation to force correction.
Agentic Loop Model panics and debates internal rules after fetching data. Broadened <think> instructions to allow synthesis.
Agentic Loop API returns containing the word "error" trigger false loops. Replaced broad matching with strict structural guards.
Performance Mutated past turns constantly destroy the prefix cache. Enforced chronological history for a 100% KV Cache hit rate.
Performance Deep Jinja nesting drops llama.cpp speed by 80%. Flattened the AST architecture to maximize throughput.
Compatibility Python-specific filters crash C++ inference engines. Rewrote all filters to be 100% minijinja safe.
Compatibility Qwen-native parsers (like vLLM) crash on JSON formatting. Maintained canonical Qwen XML format as the default.
Compatibility Older API setups and wrappers crash on native XML. Added a tool_call_format="json" opt-in override.
Compatibility Anthropic message.thinking payloads are rejected. Added native Anthropic reasoning support.
Stability Massive tool data returns blow out the context window. Added dynamic payload truncation limits.
Stability Mid-conversation system prompts crash the template. Added native support for arbitrary system messages.
Stability Model calls a tool without closing its reasoning tags. Auto-injects closing tags before tool boundaries.
Edge Cases Text occasionally duplicates during streaming generation. Restored canonical spacing to the generation prompt.
Edge Cases Model hallucinates reasoning tags when thinking is disabled. Injected strict boundaries to force reasoning bypass.

Customization & Usage

The Thinking Toggle

You can control the model reasoning behavior. Insert <|think_on|> or <|think_off|> anywhere in your system or user prompt. The template intercepts the tag, removes it from the final context so the model never sees it, and flips the reasoning mode instantly.

Fast answer, no reasoning:

System: You are a coding assistant. <|think_off|>
User: What's 2+2?

Deep reasoning:

System: You are a coding assistant. <|think_on|>
User: Implement a red-black tree in Rust.

(The tag syntax uses Qwen's control token delimiters to guarantee it will never collide with legitimate text or file paths, unlike earlier community templates that used/think)

Token Saving (Stripping past thoughts)

By default, this template preserves all past <think> blocks in the chat history. This prevents the model from suffering "amnesia stalls" during complex agentic loops, and it mathematically guarantees a 100% Prefix KV Cache hit rate on local inference engines.

If you are running constrained hardware and need to save context tokens, you can explicitly disable this feature in your engine's template kwargs to automatically strip past thoughts:

{
  "preserve_thinking": false
}

(Note: Setting this to false will reduce your KV Cache hit rate during multi-turn chats because the prompt string will dynamically mutate).

Tool Call Format Override (JSON vs XML)

Qwen models are natively trained to output tool calls in XML (<function=name>). By default, this template uses this native XML format to maximize the model's intelligence and reliability.

For most users (including those usingvLLM or llama.cpp / llama-server), you do NOT need to change anything. Modern inference engines natively understand Qwen's XML and will automatically translate it into standard OpenAI API responses for your downstream clients.

When to use the JSON override: If you are using a custom wrapper, an older engine version, or a specific framework (like ik_llama) that strictly expects the model itself to output Hermes JSON ({"name": "...", "arguments": {...}}) and crashes on XML, you can force the template to use JSON by passing this kwarg:

{
  "tool_call_format": "json"
}

When you opt into the JSON format, the template explicitly disables the max_tool_arg_chars truncation feature. Truncating a JSON string structurally corrupts its syntax, which would poison the model's history and crash downstream parsers.


Running the test suite

python3 scripts/test_v21.py

Tests cover auto_disable_thinking_with_tools, payload truncation logic, parallel tool spacing, mid-conversation system rendering, deep agent loop fallback, XML tool format, <|think_off|> / <|think_on|> inline overrides, and all legacy regression tests.


Authorship

Role Author
Original models Alibaba Cloud (Qwen team)
Template fixes froggeric
C++ AST optimizations barubary / spiritbuun

License

Apache-2.0, inherited from Qwen.


Technical Details of the Critical Fixes

1. The "Empty Think" Poisoning & Logic Trap Cure

Previous versions attempted to save tokens by replacing past thoughts with empty <think>\n</think> blocks, combined with an absolute system prompt demanding a tool be called immediately after </think>. This created a toxic learning pattern: the model associated empty thoughts with tools, and full thoughts with forbidden conversational text, causing an 80%+ premature <|im_end|> stalling rate. We abolished empty think injection and rewrote the <IMPORTANT> directives to explicitly authorize conversational synthesis after a thought block.

2. KV Cache Safety & Autoregressive Normalization

Llama.cpp and vLLM utilize prefix KV caching to speed up generation. Because this template now preserves historical thoughts chronologically by default, the rendered history perfectly synchronizes with the cached generated tokens. Combined with strict single \n normalization at autoregressive boundaries, this achieves a 100% KV Cache hit rate in multi-turn loops.

3. Native XML Tool Call Format

The model was trained with the XML tool call format used by Qwen3-Coder. We restored this format natively, making it compatible with all parsers while bypassing the |items crash by using C++ safe key iteration (for args_name in tool_call.arguments).

4. Two-Tier Agentic Error Escalation

When a tool call fails validation repeatedly, the model can enter a degenerate reasoning spiral. This template leverages a two-tier escalation system driven by a forward tracked consecutive_failures counter. On the first error, the generation prompt prefix changes to seed reasoning at a different token position, breaking the cached attractor state. On the second consecutive error, the think block is bypassed entirely and an urgent out-of-band directive forces an immediate corrected action wrapped safely within the user tool_response block.

5. Smart False-Positive Detection

Instead of broad substring matching that triggers false retry loops on successful database returns containing words like "error", this template utilizes strict structural guards looking for Exception:, "error":, Traceback, and command not found, combined with length gates and shell echo exclusions ($ ).

6. minijinja Compatibility Constraints

Python-only Jinja2 features crash or misbehave on minijinja (the C++ runtime used by llama.cpp, LM Studio, and MLX). All instances have been refactored for universal support:

  • content | replace('<|think_on|>', '') became content.split('<|think_on|>') | join('') (Fixes a bug where minja silently drops the entire text payload if the replaced string is found at index 0).
  • \| items became for key in mapping
  • loop.previtem became messages[loop.index0 - 1]
  • map('string') became join('|')
  • \| first became '$ ' in content

7. AST Flattening for C++ Throughput

Deeply nested Jinja loops and macros create severe parsing bottlenecks in C++ inference engines. We flattened the AST architecture, effectively curing an 80% inference throughput drop on llama.cpp by streamlining how ns_state tracking and historical rendering loops are evaluated.

8. Dynamic Payload Truncation

Massive API or database returns can instantly blow out a model's context window. We implemented max_tool_arg_chars and max_tool_response_chars limiters that safely slice oversized payloads. Crucially, this truncation is automatically disabled when the tool_call_format="json" override is active, as slicing a serialized JSON string structurally corrupts the data and crashes downstream parsers.

9. Reasoning Bypass Hallucination Mitigation

When thinking is disabled, Qwen models often hallucinate reasoning tags due to their training bias. We injected a safe boundary and adjusted the <IMPORTANT> system block to remove explicit mentions of </think> during tool instructions. This successfully stops the model from hallucinating closing tags when attempting to call tools in a no-reasoning state.

Update History & Changelog

2026-07-02 Update (v21.3): Optional JSON Tool Format Kwarg. Added an optional tool_call_format="json" override for the chat_template_kwargs. This provides an escape hatch for users on specific setups (like custom wrappers or older engines that only support Hermes JSON parsing) without breaking the canonical XML default or degrading the model's primary training distribution. max_tool_arg_chars truncation is safely bypassed in JSON mode to prevent syntax corruption.

2026-07-02 Update (v21.2): Reasoning Bypass Hallucination Fix. Adjusted the <IMPORTANT> block instructions to remove explicit mentions of </think> when defining tool call behavior. This stops the model from hallucinating </think> tags as a prefix when reasoning is explicitly disabled.

2026-07-02 Update (v21.1): Reliability Overhaul & XML Revert. Addressed critical bugs and compatibility issues, particularly around prefix cache efficiency. (1) Tool Call XML Format Revert: Reverted PR 45 to restore the native XML format, as JSON fundamentally broke vLLM's native qwen3_coder parser. (2) Prefix Cache Fixes: Restored the preserve_thinking default to true and removed extraneous newlines that broke caching. (3) Prompt Injection Guard: <|think_off|> tags in untrusted tool responses are now correctly ignored. (4) Quoted Tag Bug Fix: The template no longer corrupts history when the assistant quotes </think>. (5) Anthropicmessage.thinking: Added support for Anthropic reasoning content. (6) False-Positive Tool Errors: Reduced error detection scope to the first 80 characters of a response to prevent false positives. (7) Canonical Generation Prompt: Restored the canonical \n\n spacing to the non-thinking generation prompt to fix answer duplication issues under streaming. (Huge thanks toMoore2877, choongng, and the community for their excellent contributions!)

2026-06-05 Update (v20): The Architect Patch. Major structural update for agentic loops and C++ inference engines. (1) Minja AST Flattening: Optimized Jinja nesting to fix parsing bottlenecks that dropped inference throughput by 80% on llama.cpp. (2) Minja Replace Bug Fix (Hotfix): Bypassed a C++ parsing bug in llama.cpp where using the replace filter at index 0 of a user prompt silently dropped the entire text payload. Inline thinking toggles now use split and join for robust stripping. (3) Auto-disable Thinking: Introduced auto_disable_thinking_with_tools kwarg (default false) that allows users to instantly shut off reasoning blocks during tool use. (4) Deep Agent Fallbacks: Resolved exceptions triggered by mid-conversation system prompts or loops lacking human user messages. (5) Payload Truncation: Implemented max_tool_arg_chars and max_tool_response_chars configurations to definitively stop context window explosions from massive data returns. (Huge thanks tobarubary / spiritbuun for their contributions to these C++ architecture optimizations!)

2026-05-18 Update (v19): The Agentic Loop Cure. (1) Abolished "Empty Think" Poisoning: Rewrote the AST history rendering to completely remove the injection of empty <think>\n</think> blocks. This cures a severe in-context learning bias where the model assumed tools could only be called if it didn't think first, which was causing 80%+ of premature <|im_end|> turn aborts. (2) System Prompt Logic Trap Removed: Softened the absolute tool mandate in the <IMPORTANT> block and restored Universal Synthesis instructions. The model is now explicitly permitted to transition from </think> to a conversational answer without panicking. (3) True 100% KV Cache & Amnesia Fix: preserve_thinking now defaults to true. Past thoughts are retained chronologically, permanently curing "amnesia stalls" during multi-step tool loops while mathematically guaranteeing 100% KV Cache prefix matching out of the box.

2026-05-16 Update (v18): Stability & Precision Patch. (1) Bulletproof False-Positive Detection: Shifted agentic error detection from broad substring matching to strict structural formats (e.g. "error":, Exception:, Traceback), completely curing false-positive retry loops when successful JSON returns simply contain the word "error" or "fail". (2) Legacy Engine Compatibility: Replaced loop.previtem with explicit array indexing, fixing AST crashes on older llama.cpp and minijinja builds that do not track loop state items. (3) True Whitespace Normalization: Fixed a bug where reasoning bypasses and hallucinated tag recovery stacked hidden multi-newlines (\n\n\n), strictly fulfilling the 100% KV Cache hit rate claim for all edge cases. (4) Code Cleanup: Removed dead conditional branches during XML tool parsing.

2026-05-15 Update (v17): (1) Unified Template: Consolidated Qwen 3.5 and Qwen 3.6 into a single chat_template.jinja file that handles all variants. (2) Fixed "Mutually Exclusive" Stopping Bug: Changed the history pruning logic from wiping the entire turn to safely array slicing out just the raw tool tags (content.split('<tool_call>')[0]). This preserves the conversational text in the history, which cures the bug where the model would artificially abort its turn (output <|im_end|>) when it wanted to talk and use a tool simultaneously. (3) 100% KV Cache Hit Rate Restoration: Fully normalized internal whitespace logic (\n\n -> \n) around think blocks and tool calls to exactly match the model's native autoregressive generation spacing. This perfectly synchronizes the template's rendered history with the cached generated tokens, completely eliminating the severe cache invalidation and full prompt re-processing issues present in v16.

2026-05-14 Update (v16): (1) Native XML tool format: reverted from JSON back to the native <function=name> / <parameter=x> format the model was trained on, restoring full compatibility with vLLM's qwen3_coder parser and all inference engines that implement the Qwen tool protocol. (2) --reasoning off respected in error paths: when thinking is disabled (enable_thinking=false / --reasoning off), the error escalation directives are now injected as plain text without opening any <think> block, preventing degenerate prompts in no-reasoning sessions. (3) Smarter false-positive detection: short shell command results (starting with $ ) and search results with timing footers (Took X.Xs) are now correctly excluded from error detection, preventing tool retry loops when commands succeed but their output happens to contain the word error. (4) consecutive_failures counter no longer resets on assistant messages, allowing Tier 2 escalation to actually fire across multi-turn tool retry chains.

2026-05-13 Update (v15): (1) Two-tier error escalation: replaced the brittle backwards lookahead error detection with a fully forward tracking last_tool_failed + consecutive_failures counter. On the first error the generation prompt is pre-seeded with a correction directive inside <think>; on the 2nd+ consecutive error the think block is bypassed and an out-of-band directive forces an immediate corrected action. (2) Length-gated detection: error signals are only read from short tool responses (< 500 chars), preventing false positives when reading code files containing error, exception, etc in legitimate content. (3) Static system prompt: tool instructions are now fully unconditional, permanently eliminating the KV cache invalidation vector introduced in v14.

2026-05-12 Update (v14): Cured tool amnesia loops and post-tool overthinking friction! Implemented Smart Loop Preservation to dynamically scan subsequent tool returns for error markers and conditionally preserve historical reasoning context during active tool failures. Broadened the system instruction scope to define <think> as a dual-purpose planning or synthesis space, completely eliminating indecisiveness post-tool retrieval.

2026-05-11 Update (v13): Reverted tool schemas and assistant output formatting to standard JSON to natively fix downstream MCP parser crashes and C++ implicit enum coercion bugs. Removed the ns_scan history loop to permanently fix KV cache invalidation mid-conversation. Replaced global string replacement for hallucinated tags with a C++ safe, localized array slicing method to prevent data corruption on user code blocks.

2026-05-10 Update (v12): Fixed agent stalls, parameter data loss, and hallucination bugs! Restored dynamic tool instructions and the <IMPORTANT> formatting reminder block to stop grammar parser crashes.

2026-05-10 Update (v11): Fixed agent looping and overthinking! Re-implemented preserve_thinking kwarg to properly strip reasoning blocks from history by default, and restored the reasoning bypass (<think>\n\n</think>\n\n).