mirror of
https://github.com/ggerganov/llama.cpp.git
synced 2024-12-25 05:48:47 +01:00
examples : add complete parallel function calling example (#4974)
This commit is contained in:
parent
959ef0c0df
commit
4feb4b33ee
@ -1,5 +1,5 @@
|
|||||||
# Function calling example using pydantic models.
|
# Function calling example using pydantic models.
|
||||||
|
import datetime
|
||||||
import json
|
import json
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Union, Optional
|
from typing import Union, Optional
|
||||||
@ -8,7 +8,8 @@ import requests
|
|||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
import importlib
|
import importlib
|
||||||
from pydantic_models_to_grammar import generate_gbnf_grammar_and_documentation
|
from pydantic_models_to_grammar import generate_gbnf_grammar_and_documentation, convert_dictionary_to_pydantic_model, add_run_method_to_dynamic_model, create_dynamic_model_from_function
|
||||||
|
|
||||||
|
|
||||||
# Function to get completion on the llama.cpp server with grammar.
|
# Function to get completion on the llama.cpp server with grammar.
|
||||||
def create_completion(prompt, grammar):
|
def create_completion(prompt, grammar):
|
||||||
@ -134,3 +135,121 @@ text = create_completion(prompt=prompt, grammar=gbnf_grammar)
|
|||||||
json_data = json.loads(text)
|
json_data = json.loads(text)
|
||||||
|
|
||||||
print(Book(**json_data))
|
print(Book(**json_data))
|
||||||
|
# An example for parallel function calling with a Python function, a pydantic function model and an OpenAI like function definition.
|
||||||
|
|
||||||
|
def get_current_datetime(output_format: Optional[str] = None):
|
||||||
|
"""
|
||||||
|
Get the current date and time in the given format.
|
||||||
|
Args:
|
||||||
|
output_format: formatting string for the date and time, defaults to '%Y-%m-%d %H:%M:%S'
|
||||||
|
"""
|
||||||
|
if output_format is None:
|
||||||
|
output_format = '%Y-%m-%d %H:%M:%S'
|
||||||
|
return datetime.datetime.now().strftime(output_format)
|
||||||
|
|
||||||
|
|
||||||
|
# Enum for the calculator tool.
|
||||||
|
class MathOperation(Enum):
|
||||||
|
ADD = "add"
|
||||||
|
SUBTRACT = "subtract"
|
||||||
|
MULTIPLY = "multiply"
|
||||||
|
DIVIDE = "divide"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Simple pydantic calculator tool for the agent that can add, subtract, multiply, and divide. Docstring and description of fields will be used in system prompt.
|
||||||
|
class Calculator(BaseModel):
|
||||||
|
"""
|
||||||
|
Perform a math operation on two numbers.
|
||||||
|
"""
|
||||||
|
number_one: Union[int, float] = Field(..., description="First number.")
|
||||||
|
operation: MathOperation = Field(..., description="Math operation to perform.")
|
||||||
|
number_two: Union[int, float] = Field(..., description="Second number.")
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
if self.operation == MathOperation.ADD:
|
||||||
|
return self.number_one + self.number_two
|
||||||
|
elif self.operation == MathOperation.SUBTRACT:
|
||||||
|
return self.number_one - self.number_two
|
||||||
|
elif self.operation == MathOperation.MULTIPLY:
|
||||||
|
return self.number_one * self.number_two
|
||||||
|
elif self.operation == MathOperation.DIVIDE:
|
||||||
|
return self.number_one / self.number_two
|
||||||
|
else:
|
||||||
|
raise ValueError("Unknown operation.")
|
||||||
|
|
||||||
|
|
||||||
|
# Example function to get the weather
|
||||||
|
def get_current_weather(location, unit):
|
||||||
|
"""Get the current weather in a given location"""
|
||||||
|
if "London" in location:
|
||||||
|
return json.dumps({"location": "London", "temperature": "42", "unit": unit.value})
|
||||||
|
elif "New York" in location:
|
||||||
|
return json.dumps({"location": "New York", "temperature": "24", "unit": unit.value})
|
||||||
|
elif "North Pole" in location:
|
||||||
|
return json.dumps({"location": "North Pole", "temperature": "-42", "unit": unit.value})
|
||||||
|
else:
|
||||||
|
return json.dumps({"location": location, "temperature": "unknown"})
|
||||||
|
|
||||||
|
|
||||||
|
# Here is a function definition in OpenAI style
|
||||||
|
current_weather_tool = {
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "get_current_weather",
|
||||||
|
"description": "Get the current weather in a given location",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"location": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The city and state, e.g. San Francisco, CA",
|
||||||
|
},
|
||||||
|
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
|
||||||
|
},
|
||||||
|
"required": ["location"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# Convert OpenAI function definition into pydantic model
|
||||||
|
current_weather_tool_model = convert_dictionary_to_pydantic_model(current_weather_tool)
|
||||||
|
# Add the actual function to a pydantic model
|
||||||
|
current_weather_tool_model = add_run_method_to_dynamic_model(current_weather_tool_model, get_current_weather)
|
||||||
|
|
||||||
|
# Convert normal Python function to a pydantic model
|
||||||
|
current_datetime_model = create_dynamic_model_from_function(get_current_datetime)
|
||||||
|
|
||||||
|
tool_list = [SendMessageToUser, Calculator, current_datetime_model, current_weather_tool_model]
|
||||||
|
|
||||||
|
|
||||||
|
gbnf_grammar, documentation = generate_gbnf_grammar_and_documentation(
|
||||||
|
pydantic_model_list=tool_list, outer_object_name="function",
|
||||||
|
outer_object_content="params", model_prefix="Function", fields_prefix="Parameters", list_of_outputs=True)
|
||||||
|
|
||||||
|
system_message = "You are an advanced AI assistant. You are interacting with the user and with your environment by calling functions. You call functions by writing JSON objects, which represent specific function calls.\nBelow is a list of your available function calls:\n\n" + documentation
|
||||||
|
|
||||||
|
|
||||||
|
text = """Get the date and time, get the current weather in celsius in London and solve the following calculation: 42 * 42"""
|
||||||
|
prompt = f"<|im_start|>system\n{system_message}<|im_end|>\n<|im_start|>user\n{text}<|im_end|>\n<|im_start|>assistant"
|
||||||
|
|
||||||
|
text = create_completion(prompt=prompt, grammar=gbnf_grammar)
|
||||||
|
|
||||||
|
json_data = json.loads(text)
|
||||||
|
|
||||||
|
print(json_data)
|
||||||
|
# Should output something like this:
|
||||||
|
# [{'function': 'get_current_datetime', 'params': {'output_format': '%Y-%m-%d %H:%M:%S'}}, {'function': 'get_current_weather', 'params': {'location': 'London', 'unit': 'celsius'}}, {'function': 'Calculator', 'params': {'number_one': 42, 'operation': 'multiply', 'number_two': 42}}]
|
||||||
|
|
||||||
|
|
||||||
|
for call in json_data:
|
||||||
|
if call["function"] == "Calculator":
|
||||||
|
print(Calculator(**call["params"]).run())
|
||||||
|
elif call["function"] == "get_current_datetime":
|
||||||
|
print(current_datetime_model(**call["params"]).run())
|
||||||
|
elif call["function"] == "get_current_weather":
|
||||||
|
print(current_weather_tool_model(**call["params"]).run())
|
||||||
|
# Should output something like this:
|
||||||
|
# 2024-01-14 13:36:06
|
||||||
|
# {"location": "London", "temperature": "42", "unit": "celsius"}
|
||||||
|
# 1764
|
||||||
|
Loading…
Reference in New Issue
Block a user