@@ -22,7 +22,6 @@ def _find_function_call(single_content: str) -> Optional['Function']:
22
22
matches = pattern .findall (single_content )
23
23
if not matches :
24
24
return
25
-
26
25
name , arguments = matches [0 ]
27
26
return Function (name = name , arguments = arguments )
28
27
@@ -77,3 +76,70 @@ def _format_tool_calls(self, tool_call_messages) -> str:
77
76
78
77
class GLM4_0414AgentTemplate (GLM4AgentTemplate ):
79
78
is_glm4_0414 = True
79
+
80
+
81
+ class GLM4_5AgentTemplate (BaseAgentTemplate ):
82
+
83
+ @staticmethod
84
+ def _find_function_call (single_content : str ) -> Optional ['Function' ]:
85
+ from swift .llm .infer import Function
86
+ single_content = single_content .strip ()
87
+ func_name_match = re .match (r'^([^\n<]+)' , single_content )
88
+ if not func_name_match :
89
+ return None
90
+ func_name = func_name_match .group (1 ).strip ()
91
+ keys = re .findall (r'<arg_key>(.*?)</arg_key>' , single_content , re .DOTALL )
92
+ values = re .findall (r'<arg_value>(.*?)</arg_value>' , single_content , re .DOTALL )
93
+ if len (keys ) != len (values ):
94
+ return None
95
+ args = {k .strip (): v .strip () for k , v in zip (keys , values )}
96
+ return Function (name = func_name , arguments = json .dumps (args , ensure_ascii = False ))
97
+
98
+ def get_toolcall (self , response : str ) -> List ['Function' ]:
99
+ toolcall_list = re .findall (r'<tool_call>(.*?)</tool_call>' , response , re .DOTALL )
100
+ functions = []
101
+ for toolcall in toolcall_list :
102
+ function = self ._find_function_call (toolcall )
103
+ if function :
104
+ functions .append (function )
105
+ if len (functions ) == 0 :
106
+ # compat react_en
107
+ return super ().get_toolcall (response )
108
+ return functions
109
+
110
+ def _format_tools (self , tools : List [Union [str , dict ]], system : str , user_message = None ) -> str :
111
+ tool_descs = [
112
+ '# Tools\n \n You may call one or more functions to assist with the user query.\n \n You are provided with function signatures within <tools></tools> XML tags:\n <tools>'
113
+ ]
114
+ for tool in tools :
115
+ tool_descs .append (f'{ json .dumps (tool , ensure_ascii = False )} ' )
116
+ tool_descs .append ('</tools>\n \n For each function call, output the function name and arguments within the following XML format:\n <tool_call>{function-name}\n <arg_key>{arg-key-1}</arg_key>\n <arg_value>{arg-value-1}</arg_value>\n <arg_key>{arg-key-2}</arg_key>\n <arg_value>{arg-value-2}</arg_value>\n ...\n </tool_call>' )
117
+ tool_descs = '\n ' .join (tool_descs )
118
+ if system .strip ():
119
+ tool_descs += '<|system|>\n ' + system .strip ()
120
+ return tool_descs
121
+
122
+ def _format_tool_responses (
123
+ self ,
124
+ assistant_content : str ,
125
+ tool_messages ,
126
+ ) -> Tuple [str , 'Prompt' ]:
127
+ with_action = self .keyword .action in assistant_content and self .keyword .action_input in assistant_content
128
+ if with_action :
129
+ return super ()._format_tool_responses (assistant_content , tool_messages )
130
+ res = []
131
+ for _ , tool_message in enumerate (tool_messages ):
132
+ tool_content = tool_message ['content' ]
133
+ res .append (f"\n <tool_response>\n { tool_content } \n </tool_response>" )
134
+ res .append ('<|assistant|>\n ' )
135
+ return assistant_content , res
136
+
137
+ def _format_tool_calls (self , tool_call_messages ) -> str :
138
+ tool_calls = []
139
+ for message in tool_call_messages :
140
+ tool_call = self ._parse_tool_call (message ['content' ])
141
+ tool_calls .append (f"<tool_call>{ tool_call ['name' ]} " )
142
+ for arg_key , arg_value in tool_call ["arguments" ].items ():
143
+ tool_calls .append (f"<arg_key>{ arg_key } </arg_key>\n <arg_value>{ arg_value } </arg_value>" )
144
+ tool_calls .append ("</tool_call>" )
145
+ return '\n ' .join (tool_calls ) + '<|observation|>'
0 commit comments