Przeglądaj źródła

refac: tool calls

Timothy Jaeryang Baek 2 miesięcy temu
rodzic
commit
642a093d02

+ 22 - 1
backend/open_webui/config.py

@@ -1283,7 +1283,28 @@ TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE = PersistentConfig(
 )
 
 
-DEFAULT_TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE = """Available Tools: {{TOOLS}}\nReturn an empty string if no tools match the query. If a function tool matches, construct and return a JSON object in the format {\"name\": \"functionName\", \"parameters\": {\"requiredFunctionParamKey\": \"requiredFunctionParamValue\"}} using the appropriate tool and its parameters. Only return the object and limit the response to the JSON object without additional text."""
+DEFAULT_TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE = """Available Tools: {{TOOLS}}
+
+Your task is to choose and return the correct tool(s) from the list of available tools based on the query. Follow these guidelines:
+
+- Return only the JSON object, without any additional text or explanation.
+
+- If no tools match the query, return an empty array: 
+   {
+     "tool_calls": []
+   }
+
+- If one or more tools match the query, construct a JSON response containing a "tool_calls" array with objects that include:
+   - "name": The tool's name.
+   - "parameters": A dictionary of required parameters and their corresponding values.
+
+The format for the JSON response is strictly:
+{
+  "tool_calls": [
+    {"name": "toolName1", "parameters": {"key1": "value1"}},
+    {"name": "toolName2", "parameters": {"key2": "value2"}}
+  ]
+}"""
 
 
 DEFAULT_EMOJI_GENERATION_PROMPT_TEMPLATE = """Your task is to reflect the speaker's likely facial expression through a fitting emoji. Interpret emotions from the message and reflect their facial expression using fitting, diverse emojis (e.g., 😊, 😢, 😡, 😱).

+ 59 - 49
backend/open_webui/utils/middleware.py

@@ -270,60 +270,70 @@ async def chat_completion_tools_handler(
 
             result = json.loads(content)
 
-            tool_function_name = result.get("name", None)
-            if tool_function_name not in tools:
-                return body, {}
+            async def tool_call_handler(tool_call):
+                log.debug(f"{tool_call=}")
 
-            tool_function_params = result.get("parameters", {})
+                tool_function_name = tool_call.get("name", None)
+                if tool_function_name not in tools:
+                    return body, {}
 
-            try:
-                required_params = (
-                    tools[tool_function_name]
-                    .get("spec", {})
-                    .get("parameters", {})
-                    .get("required", [])
-                )
-                tool_function = tools[tool_function_name]["callable"]
-                tool_function_params = {
-                    k: v
-                    for k, v in tool_function_params.items()
-                    if k in required_params
-                }
-                tool_output = await tool_function(**tool_function_params)
+                tool_function_params = tool_call.get("parameters", {})
 
-            except Exception as e:
-                tool_output = str(e)
-
-            if isinstance(tool_output, str):
-                if tools[tool_function_name]["citation"]:
-                    sources.append(
-                        {
-                            "source": {
-                                "name": f"TOOL:{tools[tool_function_name]['toolkit_id']}/{tool_function_name}"
-                            },
-                            "document": [tool_output],
-                            "metadata": [
-                                {
-                                    "source": f"TOOL:{tools[tool_function_name]['toolkit_id']}/{tool_function_name}"
-                                }
-                            ],
-                        }
-                    )
-                else:
-                    sources.append(
-                        {
-                            "source": {},
-                            "document": [tool_output],
-                            "metadata": [
-                                {
-                                    "source": f"TOOL:{tools[tool_function_name]['toolkit_id']}/{tool_function_name}"
-                                }
-                            ],
-                        }
+                try:
+                    required_params = (
+                        tools[tool_function_name]
+                        .get("spec", {})
+                        .get("parameters", {})
+                        .get("required", [])
                     )
+                    tool_function = tools[tool_function_name]["callable"]
+                    tool_function_params = {
+                        k: v
+                        for k, v in tool_function_params.items()
+                        if k in required_params
+                    }
+                    tool_output = await tool_function(**tool_function_params)
+
+                except Exception as e:
+                    tool_output = str(e)
+
+                if isinstance(tool_output, str):
+                    if tools[tool_function_name]["citation"]:
+                        sources.append(
+                            {
+                                "source": {
+                                    "name": f"TOOL:{tools[tool_function_name]['toolkit_id']}/{tool_function_name}"
+                                },
+                                "document": [tool_output],
+                                "metadata": [
+                                    {
+                                        "source": f"TOOL:{tools[tool_function_name]['toolkit_id']}/{tool_function_name}"
+                                    }
+                                ],
+                            }
+                        )
+                    else:
+                        sources.append(
+                            {
+                                "source": {},
+                                "document": [tool_output],
+                                "metadata": [
+                                    {
+                                        "source": f"TOOL:{tools[tool_function_name]['toolkit_id']}/{tool_function_name}"
+                                    }
+                                ],
+                            }
+                        )
 
-                if tools[tool_function_name]["file_handler"]:
-                    skip_files = True
+                    if tools[tool_function_name]["file_handler"]:
+                        skip_files = True
+
+            # check if "tool_calls" in result
+            if result.get("tool_calls"):
+                for tool_call in result.get("tool_calls"):
+                    await tool_call_handler(tool_call)
+            else:
+                await tool_call_handler(result)
 
         except Exception as e:
             log.exception(f"Error: {e}")

+ 16 - 1
src/lib/components/admin/Settings/Interface.svelte

@@ -31,7 +31,8 @@
 		ENABLE_TAGS_GENERATION: true,
 		ENABLE_SEARCH_QUERY_GENERATION: true,
 		ENABLE_RETRIEVAL_QUERY_GENERATION: true,
-		QUERY_GENERATION_PROMPT_TEMPLATE: ''
+		QUERY_GENERATION_PROMPT_TEMPLATE: '',
+		TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE: ''
 	};
 
 	let promptSuggestions = [];
@@ -251,6 +252,20 @@
 				</div>
 			</div>
 
+			<div class="mt-3">
+				<div class=" mb-2.5 text-xs font-medium">{$i18n.t('Tools Function Calling Prompt')}</div>
+
+				<Tooltip
+					content={$i18n.t('Leave empty to use the default prompt, or enter a custom prompt')}
+					placement="top-start"
+				>
+					<Textarea
+						bind:value={taskConfig.TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE}
+						placeholder={$i18n.t('Leave empty to use the default prompt, or enter a custom prompt')}
+					/>
+				</Tooltip>
+			</div>
+
 			<hr class=" border-gray-50 dark:border-gray-850 my-3" />
 
 			<div class=" space-y-3 {banners.length > 0 ? ' mb-3' : ''}">

+ 6 - 6
svelte.config.js

@@ -17,12 +17,12 @@ const config = {
 		})
 	},
 	vitePlugin: {
-		inspector: {
-			toggleKeyCombo: 'meta-shift', // Key combination to open the inspector
-			holdMode: false, // Enable or disable hold mode
-			showToggleButton: 'always', // Show toggle button ('always', 'active', 'never')
-			toggleButtonPos: 'bottom-right' // Position of the toggle button
-		}
+		// inspector: {
+		// 	toggleKeyCombo: 'meta-shift', // Key combination to open the inspector
+		// 	holdMode: false, // Enable or disable hold mode
+		// 	showToggleButton: 'always', // Show toggle button ('always', 'active', 'never')
+		// 	toggleButtonPos: 'bottom-right' // Position of the toggle button
+		// }
 	},
 	onwarn: (warning, handler) => {
 		const { code } = warning;