diff --git "a/docs/source/Instruction/\346\224\257\346\214\201\347\232\204\346\250\241\345\236\213\345\222\214\346\225\260\346\215\256\351\233\206.md" "b/docs/source/Instruction/\346\224\257\346\214\201\347\232\204\346\250\241\345\236\213\345\222\214\346\225\260\346\215\256\351\233\206.md"
index 01f0e7aa98..f28d1defda 100644
--- "a/docs/source/Instruction/\346\224\257\346\214\201\347\232\204\346\250\241\345\236\213\345\222\214\346\225\260\346\215\256\351\233\206.md"
+++ "b/docs/source/Instruction/\346\224\257\346\214\201\347\232\204\346\250\241\345\236\213\345\222\214\346\225\260\346\215\256\351\233\206.md"
@@ -212,13 +212,13 @@
|[Qwen/Qwen3-235B-A22B-Instruct-2507](https://modelscope.cn/models/Qwen/Qwen3-235B-A22B-Instruct-2507)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✔|-|[Qwen/Qwen3-235B-A22B-Instruct-2507](https://huggingface.co/Qwen/Qwen3-235B-A22B-Instruct-2507)|
|[Qwen/Qwen3-235B-A22B-Instruct-2507-FP8](https://modelscope.cn/models/Qwen/Qwen3-235B-A22B-Instruct-2507-FP8)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✘|-|[Qwen/Qwen3-235B-A22B-Instruct-2507-FP8](https://huggingface.co/Qwen/Qwen3-235B-A22B-Instruct-2507-FP8)|
|[swift/Qwen3-235B-A22B-Instruct-2507-AWQ](https://modelscope.cn/models/swift/Qwen3-235B-A22B-Instruct-2507-AWQ)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✘|-|-|
-|[Qwen/Qwen3-Coder-30B-A3B-Instruct](https://modelscope.cn/models/Qwen/Qwen3-Coder-30B-A3B-Instruct)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✔|coding|[Qwen/Qwen3-Coder-30B-A3B-Instruct](https://huggingface.co/Qwen/Qwen3-Coder-30B-A3B-Instruct)|
-|[Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8](https://modelscope.cn/models/Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✘|coding|[Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8](https://huggingface.co/Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8)|
-|[Qwen/Qwen3-Coder-480B-A35B-Instruct](https://modelscope.cn/models/Qwen/Qwen3-Coder-480B-A35B-Instruct)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✔|coding|[Qwen/Qwen3-Coder-480B-A35B-Instruct](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct)|
-|[Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8](https://modelscope.cn/models/Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✘|coding|[Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8)|
-|[swift/Qwen3-Coder-480B-A35B-Instruct-AWQ](https://modelscope.cn/models/swift/Qwen3-Coder-480B-A35B-Instruct-AWQ)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✘|coding|-|
|[Qwen/Qwen3-4B-Instruct-2507](https://modelscope.cn/models/Qwen/Qwen3-4B-Instruct-2507)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✔|-|[Qwen/Qwen3-4B-Instruct-2507](https://huggingface.co/Qwen/Qwen3-4B-Instruct-2507)|
|[Qwen/Qwen3-4B-Instruct-2507-FP8](https://modelscope.cn/models/Qwen/Qwen3-4B-Instruct-2507-FP8)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✘|-|[Qwen/Qwen3-4B-Instruct-2507-FP8](https://huggingface.co/Qwen/Qwen3-4B-Instruct-2507-FP8)|
+|[Qwen/Qwen3-Coder-30B-A3B-Instruct](https://modelscope.cn/models/Qwen/Qwen3-Coder-30B-A3B-Instruct)|qwen3_coder|qwen3_coder|transformers>=4.51|✘|coding|[Qwen/Qwen3-Coder-30B-A3B-Instruct](https://huggingface.co/Qwen/Qwen3-Coder-30B-A3B-Instruct)|
+|[Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8](https://modelscope.cn/models/Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8)|qwen3_coder|qwen3_coder|transformers>=4.51|✘|coding|[Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8](https://huggingface.co/Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8)|
+|[Qwen/Qwen3-Coder-480B-A35B-Instruct](https://modelscope.cn/models/Qwen/Qwen3-Coder-480B-A35B-Instruct)|qwen3_coder|qwen3_coder|transformers>=4.51|✘|coding|[Qwen/Qwen3-Coder-480B-A35B-Instruct](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct)|
+|[Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8](https://modelscope.cn/models/Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8)|qwen3_coder|qwen3_coder|transformers>=4.51|✘|coding|[Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8)|
+|[swift/Qwen3-Coder-480B-A35B-Instruct-AWQ](https://modelscope.cn/models/swift/Qwen3-Coder-480B-A35B-Instruct-AWQ)|qwen3_coder|qwen3_coder|transformers>=4.51|✘|coding|-|
|[Qwen/Qwen3-30B-A3B-Base](https://modelscope.cn/models/Qwen/Qwen3-30B-A3B-Base)|qwen3_moe|qwen3|transformers>=4.51|✔|-|[Qwen/Qwen3-30B-A3B-Base](https://huggingface.co/Qwen/Qwen3-30B-A3B-Base)|
|[Qwen/Qwen3-30B-A3B](https://modelscope.cn/models/Qwen/Qwen3-30B-A3B)|qwen3_moe|qwen3|transformers>=4.51|✔|-|[Qwen/Qwen3-30B-A3B](https://huggingface.co/Qwen/Qwen3-30B-A3B)|
|[Qwen/Qwen3-235B-A22B](https://modelscope.cn/models/Qwen/Qwen3-235B-A22B)|qwen3_moe|qwen3|transformers>=4.51|✔|-|[Qwen/Qwen3-235B-A22B](https://huggingface.co/Qwen/Qwen3-235B-A22B)|
diff --git a/docs/source_en/Instruction/Supported-models-and-datasets.md b/docs/source_en/Instruction/Supported-models-and-datasets.md
index 20427f7f47..a93d8b951e 100644
--- a/docs/source_en/Instruction/Supported-models-and-datasets.md
+++ b/docs/source_en/Instruction/Supported-models-and-datasets.md
@@ -212,13 +212,13 @@ The table below introduces the models integrated with ms-swift:
|[Qwen/Qwen3-235B-A22B-Instruct-2507](https://modelscope.cn/models/Qwen/Qwen3-235B-A22B-Instruct-2507)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✔|-|[Qwen/Qwen3-235B-A22B-Instruct-2507](https://huggingface.co/Qwen/Qwen3-235B-A22B-Instruct-2507)|
|[Qwen/Qwen3-235B-A22B-Instruct-2507-FP8](https://modelscope.cn/models/Qwen/Qwen3-235B-A22B-Instruct-2507-FP8)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✘|-|[Qwen/Qwen3-235B-A22B-Instruct-2507-FP8](https://huggingface.co/Qwen/Qwen3-235B-A22B-Instruct-2507-FP8)|
|[swift/Qwen3-235B-A22B-Instruct-2507-AWQ](https://modelscope.cn/models/swift/Qwen3-235B-A22B-Instruct-2507-AWQ)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✘|-|-|
-|[Qwen/Qwen3-Coder-30B-A3B-Instruct](https://modelscope.cn/models/Qwen/Qwen3-Coder-30B-A3B-Instruct)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✔|coding|[Qwen/Qwen3-Coder-30B-A3B-Instruct](https://huggingface.co/Qwen/Qwen3-Coder-30B-A3B-Instruct)|
-|[Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8](https://modelscope.cn/models/Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✘|coding|[Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8](https://huggingface.co/Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8)|
-|[Qwen/Qwen3-Coder-480B-A35B-Instruct](https://modelscope.cn/models/Qwen/Qwen3-Coder-480B-A35B-Instruct)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✔|coding|[Qwen/Qwen3-Coder-480B-A35B-Instruct](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct)|
-|[Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8](https://modelscope.cn/models/Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✘|coding|[Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8)|
-|[swift/Qwen3-Coder-480B-A35B-Instruct-AWQ](https://modelscope.cn/models/swift/Qwen3-Coder-480B-A35B-Instruct-AWQ)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✘|coding|-|
|[Qwen/Qwen3-4B-Instruct-2507](https://modelscope.cn/models/Qwen/Qwen3-4B-Instruct-2507)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✔|-|[Qwen/Qwen3-4B-Instruct-2507](https://huggingface.co/Qwen/Qwen3-4B-Instruct-2507)|
|[Qwen/Qwen3-4B-Instruct-2507-FP8](https://modelscope.cn/models/Qwen/Qwen3-4B-Instruct-2507-FP8)|qwen3_nothinking|qwen3_nothinking|transformers>=4.51|✘|-|[Qwen/Qwen3-4B-Instruct-2507-FP8](https://huggingface.co/Qwen/Qwen3-4B-Instruct-2507-FP8)|
+|[Qwen/Qwen3-Coder-30B-A3B-Instruct](https://modelscope.cn/models/Qwen/Qwen3-Coder-30B-A3B-Instruct)|qwen3_coder|qwen3_coder|transformers>=4.51|✘|coding|[Qwen/Qwen3-Coder-30B-A3B-Instruct](https://huggingface.co/Qwen/Qwen3-Coder-30B-A3B-Instruct)|
+|[Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8](https://modelscope.cn/models/Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8)|qwen3_coder|qwen3_coder|transformers>=4.51|✘|coding|[Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8](https://huggingface.co/Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8)|
+|[Qwen/Qwen3-Coder-480B-A35B-Instruct](https://modelscope.cn/models/Qwen/Qwen3-Coder-480B-A35B-Instruct)|qwen3_coder|qwen3_coder|transformers>=4.51|✘|coding|[Qwen/Qwen3-Coder-480B-A35B-Instruct](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct)|
+|[Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8](https://modelscope.cn/models/Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8)|qwen3_coder|qwen3_coder|transformers>=4.51|✘|coding|[Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8)|
+|[swift/Qwen3-Coder-480B-A35B-Instruct-AWQ](https://modelscope.cn/models/swift/Qwen3-Coder-480B-A35B-Instruct-AWQ)|qwen3_coder|qwen3_coder|transformers>=4.51|✘|coding|-|
|[Qwen/Qwen3-30B-A3B-Base](https://modelscope.cn/models/Qwen/Qwen3-30B-A3B-Base)|qwen3_moe|qwen3|transformers>=4.51|✔|-|[Qwen/Qwen3-30B-A3B-Base](https://huggingface.co/Qwen/Qwen3-30B-A3B-Base)|
|[Qwen/Qwen3-30B-A3B](https://modelscope.cn/models/Qwen/Qwen3-30B-A3B)|qwen3_moe|qwen3|transformers>=4.51|✔|-|[Qwen/Qwen3-30B-A3B](https://huggingface.co/Qwen/Qwen3-30B-A3B)|
|[Qwen/Qwen3-235B-A22B](https://modelscope.cn/models/Qwen/Qwen3-235B-A22B)|qwen3_moe|qwen3|transformers>=4.51|✔|-|[Qwen/Qwen3-235B-A22B](https://huggingface.co/Qwen/Qwen3-235B-A22B)|
diff --git a/swift/llm/model/constant.py b/swift/llm/model/constant.py
index 578f44b309..6f0a951680 100644
--- a/swift/llm/model/constant.py
+++ b/swift/llm/model/constant.py
@@ -15,6 +15,7 @@ class LLMModelType:
qwen3 = 'qwen3'
qwen3_thinking = 'qwen3_thinking'
qwen3_nothinking = 'qwen3_nothinking'
+ qwen3_coder = 'qwen3_coder'
qwen3_moe = 'qwen3_moe'
qwen3_moe_thinking = 'qwen3_moe_thinking'
qwen3_next = 'qwen3_next'
diff --git a/swift/llm/model/model/qwen.py b/swift/llm/model/model/qwen.py
index 55b2f3618e..0c5d264417 100644
--- a/swift/llm/model/model/qwen.py
+++ b/swift/llm/model/model/qwen.py
@@ -586,6 +586,21 @@ def _get_cast_dtype(self) -> torch.dtype:
# awq
Model('swift/Qwen3-235B-A22B-Instruct-2507-AWQ'),
]),
+ ModelGroup([
+ Model('Qwen/Qwen3-4B-Instruct-2507', 'Qwen/Qwen3-4B-Instruct-2507'),
+ Model('Qwen/Qwen3-4B-Instruct-2507-FP8', 'Qwen/Qwen3-4B-Instruct-2507-FP8'),
+ ])
+ ],
+ TemplateType.qwen3_nothinking,
+ get_model_tokenizer_with_flash_attn,
+ architectures=['Qwen3MoeForCausalLM', 'Qwen3ForCausalLM'],
+ requires=['transformers>=4.51'],
+ ))
+
+register_model(
+ ModelMeta(
+ LLMModelType.qwen3_coder,
+ [
ModelGroup([
Model('Qwen/Qwen3-Coder-30B-A3B-Instruct', 'Qwen/Qwen3-Coder-30B-A3B-Instruct'),
Model('Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8', 'Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8'),
@@ -594,14 +609,10 @@ def _get_cast_dtype(self) -> torch.dtype:
Model('swift/Qwen3-Coder-480B-A35B-Instruct-AWQ'),
],
tags=['coding']),
- ModelGroup([
- Model('Qwen/Qwen3-4B-Instruct-2507', 'Qwen/Qwen3-4B-Instruct-2507'),
- Model('Qwen/Qwen3-4B-Instruct-2507-FP8', 'Qwen/Qwen3-4B-Instruct-2507-FP8'),
- ])
],
- TemplateType.qwen3_nothinking,
+ TemplateType.qwen3_coder,
get_model_tokenizer_with_flash_attn,
- architectures=['Qwen3MoeForCausalLM', 'Qwen3ForCausalLM'],
+ architectures=['Qwen3MoeForCausalLM'],
requires=['transformers>=4.51'],
))
diff --git a/swift/llm/template/base.py b/swift/llm/template/base.py
index f2ac26fa43..fc396e2208 100644
--- a/swift/llm/template/base.py
+++ b/swift/llm/template/base.py
@@ -1000,7 +1000,7 @@ def _get_system(self, inputs: StdTemplateInputs) -> Optional[str]:
system = template_meta.default_system
if tools is not None:
- system = self.agent_template._format_tools(tools, system or '', inputs.messages[0])
+ system = self.agent_template._format_tools(tools, system, inputs.messages[0])
return system
def _swift_prepare_inputs(self, inputs: StdTemplateInputs):
diff --git a/swift/llm/template/constant.py b/swift/llm/template/constant.py
index 6ee9804ff2..735f32170c 100644
--- a/swift/llm/template/constant.py
+++ b/swift/llm/template/constant.py
@@ -15,6 +15,7 @@ class LLMTemplateType:
qwen3 = 'qwen3'
qwen3_thinking = 'qwen3_thinking'
qwen3_nothinking = 'qwen3_nothinking'
+ qwen3_coder = 'qwen3_coder'
qwen3_emb = 'qwen3_emb'
qwen3_reranker = 'qwen3_reranker'
qwq_preview = 'qwq_preview'
diff --git a/swift/llm/template/template/qwen.py b/swift/llm/template/template/qwen.py
index 4d8edae38b..4bf605f800 100644
--- a/swift/llm/template/template/qwen.py
+++ b/swift/llm/template/template/qwen.py
@@ -68,6 +68,8 @@ class Qwen3Template(ThinkingTemplate):
register_template(QwenTemplateMeta(LLMTemplateType.qwen3_nothinking, default_system=None))
+register_template(QwenTemplateMeta(LLMTemplateType.qwen3_coder, default_system=None, agent_template='qwen3_coder'))
+
class Qwen3RerankerTemplate(Template):
instruction = 'Given a web search query, retrieve relevant passages that answer the query'
diff --git a/swift/plugin/agent_template/extra.py b/swift/plugin/agent_template/extra.py
index 019f05a786..efaa1d188b 100644
--- a/swift/plugin/agent_template/extra.py
+++ b/swift/plugin/agent_template/extra.py
@@ -1,12 +1,12 @@
# Copyright (c) Alibaba, Inc. and its affiliates.
-from typing import List, Union
+from typing import List, Optional, Union
from .base import BaseAgentTemplate
class ReactGRPOAgentTemplate(BaseAgentTemplate):
- def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message=None) -> str:
+ def _format_tools(self, tools: List[Union[str, dict]], system: Optional[str] = None, user_message=None) -> str:
tool_names = []
tool_descs = []
for tool in tools:
diff --git a/swift/plugin/agent_template/glm4.py b/swift/plugin/agent_template/glm4.py
index e18a70fb3e..fc3461fcb7 100644
--- a/swift/plugin/agent_template/glm4.py
+++ b/swift/plugin/agent_template/glm4.py
@@ -37,7 +37,7 @@ def get_toolcall(self, response: str) -> List['Function']:
return super().get_toolcall(response)
return functions
- def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message=None) -> str:
+ def _format_tools(self, tools: List[Union[str, dict]], system: Optional[str] = None, user_message=None) -> str:
tool_descs = []
for tool in tools:
tool = self.unwrap_tool(tool)
@@ -107,7 +107,7 @@ def get_toolcall(self, response: str) -> List['Function']:
return super().get_toolcall(response)
return functions
- def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message=None) -> str:
+ def _format_tools(self, tools: List[Union[str, dict]], system: Optional[str] = None, user_message=None) -> str:
tool_descs = [
'# Tools\n\nYou may call one or more functions to assist with the user query.\n\n'
'You are provided with function signatures within XML tags:\n'
@@ -119,7 +119,7 @@ def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message
'{arg-value-1}\n{arg-key-2}\n'
'{arg-value-2}\n...\n')
tool_descs = '\n'.join(tool_descs)
- if system.strip():
+ if system is not None and system.strip():
tool_descs += '<|system|>\n' + system.strip()
return tool_descs
diff --git a/swift/plugin/agent_template/hermes.py b/swift/plugin/agent_template/hermes.py
index 5cfef8f6ae..4527c92eca 100644
--- a/swift/plugin/agent_template/hermes.py
+++ b/swift/plugin/agent_template/hermes.py
@@ -1,6 +1,6 @@
# Copyright (c) Alibaba, Inc. and its affiliates.
import re
-from typing import TYPE_CHECKING, List, Tuple, Union
+from typing import TYPE_CHECKING, List, Optional, Tuple, Union
import json
@@ -58,8 +58,9 @@ def _format_tool_responses(
res.append(context)
return assistant_content, res
- def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message=None) -> str:
+ def _format_tools(self, tools: List[Union[str, dict]], system: Optional[str] = None, user_message=None) -> str:
tool_descs = [json.dumps(self.wrap_tool(tool), ensure_ascii=False) for tool in tools]
+ system = system or ''
return f"""{system}
# Tools
@@ -110,8 +111,9 @@ def _get_tool_calls(self, tool_calls: List[str]):
tool_calls = '\n'.join(tool_calls)
return f'\n{tool_calls}\n'
- def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message=None) -> str:
+ def _format_tools(self, tools: List[Union[str, dict]], system: Optional[str] = None, user_message=None) -> str:
tool_descs = [json.dumps(self.wrap_tool(tool), ensure_ascii=False) for tool in tools]
+ system = system or ''
if system:
system = f'{system}\n\n'
return f"""{system}# Tools
diff --git a/swift/plugin/agent_template/llama.py b/swift/plugin/agent_template/llama.py
index a247d8420a..3b7fff6d31 100644
--- a/swift/plugin/agent_template/llama.py
+++ b/swift/plugin/agent_template/llama.py
@@ -1,6 +1,6 @@
# Copyright (c) Alibaba, Inc. and its affiliates.
import re
-from typing import TYPE_CHECKING, List, Tuple, Union
+from typing import TYPE_CHECKING, List, Optional, Tuple, Union
import json
@@ -47,7 +47,7 @@ def _format_tool_responses(
res.append(f'{self.start_token}assistant{self.end_token}\n\n')
return assistant_content, res
- def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message=None) -> str:
+ def _format_tools(self, tools: List[Union[str, dict]], system: Optional[str] = None, user_message=None) -> str:
assert user_message is not None
user_content = user_message['content']
tool_descs = [json.dumps(tool, ensure_ascii=False, indent=4) for tool in tools]
@@ -59,7 +59,7 @@ def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message
{user_content}""" # noqa
user_message['content'] = new_user_content
- return system
+ return system or ''
def _format_tool_calls(self, tool_call_messages) -> str:
tool_calls = []
diff --git a/swift/plugin/agent_template/mistral.py b/swift/plugin/agent_template/mistral.py
index 78d76c87d4..120a3e21a9 100644
--- a/swift/plugin/agent_template/mistral.py
+++ b/swift/plugin/agent_template/mistral.py
@@ -1,5 +1,5 @@
import re
-from typing import TYPE_CHECKING, List, Tuple, Union
+from typing import TYPE_CHECKING, List, Optional, Tuple, Union
import json
@@ -55,8 +55,9 @@ def _format_tool_responses(
res.append(context)
return assistant_content, res
- def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message=None) -> str:
+ def _format_tools(self, tools: List[Union[str, dict]], system: Optional[str] = None, user_message=None) -> str:
tool_descs = [json.dumps(self.wrap_tool(tool), ensure_ascii=False) for tool in tools]
+ system = system or ''
return f"""{system}[AVAILABLE_TOOLS]{' '.join(tool_descs)}[/AVAILABLE_TOOLS]"""
def _format_tool_calls(self, tool_call_messages):
diff --git a/swift/plugin/agent_template/qwen.py b/swift/plugin/agent_template/qwen.py
index 6443a12d44..6042b91150 100644
--- a/swift/plugin/agent_template/qwen.py
+++ b/swift/plugin/agent_template/qwen.py
@@ -1,5 +1,5 @@
# Copyright (c) Alibaba, Inc. and its affiliates.
-from typing import List, Union
+from typing import List, Optional, Union
from .base import AgentKeyword, BaseAgentTemplate
@@ -24,8 +24,9 @@ def _get_tool_names_descs(self, tools):
f'Parameters: {tool_desc.parameters} {tool_desc.args_format}')
return tool_names, tool_descs
- def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message=None) -> str:
+ def _format_tools(self, tools: List[Union[str, dict]], system: Optional[str] = None, user_message=None) -> str:
tool_names, tool_descs = self._get_tool_names_descs(tools)
+ system = system or ''
return f"""{system}
# Tools
@@ -56,8 +57,9 @@ def _get_tool_names_descs(self, tools):
f'输入参数:{tool_desc.parameters} {tool_desc.args_format}')
return tool_names, tool_descs
- def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message=None) -> str:
+ def _format_tools(self, tools: List[Union[str, dict]], system: Optional[str] = None, user_message=None) -> str:
tool_names, tool_descs = self._get_tool_names_descs(tools)
+ system = system or ''
return f"""{system}
# 工具
@@ -76,8 +78,9 @@ def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message
class QwenEnParallelAgentTemplate(QwenEnAgentTemplate):
- def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message=None) -> str:
+ def _format_tools(self, tools: List[Union[str, dict]], system: Optional[str] = None, user_message=None) -> str:
tool_names, tool_descs = self._get_tool_names_descs(tools)
+ system = system or ''
return f"""{system}
# Tools
@@ -104,8 +107,9 @@ def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message
class QwenZhParallelAgentTemplate(QwenZhAgentTemplate):
- def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message=None) -> str:
+ def _format_tools(self, tools: List[Union[str, dict]], system: Optional[str] = None, user_message=None) -> str:
tool_names, tool_descs = self._get_tool_names_descs(tools)
+ system = system or ''
return f"""{system}
# 工具
diff --git a/swift/plugin/agent_template/qwen3_coder.py b/swift/plugin/agent_template/qwen3_coder.py
index 170b6b44ae..86418646d3 100644
--- a/swift/plugin/agent_template/qwen3_coder.py
+++ b/swift/plugin/agent_template/qwen3_coder.py
@@ -1,14 +1,13 @@
# Copyright (c) Alibaba, Inc. and its affiliates.
import re
-from typing import TYPE_CHECKING, List, Optional, Tuple, Union
+from typing import TYPE_CHECKING, List, Optional, Union
import json
-from .base import BaseAgentTemplate
+from .hermes import HermesAgentTemplate
if TYPE_CHECKING:
from swift.llm.infer import Function
- from swift.llm.template import Prompt
def render_extra_keys(obj, handled_keys):
@@ -17,11 +16,11 @@ def render_extra_keys(obj, handled_keys):
if isinstance(obj, dict):
for key, value in obj.items():
if key not in handled_keys:
- result += f'\n<{key}>{value}{key}>'
+ result += f'\n<{key}>{json.dumps(value, ensure_ascii=False)}{key}>'
return result
-class Qwen3CoderAgentTemplate(BaseAgentTemplate):
+class Qwen3CoderAgentTemplate(HermesAgentTemplate):
@staticmethod
def _find_function_call(single_content: str) -> Optional['Function']:
@@ -61,11 +60,13 @@ def get_toolcall(self, response: str) -> List['Function']:
functions.append(function)
if len(functions) == 0:
# Compat react_en
- return super().get_toolcall(response)
+ return super(HermesAgentTemplate, self).get_toolcall(response)
return functions
- def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message=None) -> str:
- tool_descs = ['You have access to the following functions:\n\n' '']
+ def _format_tools(self, tools: List[Union[str, dict]], system: Optional[str] = None, user_message=None) -> str:
+ if system is None:
+ system = 'You are Qwen, a helpful AI assistant that can interact with a computer to solve tasks.'
+ tool_descs = [f'{system}\n\n# Tools\n\nYou have access to the following functions:\n\n']
for tool in tools:
tool_desc = ''
@@ -129,8 +130,6 @@ def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message
'answer the question like normal with your current '
'knowledge and do not tell the user about function calls\n')
tool_descs = '\n'.join(tool_descs)
- if system.strip():
- tool_descs = '<|system|>\n' + system.strip() + '\n\n' + tool_descs
return tool_descs
def _format_tool_calls(self, tool_call_messages):
@@ -150,9 +149,7 @@ def _format_tool_calls(self, tool_call_messages):
# For other types, convert to strings
args_value = str(args_value)
result_parts.append(f'{args_value}\n\n')
-
-
-# Close tags
+ # Close tags
result_parts.append('\n')
return ''.join(result_parts)
@@ -160,27 +157,5 @@ def _get_tool_responses(self, tool_messages):
res_tool = []
for tool_message in tool_messages:
tool_content = tool_message['content']
- res_tool.append(f'\n{tool_content}\n')
- return '\n'.join(res_tool) + '\n'
-
- def _format_tool_responses(
- self,
- assistant_content: str,
- tool_messages,
- ) -> Tuple[str, 'Prompt']:
- with_action = self.keyword.action in assistant_content and self.keyword.action_input in assistant_content
- if with_action:
- return super()._format_tool_responses(assistant_content, tool_messages)
- if hasattr(self, 'template_meta'):
- prompt = self.template_meta.prompt
- chat_sep = self.template_meta.chat_sep
- else:
- prompt = ['<|im_start|>user\n{{QUERY}}<|im_end|>\n<|im_start|>assistant\n']
- chat_sep = ['<|im_end|>\n']
- res = chat_sep.copy()
- total_tool = self._get_tool_responses(tool_messages)
- for context in prompt:
- if isinstance(context, str):
- context = context.replace('{{QUERY}}', total_tool)
- res.append(context)
- return assistant_content, res
+ res_tool.append(f'\n{tool_content}\n\n')
+ return ''.join(res_tool)
diff --git a/swift/plugin/agent_template/react.py b/swift/plugin/agent_template/react.py
index 6bfa5b820c..5017e32313 100644
--- a/swift/plugin/agent_template/react.py
+++ b/swift/plugin/agent_template/react.py
@@ -1,12 +1,12 @@
# Copyright (c) Alibaba, Inc. and its affiliates.
-from typing import List, Union
+from typing import List, Optional, Union
from .base import BaseAgentTemplate
class ReactEnAgentTemplate(BaseAgentTemplate):
- def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message=None) -> str:
+ def _format_tools(self, tools: List[Union[str, dict]], system: Optional[str] = None, user_message=None) -> str:
tool_names = []
tool_descs = []
for tool in tools:
@@ -38,7 +38,7 @@ def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message
class ReactZnAgentTemplate(BaseAgentTemplate):
- def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message=None) -> str:
+ def _format_tools(self, tools: List[Union[str, dict]], system: Optional[str] = None, user_message=None) -> str:
tool_names = []
tool_descs = []
for tool in tools:
diff --git a/swift/plugin/agent_template/toolbench.py b/swift/plugin/agent_template/toolbench.py
index 54404e9f8e..1db40b1643 100644
--- a/swift/plugin/agent_template/toolbench.py
+++ b/swift/plugin/agent_template/toolbench.py
@@ -1,5 +1,5 @@
# Copyright (c) Alibaba, Inc. and its affiliates.
-from typing import List, Union
+from typing import List, Optional, Union
import json
@@ -8,7 +8,7 @@
class ToolBenchAgentTemplate(BaseAgentTemplate):
- def _format_tools(self, tools: List[Union[str, dict]], system: str, user_message=None) -> str:
+ def _format_tools(self, tools: List[Union[str, dict]], system: Optional[str] = None, user_message=None) -> str:
for i, tool in enumerate(tools):
tools[i] = self.unwrap_tool(tool)
tools = json.dumps(tools, ensure_ascii=False)
diff --git a/tests/test_align/test_template/test_agent.py b/tests/test_align/test_template/test_agent.py
index a017697ce5..a65dc2b2b3 100644
--- a/tests/test_align/test_template/test_agent.py
+++ b/tests/test_align/test_template/test_agent.py
@@ -355,7 +355,7 @@ def test_glm4_5():
def test_qwen3_coder():
agent_template = agent_templates['qwen3_coder']()
- engine = PtEngine('Qwen/Qwen3-Coder-30B-A3B-Instruct', model_type='qwen3_nothinking')
+ engine = PtEngine('Qwen/Qwen3-Coder-30B-A3B-Instruct')
template = engine.default_template
template.agent_template = agent_template
template.template_backend = 'jinja'
@@ -370,6 +370,11 @@ def test_qwen3_coder():
encoded = template.encode(data)
print(f'input_ids: {template.safe_decode(encoded["input_ids"])}')
print(f'labels: {template.safe_decode(encoded["labels"])}')
+ template.template_backend = 'jinja'
+ encoded2 = template.encode(data)
+ print(f'input_ids: {template.safe_decode(encoded2["input_ids"])}')
+ print(f'labels: {template.safe_decode(encoded2["labels"])}')
+ assert encoded['input_ids'] == encoded2['input_ids'][:-1]
if __name__ == '__main__':