├── LICENSE ├── README.md └── natural-functions-demo.ipynb /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Natural Functions 2 | 3 | Mistral-7B finetuned for function calling! 4 | 5 | [HuggingFace](https://huggingface.co/cfahlgren1/natural-functions) 6 | [Ollama](https://ollama.ai/calebfahlgren/natural-functions) 7 | [HuggingFace GGUF](https://huggingface.co/cfahlgren1/natural-functions-GGUF) 8 | 9 | ### Try Natural Functions on Ollama! 10 | 11 | ```bash 12 | ollama run calebfahlgren/natural-functions 13 | ``` 14 | 15 | ![Ollama Natural Functions](https://pouch.jumpshare.com/preview/ZZCERaAswnBOtGoesf4APEBB280jYQqfpr2Yo1Ff0_yjNcBG3-LdXr80SS7M_WlksMJBct0M9hMbKIJUQ9BzYt78mKKLZcWqWGpguO5JYcY) 16 | 17 | ### System Prompt via Ollama 18 | 19 | Setting System Prompt with Function Definition 20 | You can set the system prompt with /set system with your function definitions. 21 | 22 | ```bash 23 | >>> /set system """ 24 | ... You are a helpful assistant with access to the following functions. Use them if required - 25 | ... { 26 | ... "name": "order_pizza", 27 | ... "description": "Order a pizza with custom toppings", 28 | ... "parameters": { 29 | ... "type": "object", 30 | ... "properties": { 31 | ... "size": { 32 | ... "type": "string", 33 | ... "description": "Size of the pizza (small, medium, large)" 34 | ... }, 35 | ... "crust": { 36 | ... "type": "string", 37 | ... "description": "Type of crust (thin, regular, thick)" 38 | ... }, 39 | ... "toppings": { 40 | ... "type": "array", 41 | ... "items": { 42 | ... "type": "string" 43 | ... }, 44 | ... "description": "List of toppings for the pizza" 45 | ... }, 46 | ... "delivery_address": { 47 | ... "type": "string", 48 | ... "description": "Address where the pizza should be delivered" 49 | ... } 50 | ... }, 51 | ... "required": [ 52 | ... "size", 53 | ... "crust", 54 | ... "toppings", 55 | ... "delivery_address" 56 | ... ] 57 | ... } 58 | ... } 59 | ... """ 60 | ``` -------------------------------------------------------------------------------- /natural-functions-demo.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "%pip install langchain_openai langchain langchain_experimental ollama" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 71, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "from langchain_core.utils.function_calling import convert_to_openai_function\n", 19 | "from langchain.pydantic_v1 import BaseModel, Field\n", 20 | "from langchain.tools import tool" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "metadata": {}, 26 | "source": [ 27 | "# Define your tools!\n", 28 | "\n", 29 | "For this we create a Langchain tool for retrieving weather information and use the `convert_to_openai_function` to create the function definition that we will feed into the model" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 67, 35 | "metadata": {}, 36 | "outputs": [ 37 | { 38 | "data": { 39 | "text/plain": [ 40 | "[{'name': 'get_weather_tool',\n", 41 | " 'description': 'get_weather_tool(location: str) -> str - Get the current weather in a given location',\n", 42 | " 'parameters': {'type': 'object',\n", 43 | " 'properties': {'location': {'description': 'The city and state, e.g. San Francisco, CA',\n", 44 | " 'type': 'string'}},\n", 45 | " 'required': ['location']}}]" 46 | ] 47 | }, 48 | "execution_count": 67, 49 | "metadata": {}, 50 | "output_type": "execute_result" 51 | } 52 | ], 53 | "source": [ 54 | "class SearchInput(BaseModel):\n", 55 | " location: str = Field(description=\"The city and state, \" \"e.g. San Francisco, CA\")\n", 56 | "\n", 57 | "@tool(\"get_weather_tool\", args_schema=SearchInput)\n", 58 | "def get_current_weather(location: str) -> str:\n", 59 | " \"\"\"Get the current weather in a given location\"\"\"\n", 60 | " return {\"location\": location, \"fahrenheit\": 73.4}\n", 61 | "\n", 62 | "tools = [get_current_weather]\n", 63 | "functions = [convert_to_openai_function(t) for t in tools]\n", 64 | "\n", 65 | "functions" 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "# Invoke the Model\n", 73 | "\n", 74 | "Now we can prompt the model and pass the functions 🥳" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": 69, 80 | "metadata": {}, 81 | "outputs": [ 82 | { 83 | "name": "stdout", 84 | "output_type": "stream", 85 | "text": [ 86 | "\n", 87 | "You are a weather assistant with access to these functions -\n", 88 | "[\n", 89 | " {\n", 90 | " \"name\": \"get_weather_tool\",\n", 91 | " \"description\": \"get_weather_tool(location: str) -> str - Get the current weather in a given location\",\n", 92 | " \"parameters\": {\n", 93 | " \"type\": \"object\",\n", 94 | " \"properties\": {\n", 95 | " \"location\": {\n", 96 | " \"description\": \"The city and state, e.g. San Francisco, CA\",\n", 97 | " \"type\": \"string\"\n", 98 | " }\n", 99 | " },\n", 100 | " \"required\": [\n", 101 | " \"location\"\n", 102 | " ]\n", 103 | " }\n", 104 | " }\n", 105 | "]\n", 106 | "\n" 107 | ] 108 | } 109 | ], 110 | "source": [ 111 | "import ollama\n", 112 | "import json\n", 113 | "\n", 114 | "SYSTEM_PROMPT = f\"\"\"\n", 115 | "You are a weather assistant with access to these functions -\n", 116 | "{json.dumps(functions, indent=4)}\n", 117 | "\"\"\"\n", 118 | "\n", 119 | "print (SYSTEM_PROMPT)" 120 | ] 121 | }, 122 | { 123 | "cell_type": "code", 124 | "execution_count": 122, 125 | "metadata": {}, 126 | "outputs": [], 127 | "source": [ 128 | "import json\n", 129 | "import re\n", 130 | "from typing import Optional, Dict\n", 131 | "\n", 132 | "def parse_function_call(input_str: str) -> Optional[Dict[str, any]]:\n", 133 | " \"\"\"\n", 134 | " Parses a text string to find and extract a function call.\n", 135 | " The function call is expected to be in the format:\n", 136 | " {\"name\": \"\", \"arguments\": \"\"}\n", 137 | "\n", 138 | " Args:\n", 139 | " input_str (str): The text containing the function call.\n", 140 | "\n", 141 | " Returns:\n", 142 | " Optional[Dict[str, any]]: A dictionary with 'name' and 'arguments' if a function call is found,\n", 143 | " otherwise None.\n", 144 | " \"\"\"\n", 145 | " # Regex pattern to extract 'name' and 'arguments'\n", 146 | " pattern = r'\"name\":\\s*\"([^\"]+)\",\\s*\"arguments\":\\s*\\'(.*?)\\''\n", 147 | "\n", 148 | " # Search with regex\n", 149 | " match = re.search(pattern, input_str)\n", 150 | " if match:\n", 151 | " try:\n", 152 | " name = match.group(1)\n", 153 | " arguments_str = match.group(2)\n", 154 | "\n", 155 | " # Parse the arguments JSON\n", 156 | " arguments = json.loads(arguments_str)\n", 157 | "\n", 158 | " return {\"name\": name, \"arguments\": arguments}\n", 159 | " except json.JSONDecodeError:\n", 160 | " # If JSON parsing fails, return None\n", 161 | " return None\n", 162 | " return None\n" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": 153, 168 | "metadata": {}, 169 | "outputs": [], 170 | "source": [ 171 | "messages = [\n", 172 | " {'role': 'system','content': SYSTEM_PROMPT}, \n", 173 | " {'role': 'user','content': 'What is the weather like in the Dallas, TX?'},\n", 174 | "]\n", 175 | "\n", 176 | "response = ollama.chat(model='natural-functions', messages=messages)\n", 177 | "message = (response['message']['content'])" 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": 154, 183 | "metadata": {}, 184 | "outputs": [ 185 | { 186 | "data": { 187 | "text/plain": [ 188 | "' {\"name\": \"get_weather_tool\", \"arguments\": \\'{\"location\": \"Dallas, TX\"}\\'}'" 189 | ] 190 | }, 191 | "execution_count": 154, 192 | "metadata": {}, 193 | "output_type": "execute_result" 194 | } 195 | ], 196 | "source": [ 197 | "message" 198 | ] 199 | }, 200 | { 201 | "cell_type": "markdown", 202 | "metadata": {}, 203 | "source": [ 204 | "# Call the Function\n", 205 | "\n", 206 | "Here we pull the function out of `kwargs` and call our tool with the arguments" 207 | ] 208 | }, 209 | { 210 | "cell_type": "code", 211 | "execution_count": 155, 212 | "metadata": {}, 213 | "outputs": [ 214 | { 215 | "data": { 216 | "text/plain": [ 217 | "{'location': 'Dallas, TX', 'fahrenheit': 73.4}" 218 | ] 219 | }, 220 | "execution_count": 155, 221 | "metadata": {}, 222 | "output_type": "execute_result" 223 | } 224 | ], 225 | "source": [ 226 | "messages.append({'role': 'assistant', 'content': message}) # add ai response to history\n", 227 | "\n", 228 | "function_call = parse_function_call(message) # parse out function call name and args into json\n", 229 | "\n", 230 | "if function_call and function_call.get(\"name\") == \"get_weather_tool\":\n", 231 | " args = function_call.get(\"arguments\")\n", 232 | " current_weather = get_current_weather.run(args)\n", 233 | "\n", 234 | "current_weather" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": 156, 240 | "metadata": {}, 241 | "outputs": [ 242 | { 243 | "data": { 244 | "text/plain": [ 245 | "[{'role': 'system',\n", 246 | " 'content': '\\nYou are a weather assistant with access to these functions -\\n[\\n {\\n \"name\": \"get_weather_tool\",\\n \"description\": \"get_weather_tool(location: str) -> str - Get the current weather in a given location\",\\n \"parameters\": {\\n \"type\": \"object\",\\n \"properties\": {\\n \"location\": {\\n \"description\": \"The city and state, e.g. San Francisco, CA\",\\n \"type\": \"string\"\\n }\\n },\\n \"required\": [\\n \"location\"\\n ]\\n }\\n }\\n]\\n'},\n", 247 | " {'role': 'user', 'content': 'What is the weather like in the Dallas, TX?'},\n", 248 | " {'role': 'assistant',\n", 249 | " 'content': ' {\"name\": \"get_weather_tool\", \"arguments\": \\'{\"location\": \"Dallas, TX\"}\\'}'},\n", 250 | " {'role': 'user',\n", 251 | " 'content': \"Function Response: {'location': 'Dallas, TX', 'fahrenheit': 73.4}\"}]" 252 | ] 253 | }, 254 | "execution_count": 156, 255 | "metadata": {}, 256 | "output_type": "execute_result" 257 | } 258 | ], 259 | "source": [ 260 | "messages.append({'role': 'user', 'content': 'Function Response: ' + str(current_weather)})\n", 261 | "messages" 262 | ] 263 | }, 264 | { 265 | "cell_type": "code", 266 | "execution_count": 157, 267 | "metadata": {}, 268 | "outputs": [ 269 | { 270 | "data": { 271 | "text/plain": [ 272 | "'The current weather in Dallas, TX is sunny and the temperature is around 73.4 degrees Fahrenheit'" 273 | ] 274 | }, 275 | "execution_count": 157, 276 | "metadata": {}, 277 | "output_type": "execute_result" 278 | } 279 | ], 280 | "source": [ 281 | "response = ollama.chat(model='natural-functions', messages=messages)\n", 282 | "response['message']['content']" 283 | ] 284 | } 285 | ], 286 | "metadata": { 287 | "kernelspec": { 288 | "display_name": "Python 3", 289 | "language": "python", 290 | "name": "python3" 291 | }, 292 | "language_info": { 293 | "codemirror_mode": { 294 | "name": "ipython", 295 | "version": 3 296 | }, 297 | "file_extension": ".py", 298 | "mimetype": "text/x-python", 299 | "name": "python", 300 | "nbconvert_exporter": "python", 301 | "pygments_lexer": "ipython3", 302 | "version": "3.10.7" 303 | } 304 | }, 305 | "nbformat": 4, 306 | "nbformat_minor": 2 307 | } 308 | --------------------------------------------------------------------------------