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}' + result += f'\n<{key}>{json.dumps(value, ensure_ascii=False)}' 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__':