Article
function-callingtool-useopenaistructured-outputapi-integrationpythonllm-agents
Use Function Calling to Connect LLMs to External Tools
Enable LLMs to use your custom functions or external APIs. You define your tools with a JSON schema, the model generates the arguments, you execute the function, and return the results to the model for a final, tool-informed answer.
intermediate30 min4 steps
The play
- Define a Function and its SchemaFirst, write a standard Python function. Then, create a JSON schema describing it. This schema tells the LLM the function's name, purpose, and parameters. The model uses this to decide when and how to call your function.
- Make the Initial API CallSend the user's prompt and your tool schemas to the model. Instead of answering directly, the model might respond with a `tool_calls` object, indicating its intent to use your function with specific arguments it generated.
- Execute the Function LocallyCheck the response for `tool_calls`. If it exists, parse the function name and arguments. Use this information to execute your actual Python function. This is the step where your code runs based on the LLM's request.
- Send the Result Back to the ModelTo get a final, natural-language answer, make a second API call. Append the assistant's `tool_calls` message and a new `tool` message containing the function's return value to your message history. The model will use this new context to formulate its final response.
Starter code
import os
import json
from openai import OpenAI
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
# Ensure you have OPENAI_API_KEY set in your .env file or environment
if not os.getenv("OPENAI_API_KEY"):
raise ValueError("OPENAI_API_KEY environment variable not set.")
client = OpenAI()
# 1. Define your local function
def get_current_weather(location, unit="celsius"):
"""Get the current weather in a given location."""
# In a real application, this would make an API call to a weather service.
# For this example, we'll return a mock response.
if "tokyo" in location.lower():
return json.dumps({"location": "Tokyo", "temperature": "15", "unit": unit, "forecast": "rainy"})
elif "boston" in location.lower():
return json.dumps({"location": "Boston", "temperature": "22", "unit": unit, "forecast": "sunny"})
else:
return json.dumps({"location": location, "temperature": "unknown"})
def run_conversation(user_prompt: str):
# 2. Define the schema for the function so the model knows how to use it
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",
},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
},
"required": ["location"],
},
},
}
]
messages = [{"role": "user", "content": user_prompt}]
# 3. First call to the model to see if it wants to use a tool
print(f"\n> User: {user_prompt}")
response = client.chat.completions.create(
model="gpt-4-turbo",
messages=messages,
tools=tools,
tool_choice="auto",
)
response_message = response.choices[0].message
# 4. Check if the model wants to call a function
tool_calls = response_message.tool_calls
if tool_calls:
print("> Assistant wants to call a function...")
# 5. Execute the function
available_functions = {"get_current_weather": get_current_weather}
messages.append(response_message) # extend conversation with assistant's reply
for tool_call in tool_calls:
function_name = tool_call.function.name
function_to_call = available_functions[function_name]
function_args = json.loads(tool_call.function.arguments)
print(f"> Calling function '{function_name}' with args: {function_args}")
function_response = function_to_call(**function_args)
# 6. Send the info back to the model
messages.append(
{
"tool_call_id": tool_call.id,
"role": "tool",
"name": function_name,
"content": function_response,
}
)
print("> Sending function response back to the model...")
second_response = client.chat.completions.create(
model="gpt-4-turbo",
messages=messages,
)
final_response = second_response.choices[0].message.content
else:
final_response = response_message.content
print(f"\n> Final Assistant Response: {final_response}")
if __name__ == "__main__":
# To run this:
# 1. pip install openai python-dotenv
# 2. Create a .env file with your OPENAI_API_KEY
# OPENAI_API_KEY='sk-...'
# 3. python your_script_name.py
run_conversation("What's the weather like in Boston?")
run_conversation("What is the weather in Tokyo in fahrenheit?")