Function Calling
Introduction to Prompt Engineering II (Function calling)¶
Below we are loading the necessary libraries, utilities, and configurations.
In [ ]:
Copied!
# !pip install openai
# !pip install python-dotenv
# !pip install rich
# !pip install requests
# !pip install openai
# !pip install python-dotenv
# !pip install rich
# !pip install requests
In [18]:
Copied!
import os
import openai
import requests
from rich import print
from dotenv import load_dotenv
import json
load_dotenv()
local_api_key = os.getenv("GROQ_API_KEY")
# openai.api_key = os.getenv("GROQ_API_KEY")
client = openai.OpenAI(
base_url="https://api.groq.com/openai/v1",
api_key=local_api_key
)
import os
import openai
import requests
from rich import print
from dotenv import load_dotenv
import json
load_dotenv()
local_api_key = os.getenv("GROQ_API_KEY")
# openai.api_key = os.getenv("GROQ_API_KEY")
client = openai.OpenAI(
base_url="https://api.groq.com/openai/v1",
api_key=local_api_key
)
In [10]:
Copied!
def get_completion(messages, model="llama-3.2-90b-text-preview", temperature=0, max_tokens=300, tools=None):
response = client.chat.completions.create(
model=model,
messages=messages,
temperature=temperature,
max_tokens=max_tokens,
tools=tools
)
return response.choices[0].message
def get_completion(messages, model="llama-3.2-90b-text-preview", temperature=0, max_tokens=300, tools=None):
response = client.chat.completions.create(
model=model,
messages=messages,
temperature=temperature,
max_tokens=max_tokens,
tools=tools
)
return response.choices[0].message
Adding two numbers¶
In [11]:
Copied!
## Define Function
def add_numbers(number_1 , number_2):
"""
returns the sum of two numbers
"""
return int(number_1) + int(number_2)
## Define Function
def add_numbers(number_1 , number_2):
"""
returns the sum of two numbers
"""
return int(number_1) + int(number_2)
In [12]:
Copied!
add_tool = [
{
"type": "function",
"function": {
"name": "add_numbers",
"description": "Adds two numbers and returns the sum",
"parameters": {
"type": "object",
"properties": {
"number_1": {
"type": "number",
"description": "The first number to add",
},
"number_2": {
"type": "number",
"description": "The second number to add",
},
},
"required": ["number_1", "number_2"],
},
},
}
]
add_tool = [
{
"type": "function",
"function": {
"name": "add_numbers",
"description": "Adds two numbers and returns the sum",
"parameters": {
"type": "object",
"properties": {
"number_1": {
"type": "number",
"description": "The first number to add",
},
"number_2": {
"type": "number",
"description": "The second number to add",
},
},
"required": ["number_1", "number_2"],
},
},
}
]
In [13]:
Copied!
messages = [
{
"role": "user",
"content": "add 66034 and 39385"
}
]
messages = [
{
"role": "user",
"content": "add 66034 and 39385"
}
]
Without Using Function Calling¶
In [14]:
Copied!
response = get_completion(messages)
print(response)
response = get_completion(messages)
print(response)
ChatCompletionMessage( content='66034 + 39385 = 105419.', refusal=None, role='assistant', function_call=None, tool_calls=None )
Using Function Calling¶
In [15]:
Copied!
response = get_completion(messages, tools=add_tool)
print(response)
response = get_completion(messages, tools=add_tool)
print(response)
ChatCompletionMessage( content=None, refusal=None, role='assistant', function_call=None, tool_calls=[ ChatCompletionMessageToolCall( id='call_t6e8', function=Function(arguments='{"number_1": 66034, "number_2": 39385}', name='add_numbers'), type='function' ) ] )
In [17]:
Copied!
args = json.loads(response.tool_calls[0].function.arguments)
print(args)
print(add_numbers(**args))
args = json.loads(response.tool_calls[0].function.arguments)
print(args)
print(add_numbers(**args))
{'number_1': 66034, 'number_2': 39385}
105419
Counting the number of "r" in strawberry¶
In [19]:
Copied!
def count_letters_in_word(word:str , letter:str):
"""
returns the number of letters in word
for example word = strawberry and letter = r
it will return 3
"""
count = 0
for i in word:
if i == letter:
count += 1
return count
def count_letters_in_word(word:str , letter:str):
"""
returns the number of letters in word
for example word = strawberry and letter = r
it will return 3
"""
count = 0
for i in word:
if i == letter:
count += 1
return count
In [32]:
Copied!
count_letters_in_word("strawberry", "r")
count_letters_in_word("strawberry", "r")
Out[32]:
3
In [33]:
Copied!
counter_tool = [
{
"type": "function",
"function": {
"name": "count_letters_in_word",
"description": "counts the number of a specific letter in a given word or string",
"parameters": {
"type": "object",
"properties": {
"word": {
"type": "string",
"description": "The word",
},
"letter": {
"type": "string",
"description": "the letter",
},
},
"required": ["word", "letter"],
},
},
}
]
counter_tool = [
{
"type": "function",
"function": {
"name": "count_letters_in_word",
"description": "counts the number of a specific letter in a given word or string",
"parameters": {
"type": "object",
"properties": {
"word": {
"type": "string",
"description": "The word",
},
"letter": {
"type": "string",
"description": "the letter",
},
},
"required": ["word", "letter"],
},
},
}
]
In [34]:
Copied!
messages = [
{
"role": "user",
"content": "Counting the number of 'r' in strawberry"
}
]
messages = [
{
"role": "user",
"content": "Counting the number of 'r' in strawberry"
}
]
Without function calling¶
In [35]:
Copied!
response = get_completion(messages)
print(response)
response = get_completion(messages)
print(response)
ChatCompletionMessage( content='There are 2 \'r\'s in the word "strawberry"', refusal=None, role='assistant', function_call=None, tool_calls=None )
With funciton calling¶
In [36]:
Copied!
response = get_completion(messages, tools=counter_tool)
print(response)
response = get_completion(messages, tools=counter_tool)
print(response)
ChatCompletionMessage( content=None, refusal=None, role='assistant', function_call=None, tool_calls=[ ChatCompletionMessageToolCall( id='call_gvn1', function=Function(arguments='{"word": "strawberry", "letter": "r"}', name='count_letters_in_word'), type='function' ) ] )
In [38]:
Copied!
args = json.loads(response.tool_calls[0].function.arguments)
print(count_letters_in_word(**args))
args = json.loads(response.tool_calls[0].function.arguments)
print(count_letters_in_word(**args))
3
Getting Current Weather¶
please get you api key from openweathermap
In [21]:
Copied!
def get_current_weather(location):
API_KEY = "YOUR_API_KEY"
url = f"https://api.openweathermap.org/data/2.5/weather?q={location}&appid={API_KEY}"
response = requests.get(url)
data = response.json()
# Extract the temperature in Kelvin
kelvin_temp = data['main']['temp']
# Convert Kelvin to Celsius
celsius_temp = kelvin_temp - 273.15
return {"location": location, "temperature": round(celsius_temp, 2)}
def get_current_weather(location):
API_KEY = "YOUR_API_KEY"
url = f"https://api.openweathermap.org/data/2.5/weather?q={location}&appid={API_KEY}"
response = requests.get(url)
data = response.json()
# Extract the temperature in Kelvin
kelvin_temp = data['main']['temp']
# Convert Kelvin to Celsius
celsius_temp = kelvin_temp - 273.15
return {"location": location, "temperature": round(celsius_temp, 2)}
In [24]:
Copied!
get_weather_tools = [
{
"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",
},
},
"required": ["location"],
}
}
}
]
get_weather_tools = [
{
"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",
},
},
"required": ["location"],
}
}
}
]
In [27]:
Copied!
messages = [
{
"role": "user",
"content": "What's the weather like in Jakarta?"
}
]
messages = [
{
"role": "user",
"content": "What's the weather like in Jakarta?"
}
]
In [28]:
Copied!
response = get_completion(messages, tools=get_weather_tools)
print(response)
response = get_completion(messages, tools=get_weather_tools)
print(response)
ChatCompletionMessage( content=None, refusal=None, role='assistant', function_call=None, tool_calls=[ ChatCompletionMessageToolCall( id='call_q0ny', function=Function(arguments='{"location": "Jakarta"}', name='get_current_weather'), type='function' ) ] )
In [30]:
Copied!
args = json.loads(response.tool_calls[0].function.arguments)
print(args)
args = json.loads(response.tool_calls[0].function.arguments)
print(args)
{'location': 'Jakarta'}
In [ ]:
Copied!
## Will only work if api key is added
get_current_weather(**args)
## Will only work if api key is added
get_current_weather(**args)
Duck Duck Go Search¶
In [ ]:
Copied!
# !pip install -U duckduckgo_search
# !pip install -U duckduckgo_search
In [5]:
Copied!
from duckduckgo_search import DDGS
results = DDGS().text("Python Programming", max_results=5)
print(results)
from duckduckgo_search import DDGS
results = DDGS().text("Python Programming", max_results=5)
print(results)
[ { 'title': 'Welcome to Python.org', 'href': 'https://www.python.org/', 'body': 'The mission of the Python Software Foundation is to promote, protect, and advance the Python programming language, and to support and facilitate the growth of a diverse and international community of Python programmers. Learn more. Become a Member Donate to the PSF. The official home of the Python Programming Language.' }, { 'title': 'Python For Beginners | Python.org', 'href': 'https://www.python.org/about/gettingstarted/', 'body': 'Learn how to get started with Python, a popular and easy-to-use programming language. Find out how to install, edit, and use Python, and explore its libraries, documentation, and community resources.' }, { 'title': 'Python Tutorial - W3Schools', 'href': 'https://www.w3schools.com/python/', 'body': 'W3Schools offers a comprehensive and interactive Python tutorial with examples, exercises, quizzes, and references. You can also download Python and get certified by completing the PYTHON course.' }, { 'title': 'The Python Tutorial — Python 3.13.0 documentation', 'href': 'https://docs.python.org/3/tutorial/index.html', 'body': 'This tutorial introduces the basic concepts and features of the Python language and system, with examples and exercises. It covers topics such as data structures, modules, classes, exceptions, and more.' }, { 'title': 'Python (programming language) - Wikipedia', 'href': 'https://en.wikipedia.org/wiki/Python_(programming_language)', 'body': 'Python is a high-level, general-purpose programming language.Its design philosophy emphasizes code readability with the use of significant indentation. [32]Python is dynamically typed and garbage-collected.It supports multiple programming paradigms, including structured (particularly procedural), object-oriented and functional programming.It is often described as a "batteries included ...' } ]
In [49]:
Copied!
## Creating a function around duck duck go search
def web_search(search_query : str, max_results):
try:
from duckduckgo_search import DDGS
except:
assert "duckduckgo_search package not found please install using `pip install -U duckduckgo_search` "
results = DDGS().text(search_query, max_results=int(max_results))
return results
## Creating a function around duck duck go search
def web_search(search_query : str, max_results):
try:
from duckduckgo_search import DDGS
except:
assert "duckduckgo_search package not found please install using `pip install -U duckduckgo_search` "
results = DDGS().text(search_query, max_results=int(max_results))
return results
In [50]:
Copied!
websearch_tool = [
{
"type": "function",
"function": {
"name": "web_search",
"description": "searches the web and returns top k results",
"parameters": {
"type": "object",
"properties": {
"search_query": {
"type": "string",
"description": "The most optimal search query that will go into the search engine",
},
"max_results": {
"type": "integer",
"description": "the number of results based on complexity of query",
},
},
"required": ["search_query"],
},
},
}
]
websearch_tool = [
{
"type": "function",
"function": {
"name": "web_search",
"description": "searches the web and returns top k results",
"parameters": {
"type": "object",
"properties": {
"search_query": {
"type": "string",
"description": "The most optimal search query that will go into the search engine",
},
"max_results": {
"type": "integer",
"description": "the number of results based on complexity of query",
},
},
"required": ["search_query"],
},
},
}
]
In [51]:
Copied!
messages = [
{
"role": "user",
"content": "what is Nvidia current Stock Price"
}
]
messages = [
{
"role": "user",
"content": "what is Nvidia current Stock Price"
}
]
Without Function Calling¶
In [52]:
Copied!
response = get_completion(messages)
print(response)
response = get_completion(messages)
print(response)
ChatCompletionMessage( content="I'm not able to provide real-time information or current stock prices. However, I can suggest some ways for you to find the current stock price of Nvidia.\n\n1. **Check online stock market platforms**: You can check websites like Yahoo Finance, Google Finance, or Bloomberg to get the current stock price of Nvidia (NVDA).\n2. **Use a stock market app**: You can download a stock market app like Robinhood, Fidelity, or E\\*TRADE to get real-time stock prices.\n3. **Visit Nvidia's investor relations website**: Nvidia's investor relations website may also provide information on the company's current stock price.\n\nPlease note that stock prices can fluctuate rapidly and may be different by the time you check.", refusal=None, role='assistant', function_call=None, tool_calls=None )
With Function Calling¶
In [53]:
Copied!
response = get_completion(messages , tools=websearch_tool)
args = json.loads(response.tool_calls[0].function.arguments)
print(args)
response = get_completion(messages , tools=websearch_tool)
args = json.loads(response.tool_calls[0].function.arguments)
print(args)
{'search_query': 'Nvidia current stock price', 'max_results': '1'}
In [54]:
Copied!
print(web_search(**args))
print(web_search(**args))
[ { 'title': 'NVIDIA Corporation (NVDA) Stock Price, News, Quote & History - Yahoo ...', 'href': 'https://finance.yahoo.com/quote/NVDA/', 'body': 'Find the latest NVIDIA Corporation (NVDA) stock quote, history, news and other vital information to help you with your stock trading and investing. ... Current Quarterly Annual . As of 10/14/2024 ...' } ]
Try it Out Your Self¶
- Create a simple calculator that can handle multiple opration and varied number of inputs
- Create a Units converter that can handle multiple standard units (m , cm , km , kg , liter ...).
In [57]:
Copied!
def calculate(operation, *numbers):
"""
Perform a calculation on a variable number of inputs.
:param operation: String indicating the operation ('add', 'subtract', 'multiply', 'divide')
:param numbers: Variable number of numeric inputs
:return: Result of the calculation
"""
if not numbers:
return "Error: No numbers provided"
result = numbers[0]
for num in numbers[1:]:
if operation == 'add':
result += num
elif operation == 'subtract':
result -= num
elif operation == 'multiply':
result *= num
elif operation == 'divide':
if num == 0:
return "Error: Division by zero"
result /= num
else:
return "Error: Invalid operation"
return result
# Function schema for the calculator
calculator_tool = [
{
"type": "function",
"function": {
"name": "calculate",
"description": "Perform a calculation on multiple numbers",
"parameters": {
"type": "object",
"properties": {
"operation": {
"type": "string",
"enum": ["add", "subtract", "multiply", "divide"],
"description": "The mathematical operation to perform",
},
"numbers": {
"type": "array",
"items": {
"type": "number"
},
"description": "The numbers to perform the operation on",
},
},
"required": ["operation", "numbers"],
},
},
}
]
# Example usage
messages = [
{
"role": "user",
"content": "Calculate the sum of 5, 10, and 15"
}
]
response = get_completion(messages , tools=calculator_tool)
# Parse the arguments and call the function
args = json.loads(response.tool_calls[0].function.arguments)
result = calculate(args["operation"], *args["numbers"])
print(f"Result: {result}")
def calculate(operation, *numbers):
"""
Perform a calculation on a variable number of inputs.
:param operation: String indicating the operation ('add', 'subtract', 'multiply', 'divide')
:param numbers: Variable number of numeric inputs
:return: Result of the calculation
"""
if not numbers:
return "Error: No numbers provided"
result = numbers[0]
for num in numbers[1:]:
if operation == 'add':
result += num
elif operation == 'subtract':
result -= num
elif operation == 'multiply':
result *= num
elif operation == 'divide':
if num == 0:
return "Error: Division by zero"
result /= num
else:
return "Error: Invalid operation"
return result
# Function schema for the calculator
calculator_tool = [
{
"type": "function",
"function": {
"name": "calculate",
"description": "Perform a calculation on multiple numbers",
"parameters": {
"type": "object",
"properties": {
"operation": {
"type": "string",
"enum": ["add", "subtract", "multiply", "divide"],
"description": "The mathematical operation to perform",
},
"numbers": {
"type": "array",
"items": {
"type": "number"
},
"description": "The numbers to perform the operation on",
},
},
"required": ["operation", "numbers"],
},
},
}
]
# Example usage
messages = [
{
"role": "user",
"content": "Calculate the sum of 5, 10, and 15"
}
]
response = get_completion(messages , tools=calculator_tool)
# Parse the arguments and call the function
args = json.loads(response.tool_calls[0].function.arguments)
result = calculate(args["operation"], *args["numbers"])
print(f"Result: {result}")
Result: 30
In [64]:
Copied!
def convert_units(value, from_unit, to_unit):
"""
Convert between different units of measurement.
:param value: Numeric value to convert
:param from_unit: Original unit
:param to_unit: Target unit
:return: Converted value
"""
# Conversion factors (relative to base units)
units = {
"m": 1,
"cm": 0.01,
"km": 1000,
"kg": 1,
"g": 0.001,
"l": 1,
"ml": 0.001
}
if from_unit not in units or to_unit not in units:
return "Error: Invalid unit"
# Convert to base unit, then to target unit
base_value = value * units[from_unit]
converted_value = base_value / units[to_unit]
return converted_value
# Function schema for the units converter
converter_tool = [
{
"type": "function",
"function": {
"name": "convert_units",
"description": "Convert between different units of measurement",
"parameters": {
"type": "object",
"properties": {
"value": {
"type": "number",
"description": "The numeric value to convert",
},
"from_unit": {
"type": "string",
"enum": ["m", "cm", "km", "kg", "g", "l", "ml"],
"description": "The original unit of measurement",
},
"to_unit": {
"type": "string",
"enum": ["m", "cm", "km", "kg", "g", "l", "ml"],
"description": "The target unit of measurement",
},
},
"required": ["value", "from_unit", "to_unit"],
},
},
}
]
# Example usage
messages = [
{
"role": "user",
"content": "Convert 5 kilometers to meters"
}
]
response = get_completion(messages , tools=converter_tool)
# Parse the arguments and call the function
args = json.loads(response.tool_calls[0].function.arguments)
print(args)
result = convert_units(args["value"], args["from_unit"], args["to_unit"])
print(f"Result: {result}")
def convert_units(value, from_unit, to_unit):
"""
Convert between different units of measurement.
:param value: Numeric value to convert
:param from_unit: Original unit
:param to_unit: Target unit
:return: Converted value
"""
# Conversion factors (relative to base units)
units = {
"m": 1,
"cm": 0.01,
"km": 1000,
"kg": 1,
"g": 0.001,
"l": 1,
"ml": 0.001
}
if from_unit not in units or to_unit not in units:
return "Error: Invalid unit"
# Convert to base unit, then to target unit
base_value = value * units[from_unit]
converted_value = base_value / units[to_unit]
return converted_value
# Function schema for the units converter
converter_tool = [
{
"type": "function",
"function": {
"name": "convert_units",
"description": "Convert between different units of measurement",
"parameters": {
"type": "object",
"properties": {
"value": {
"type": "number",
"description": "The numeric value to convert",
},
"from_unit": {
"type": "string",
"enum": ["m", "cm", "km", "kg", "g", "l", "ml"],
"description": "The original unit of measurement",
},
"to_unit": {
"type": "string",
"enum": ["m", "cm", "km", "kg", "g", "l", "ml"],
"description": "The target unit of measurement",
},
},
"required": ["value", "from_unit", "to_unit"],
},
},
}
]
# Example usage
messages = [
{
"role": "user",
"content": "Convert 5 kilometers to meters"
}
]
response = get_completion(messages , tools=converter_tool)
# Parse the arguments and call the function
args = json.loads(response.tool_calls[0].function.arguments)
print(args)
result = convert_units(args["value"], args["from_unit"], args["to_unit"])
print(f"Result: {result}")
{'value': 5, 'from_unit': 'km', 'to_unit': 'm'}
Result: 5000.0