Last active
October 4, 2023 07:38
-
-
Save peterroelants/f3508b85b5574576b5f85cd90c721a9d to your computer and use it in GitHub Desktop.
Revisions
-
peterroelants revised this gist
Oct 4, 2023 . 1 changed file with 0 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -14,8 +14,6 @@ - ReAct - https://arxiv.org/abs/2210.03629 - https://peterroelants.github.io/posts/react-repl-agent/ """ import inspect import json -
peterroelants revised this gist
Oct 4, 2023 . 1 changed file with 21 additions and 6 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,11 +1,21 @@ """ Simple example of OpenAI Function Calling in ReAct Loop. Functions are described in JSON with each parameter the function accepts described as a JSON Schema object. More info: - OpenAI Function Calling - https://openai.com/blog/function-calling-and-other-api-updates - https://platform.openai.com/docs/guides/gpt/function-calling - https://platform.openai.com/docs/api-reference/chat/create#chat/create-functions - JSON Schema - https://json-schema.org/ - https://json-schema.org/specification-links#2020-12 - ReAct - https://arxiv.org/abs/2210.03629 - https://peterroelants.github.io/posts/react-repl-agent/ """ import inspect import json @@ -15,6 +25,10 @@ # Functions ######################################################## class StopException(Exception): """ Stop Execution (Task is Finished) """ ... @@ -59,6 +73,7 @@ def calculate(formula): } # The parameters the functions accepts, described as a JSON Schema object. functions = [ { "name": get_current_location.__name__, @@ -122,7 +137,7 @@ def calculate(formula): { "role": "user", "content": "What's the current weather for my location? Give me the temperature in degrees Celsius.\n\nReason step by step which actions to take to get to the answer.", }, ] @@ -250,4 +265,4 @@ def calculate(formula): # "arguments": "{\n \"answer\": \"The current weather for your location is sunny with a temperature of 22.22 degrees Celsius.\"\n}" # } # } # ] -
peterroelants revised this gist
Sep 22, 2023 . 1 changed file with 46 additions and 47 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -192,63 +192,62 @@ def calculate(formula): print(f"messages: {json.dumps(messages, indent=2)}") # [ # { # "role": "system", # "content": "You are a helpful assistant that can answer multi-step questions by sequentially calling functions. Follow a pattern of THOUGHT (reason step-by-step about which function to call next), ACTION (call a function to get closer to the answer), OBSERVATION (output of the function)." # }, # { # "role": "user", # "content": "What's the current weather for my location? Give me the temperature in degrees Celsius.\n\nReason step by step which actions to take to get to the answer." # }, # { # "role": "assistant", # "content": "To get the current weather for the user's location, we need to follow these steps:\n\n1. Get the user's current location.\n2. Retrieve the latitude and longitude coordinates from the user's location.\n3. Use the coordinates to get the current weather.\n4. Extract the temperature from the weather data.\n5. Convert the temperature to degrees Celsius.\n\nNow, let's take these steps one by one and call the appropriate functions to get the answer.", # "function_call": { # "name": "get_current_location", # "arguments": "{}" # } # }, # { # "role": "function", # "name": "get_current_location", # "content": "{\"latitude\": 50.9326, \"longitude\": 5.3426}" # }, # { # "role": "assistant", # "content": null, # "function_call": { # "name": "get_current_weather", # "arguments": "{\n \"latitude\": 50.9326,\n \"longitude\": 5.3426\n}" # } # }, # { # "role": "function", # "name": "get_current_weather", # "content": "{\"location\": [50.9326, 5.3426], \"temperature\": \"72\", \"unit\": \"fahrenheit\", \"forecast\": \"sunny\"}" # }, # { # "role": "assistant", # "content": "The current weather for your location is sunny with a temperature of 72 degrees Fahrenheit. \n\nTo convert the temperature to Celsius, we can use the formula: \n\nCelsius = (Fahrenheit - 32) * 5/9\n\nLet's calculate it.", # "function_call": { # "name": "calculate", # "arguments": "{\n \"formula\": \"(72 - 32) * 5/9\"\n}" # } # }, # { # "role": "function", # "name": "calculate", # "content": "22.22222222222222" # }, # { # "role": "assistant", # "content": "The current temperature in your location is approximately 22.22 degrees Celsius." # }, # { # "role": "assistant", # "content": null, # "function_call": { # "name": "finish", # "arguments": "{\n \"answer\": \"The current weather for your location is sunny with a temperature of 22.22 degrees Celsius.\"\n}" # } # } # ] -
peterroelants revised this gist
Sep 22, 2023 . 1 changed file with 62 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -190,3 +190,65 @@ def calculate(formula): print(f"messages: {json.dumps(messages, indent=2)}") # [ # { # "name": "get_current_location", # "description": "Get the current location of the user", # "parameters": { # "type": "object", # "properties": {}, # "required": [] # } # }, # { # "name": "get_current_weather", # "description": "Get the current weather in a given location", # "parameters": { # "type": "object", # "properties": { # "latitude": { # "type": "number" # }, # "longitude": { # "type": "number" # } # }, # "required": [ # "latitude", # "longitude" # ] # } # }, # { # "name": "calculate", # "description": "Calculate the result of a given formula", # "parameters": { # "type": "object", # "properties": { # "formula": { # "type": "string", # "description": "Formula to compute the result of, in Python syntax." # } # }, # "required": [ # "formula" # ] # } # }, # { # "name": "finish", # "description": "Answer the user's question, and finish the conversation.", # "parameters": { # "type": "object", # "properties": { # "answer": { # "type": "string", # "description": "Text to answer the user with." # } # }, # "required": [ # "answer" # ] # } # } # ] -
peterroelants revised this gist
Sep 22, 2023 . 1 changed file with 0 additions and 61 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,61 +0,0 @@ -
peterroelants revised this gist
Sep 22, 2023 . No changes.There are no files selected for viewing
-
peterroelants revised this gist
Sep 22, 2023 . No changes.There are no files selected for viewing
-
peterroelants revised this gist
Sep 22, 2023 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,4 @@ [ { "role": "system", "content": "You are a helpful assistant that can answer multi-step questions by sequentially calling functions. Follow a pattern of THOUGHT (reason step-by-step about which function to call next), ACTION (call a function to get closer to the answer), OBSERVATION (output of the function)." -
peterroelants created this gist
Sep 22, 2023 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,61 @@ messages: [ { "role": "system", "content": "You are a helpful assistant that can answer multi-step questions by sequentially calling functions. Follow a pattern of THOUGHT (reason step-by-step about which function to call next), ACTION (call a function to get closer to the answer), OBSERVATION (output of the function)." }, { "role": "user", "content": "What's the current weather for my location? Give me the temperature in degrees Celsius.\n\nReason step by step which actions to take to get to the answer." }, { "role": "assistant", "content": "To get the current weather for the user's location, we need to follow these steps:\n\n1. Get the user's current location.\n2. Retrieve the latitude and longitude coordinates from the user's location.\n3. Use the coordinates to get the current weather.\n4. Extract the temperature from the weather data.\n5. Convert the temperature to degrees Celsius.\n\nNow, let's take these steps one by one and call the appropriate functions to get the answer.", "function_call": { "name": "get_current_location", "arguments": "{}" } }, { "role": "function", "name": "get_current_location", "content": "{\"latitude\": 50.9326, \"longitude\": 5.3426}" }, { "role": "assistant", "content": null, "function_call": { "name": "get_current_weather", "arguments": "{\n \"latitude\": 50.9326,\n \"longitude\": 5.3426\n}" } }, { "role": "function", "name": "get_current_weather", "content": "{\"location\": [50.9326, 5.3426], \"temperature\": \"72\", \"unit\": \"fahrenheit\", \"forecast\": \"sunny\"}" }, { "role": "assistant", "content": "The current weather for your location is sunny with a temperature of 72 degrees Fahrenheit. \n\nTo convert the temperature to Celsius, we can use the formula: \n\nCelsius = (Fahrenheit - 32) * 5/9\n\nLet's calculate it.", "function_call": { "name": "calculate", "arguments": "{\n \"formula\": \"(72 - 32) * 5/9\"\n}" } }, { "role": "function", "name": "calculate", "content": "22.22222222222222" }, { "role": "assistant", "content": "The current temperature in your location is approximately 22.22 degrees Celsius." }, { "role": "assistant", "content": null, "function_call": { "name": "finish", "arguments": "{\n \"answer\": \"The current weather for your location is sunny with a temperature of 22.22 degrees Celsius.\"\n}" } } ] This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,192 @@ """ Simple example of OpenAI Function Calling in ReAct Loop. More info: - https://openai.com/blog/function-calling-and-other-api-updates - https://platform.openai.com/docs/guides/gpt/function-calling - https://arxiv.org/abs/2210.03629 - https://peterroelants.github.io/posts/react-repl-agent/ """ import inspect import json import openai # Functions ######################################################## class StopException(Exception): ... def finish(answer): """Answer the user's question, and finish the conversation.""" raise StopException(answer) def get_current_location(): """Get the current location of the user""" # Mocked for the sake of the example return json.dumps( { "latitude": 50.9326, "longitude": 5.34260, } ) def get_current_weather(latitude, longitude): """Get the current weather in a given location""" # Mocked for the sake of the example weather_info = { "location": (latitude, longitude), "temperature": "72", "unit": "fahrenheit", "forecast": "sunny", } return json.dumps(weather_info) def calculate(formula): """Calculate the result of a given formula""" return str(eval(formula)) name_to_function_map = { get_current_location.__name__: get_current_location, get_current_weather.__name__: get_current_weather, calculate.__name__: calculate, finish.__name__: finish, } functions = [ { "name": get_current_location.__name__, "description": inspect.getdoc(get_current_location).strip(), "parameters": { "type": "object", "properties": {}, "required": [], }, }, { "name": get_current_weather.__name__, "description": inspect.getdoc(get_current_weather).strip(), "parameters": { "type": "object", "properties": { "latitude": {"type": "number"}, "longitude": {"type": "number"}, }, "required": ["latitude", "longitude"], }, }, { "name": calculate.__name__, "description": inspect.getdoc(calculate).strip(), "parameters": { "type": "object", "properties": { "formula": { "type": "string", "description": "Formula to compute the result of, in Python syntax.", }, }, "required": ["formula"], }, }, { "name": finish.__name__, "description": inspect.getdoc(finish).strip(), "parameters": { "type": "object", "properties": { "answer": { "type": "string", "description": "Text to answer the user with.", }, }, "required": ["answer"], }, }, ] # Function Calling in loop ######################################### # Initial "chat" messages messages = [ { "role": "system", "content": "You are a helpful assistant that can answer multi-step questions by sequentially calling functions. Follow a pattern of THOUGHT (reason step-by-step about which function to call next), ACTION (call a function to get closer to the answer), OBSERVATION (output of the function).", }, { "role": "user", "content": "What's the current weather for my location? Give me the temperature in degrees Celsius.\n\nReason step by step which actions to take to get to the answer.", } ] # Run in loop max_iterations = 20 for i in range(max_iterations): print(f"\n\n# Iteration {i}:") # Call OpenAI's API to get the next message response = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=messages, functions=functions, function_call="auto", ) response_message = response["choices"][0]["message"] # Extend conversation with assistant's reply messages.append(response_message.to_dict()) # Check if GPT wanted to call a function if response_message.get("function_call"): function_call_message = response_message["function_call"] print(f"function_call_message={json.dumps(function_call_message, indent=2)}") # Call the function function_name = function_call_message["name"] function_to_call = name_to_function_map[function_name] function_args = function_call_message["arguments"] try: function_args_dict = json.loads(function_args) except json.JSONDecodeError as exc: # JSON decoding failed print(f"Error decoding function arguments: {exc}") messages.append( { "role": "function", "name": function_name, "content": f"Error decoding function arguments {function_args!r}! Error: {exc}", } ) continue try: function_response = function_to_call(**function_args_dict) except StopException as exc: # Agent wants to stop the conversation (Expected) print(f"Stopping conversation: {exc}") break except Exception as exc: # Unexpected error calling function print(f"Error calling function {function_name}: {exc}") messages.append( { "role": "function", "name": function_name, "content": f"Error calling function {function_name}: {exc}!", } ) continue print(f"{function_response=}") # Extend conversation with function response messages.append( { "role": "function", "name": function_name, "content": function_response, } ) print(f"messages: {json.dumps(messages, indent=2)}")