Enable AI models to interact with external tools and APIs through structured function calls
{
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature unit"
}
},
"required": ["location"]
}
}
import requests
import json
def get_weather(location, unit="celsius"):
"""Mock weather function"""
# In reality, this would call a weather API
return {
"location": location,
"temperature": "22°C" if unit == "celsius" else "72°F",
"condition": "Sunny",
"humidity": "45%"
}
def calculate(expression):
"""Safe calculator function"""
try:
# Only allow basic math operations
allowed_chars = set("0123456789+-*/.()")
if all(c in allowed_chars for c in expression.replace(" ", "")):
result = eval(expression)
return {"expression": expression, "result": result}
else:
return {"error": "Invalid expression"}
except:
return {"error": "Calculation failed"}
def function_calling_chat(messages, available_functions):
"""Chat with function calling capability"""
# Define functions for the API
functions = [
{
"name": "get_weather",
"description": "Get current weather information for a location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature unit"
}
},
"required": ["location"]
}
},
{
"name": "calculate",
"description": "Perform mathematical calculations",
"parameters": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "Mathematical expression to evaluate"
}
},
"required": ["expression"]
}
}
]
# Make initial request
response = requests.post(
"https://api.anyapi.ai/v1/chat/completions",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
json={
"model": "gpt-4o",
"messages": messages,
"functions": functions,
"function_call": "auto"
}
)
response_data = response.json()
message = response_data["choices"][0]["message"]
# Check if the model wants to call a function
if message.get("function_call"):
function_name = message["function_call"]["name"]
function_args = json.loads(message["function_call"]["arguments"])
print(f"Calling function: {function_name}")
print(f"Arguments: {function_args}")
# Execute the function
if function_name in available_functions:
function_result = available_functions[function_name](**function_args)
else:
function_result = {"error": "Function not found"}
# Add the function call and result to the conversation
messages.append(message) # Assistant's function call
messages.append({
"role": "function",
"name": function_name,
"content": json.dumps(function_result)
})
# Get the final response
final_response = requests.post(
"https://api.anyapi.ai/v1/chat/completions",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
json={
"model": "gpt-4o",
"messages": messages
}
)
return final_response.json()["choices"][0]["message"]["content"]
else:
# No function call needed
return message["content"]
# Available functions mapping
available_functions = {
"get_weather": get_weather,
"calculate": calculate
}
# Usage
messages = [
{"role": "user", "content": "What's the weather like in Tokyo and what's 15 * 24?"}
]
response = function_calling_chat(messages, available_functions)
print(response)
class AdvancedFunctionCaller:
def __init__(self, api_key):
self.api_key = api_key
self.functions = {}
self.function_definitions = []
def register_function(self, name, func, description, parameters):
"""Register a function for calling"""
self.functions[name] = func
self.function_definitions.append({
"name": name,
"description": description,
"parameters": parameters
})
def chat_with_functions(self, messages, max_function_calls=5):
"""Handle multiple function calls in a conversation"""
conversation = messages.copy()
function_call_count = 0
while function_call_count < max_function_calls:
response = requests.post(
"https://api.anyapi.ai/v1/chat/completions",
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
},
json={
"model": "gpt-4o",
"messages": conversation,
"functions": self.function_definitions,
"function_call": "auto"
}
)
response_data = response.json()
message = response_data["choices"][0]["message"]
if message.get("function_call"):
function_name = message["function_call"]["name"]
function_args = json.loads(message["function_call"]["arguments"])
print(f"Function call #{function_call_count + 1}: {function_name}")
# Execute function
if function_name in self.functions:
try:
function_result = self.functions[function_name](**function_args)
except Exception as e:
function_result = {"error": str(e)}
else:
function_result = {"error": "Function not available"}
# Add to conversation
conversation.append(message)
conversation.append({
"role": "function",
"name": function_name,
"content": json.dumps(function_result)
})
function_call_count += 1
else:
# No more function calls needed
return message["content"]
# Max function calls reached
return "I've reached the maximum number of function calls. Please ask me to continue if needed."
# Example functions
def get_stock_price(symbol):
"""Mock stock price function"""
prices = {
"AAPL": {"price": 175.84, "change": "+2.3%"},
"GOOGL": {"price": 142.56, "change": "-0.8%"},
"MSFT": {"price": 378.85, "change": "+1.2%"}
}
return prices.get(symbol.upper(), {"error": "Symbol not found"})
def search_news(query, limit=3):
"""Mock news search function"""
return {
"query": query,
"articles": [
{"title": f"Article about {query} #1", "summary": "Summary 1"},
{"title": f"Article about {query} #2", "summary": "Summary 2"},
{"title": f"Article about {query} #3", "summary": "Summary 3"}
][:limit]
}
def send_email(to, subject, body):
"""Mock email function"""
return {
"status": "sent",
"to": to,
"subject": subject,
"message": "Email sent successfully"
}
# Setup
function_caller = AdvancedFunctionCaller("YOUR_API_KEY")
# Register functions
function_caller.register_function(
"get_stock_price",
get_stock_price,
"Get current stock price for a given symbol",
{
"type": "object",
"properties": {
"symbol": {"type": "string", "description": "Stock symbol (e.g., AAPL)"}
},
"required": ["symbol"]
}
)
function_caller.register_function(
"search_news",
search_news,
"Search for news articles about a topic",
{
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"},
"limit": {"type": "integer", "description": "Number of articles", "default": 3}
},
"required": ["query"]
}
)
# Usage
messages = [
{
"role": "user",
"content": "Get me the stock price for Apple, then search for recent news about the company"
}
]
response = function_caller.chat_with_functions(messages)
print(response)
def stream_with_function_calls(messages, functions, available_functions):
"""Stream responses while handling function calls"""
response = requests.post(
"https://api.anyapi.ai/v1/chat/completions",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
json={
"model": "gpt-4o",
"messages": messages,
"functions": functions,
"function_call": "auto",
"stream": True
},
stream=True
)
function_call_buffer = ""
function_name = ""
for line in response.iter_lines(decode_unicode=True):
if line.startswith('data: '):
data = line[6:]
if data == '[DONE]':
break
try:
chunk = json.loads(data)
if chunk.get('choices') and len(chunk['choices']) > 0:
choice = chunk['choices'][0]
delta = choice.get('delta', {})
# Handle regular content
if 'content' in delta and delta['content']:
yield {'type': 'content', 'data': delta['content']}
# Handle function calls
if 'function_call' in delta:
func_call = delta['function_call']
if 'name' in func_call:
function_name = func_call['name']
yield {'type': 'function_call_start', 'data': function_name}
if 'arguments' in func_call:
function_call_buffer += func_call['arguments']
# Handle completion
if choice.get('finish_reason') == 'function_call':
# Execute function
try:
args = json.loads(function_call_buffer)
result = available_functions[function_name](**args)
yield {
'type': 'function_result',
'data': {
'name': function_name,
'arguments': args,
'result': result
}
}
# Continue conversation with function result
messages.append({
"role": "assistant",
"content": None,
"function_call": {
"name": function_name,
"arguments": function_call_buffer
}
})
messages.append({
"role": "function",
"name": function_name,
"content": json.dumps(result)
})
# Get continuation
yield from stream_with_function_calls(messages, functions, available_functions)
return
except Exception as e:
yield {'type': 'error', 'data': f"Function execution failed: {e}"}
return
except json.JSONDecodeError:
continue
# Usage
functions = [
{
"name": "get_weather",
"description": "Get weather information",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "City name"}
},
"required": ["location"]
}
}
]
available_functions = {
"get_weather": lambda location: {
"location": location,
"temperature": "22°C",
"condition": "Sunny"
}
}
messages = [
{"role": "user", "content": "What's the weather like in Tokyo?"}
]
for event in stream_with_function_calls(messages, functions, available_functions):
if event['type'] == 'content':
print(event['data'], end='', flush=True)
elif event['type'] == 'function_call_start':
print(f"\n[Calling {event['data']}...]")
elif event['type'] == 'function_result':
print(f"[Got result: {event['data']['result']}]")
import sqlite3
class DatabaseFunctions:
def __init__(self, db_path):
self.db_path = db_path
def query_users(self, limit=10, filter_active=True):
"""Query users from database"""
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
query = "SELECT id, name, email, created_at FROM users"
params = []
if filter_active:
query += " WHERE active = ?"
params.append(True)
query += " LIMIT ?"
params.append(limit)
cursor.execute(query, params)
results = cursor.fetchall()
users = []
for row in results:
users.append({
"id": row[0],
"name": row[1],
"email": row[2],
"created_at": row[3]
})
conn.close()
return {"users": users, "count": len(users)}
except Exception as e:
return {"error": str(e)}
def get_user_stats(self):
"""Get user statistics"""
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute("SELECT COUNT(*) FROM users WHERE active = 1")
active_users = cursor.fetchone()[0]
cursor.execute("SELECT COUNT(*) FROM users")
total_users = cursor.fetchone()[0]
cursor.execute("SELECT COUNT(*) FROM users WHERE created_at > datetime('now', '-30 days')")
new_users = cursor.fetchone()[0]
conn.close()
return {
"total_users": total_users,
"active_users": active_users,
"new_users_30_days": new_users
}
except Exception as e:
return {"error": str(e)}
# Function definitions for API
def get_db_function_definitions():
return [
{
"name": "query_users",
"description": "Query users from the database",
"parameters": {
"type": "object",
"properties": {
"limit": {
"type": "integer",
"description": "Maximum number of users to return",
"default": 10
},
"filter_active": {
"type": "boolean",
"description": "Only return active users",
"default": True
}
}
}
},
{
"name": "get_user_stats",
"description": "Get user statistics and metrics",
"parameters": {
"type": "object",
"properties": {}
}
}
]
import requests
from datetime import datetime
class ExternalAPIFunctions:
def __init__(self, weather_api_key, news_api_key):
self.weather_api_key = weather_api_key
self.news_api_key = news_api_key
def get_weather(self, location, unit="metric"):
"""Get real weather data from OpenWeatherMap API"""
try:
url = f"http://api.openweathermap.org/data/2.5/weather"
params = {
"q": location,
"appid": self.weather_api_key,
"units": unit
}
response = requests.get(url, params=params, timeout=5)
response.raise_for_status()
data = response.json()
return {
"location": data["name"],
"country": data["sys"]["country"],
"temperature": f"{data['main']['temp']}°{'C' if unit == 'metric' else 'F'}",
"description": data["weather"][0]["description"],
"humidity": f"{data['main']['humidity']}%",
"pressure": f"{data['main']['pressure']} hPa",
"wind_speed": f"{data['wind']['speed']} {'m/s' if unit == 'metric' else 'mph'}"
}
except requests.exceptions.RequestException as e:
return {"error": f"Weather API error: {str(e)}"}
except KeyError as e:
return {"error": f"Invalid weather data format: {str(e)}"}
def search_news(self, query, limit=5, language="en"):
"""Search news using NewsAPI"""
try:
url = "https://newsapi.org/v2/everything"
params = {
"q": query,
"apiKey": self.news_api_key,
"language": language,
"sortBy": "publishedAt",
"pageSize": limit
}
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
articles = []
for article in data.get("articles", []):
articles.append({
"title": article["title"],
"description": article["description"],
"source": article["source"]["name"],
"url": article["url"],
"published_at": article["publishedAt"]
})
return {
"query": query,
"total_results": data.get("totalResults", 0),
"articles": articles
}
except requests.exceptions.RequestException as e:
return {"error": f"News API error: {str(e)}"}
def get_stock_price(self, symbol):
"""Get stock price from Alpha Vantage (free tier)"""
try:
# Using a free API for demo purposes
url = f"https://api.twelvedata.com/price"
params = {
"symbol": symbol.upper(),
"apikey": "demo" # Use demo key for testing
}
response = requests.get(url, params=params, timeout=5)
response.raise_for_status()
data = response.json()
if "price" in data:
return {
"symbol": symbol.upper(),
"price": f"${float(data['price']):.2f}",
"timestamp": datetime.now().isoformat()
}
else:
return {"error": "Stock data not available"}
except requests.exceptions.RequestException as e:
return {"error": f"Stock API error: {str(e)}"}
# Function definitions
def get_api_function_definitions():
return [
{
"name": "get_weather",
"description": "Get current weather information for any location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name or 'City, Country' format"
},
"unit": {
"type": "string",
"enum": ["metric", "imperial"],
"description": "Temperature unit (metric for Celsius, imperial for Fahrenheit)",
"default": "metric"
}
},
"required": ["location"]
}
},
{
"name": "search_news",
"description": "Search for recent news articles on any topic",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Search query for news articles"
},
"limit": {
"type": "integer",
"description": "Number of articles to return (max 10)",
"default": 5,
"minimum": 1,
"maximum": 10
},
"language": {
"type": "string",
"description": "Language code (e.g., 'en', 'es', 'fr')",
"default": "en"
}
},
"required": ["query"]
}
},
{
"name": "get_stock_price",
"description": "Get current stock price for a given symbol",
"parameters": {
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "Stock symbol (e.g., AAPL, GOOGL, MSFT)"
}
},
"required": ["symbol"]
}
}
]
import jsonschema
from jsonschema import validate
class SafeFunctionCaller:
def __init__(self, api_key):
self.api_key = api_key
self.functions = {}
self.schemas = {}
def register_function(self, name, func, schema):
"""Register function with input validation"""
self.functions[name] = func
self.schemas[name] = schema
def validate_function_args(self, function_name, args):
"""Validate function arguments against schema"""
if function_name not in self.schemas:
return False, "Function not registered"
try:
validate(instance=args, schema=self.schemas[function_name]["parameters"])
return True, None
except jsonschema.exceptions.ValidationError as e:
return False, f"Validation error: {e.message}"
def safe_execute_function(self, function_name, args):
"""Safely execute function with validation"""
# Validate arguments
is_valid, error = self.validate_function_args(function_name, args)
if not is_valid:
return {"error": error}
# Execute function with timeout and error handling
try:
if function_name in self.functions:
result = self.functions[function_name](**args)
return result
else:
return {"error": "Function not found"}
except TypeError as e:
return {"error": f"Invalid arguments: {str(e)}"}
except Exception as e:
return {"error": f"Function execution failed: {str(e)}"}
def chat_with_safe_functions(self, messages):
"""Chat with safe function execution"""
function_definitions = [
{
"name": name,
"description": schema["description"],
"parameters": schema["parameters"]
}
for name, schema in self.schemas.items()
]
response = requests.post(
"https://api.anyapi.ai/v1/chat/completions",
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
},
json={
"model": "gpt-4o",
"messages": messages,
"functions": function_definitions,
"function_call": "auto"
}
)
response_data = response.json()
message = response_data["choices"][0]["message"]
if message.get("function_call"):
function_name = message["function_call"]["name"]
try:
function_args = json.loads(message["function_call"]["arguments"])
except json.JSONDecodeError:
function_result = {"error": "Invalid function arguments JSON"}
else:
function_result = self.safe_execute_function(function_name, function_args)
# Continue conversation
messages.append(message)
messages.append({
"role": "function",
"name": function_name,
"content": json.dumps(function_result)
})
# Get final response
final_response = requests.post(
"https://api.anyapi.ai/v1/chat/completions",
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
},
json={
"model": "gpt-4o",
"messages": messages
}
)
return final_response.json()["choices"][0]["message"]["content"]
return message["content"]
# Usage with safe execution
safe_caller = SafeFunctionCaller("YOUR_API_KEY")
# Register function with schema
safe_caller.register_function(
"divide_numbers",
lambda x, y: {"result": x / y if y != 0 else "Cannot divide by zero"},
{
"description": "Divide two numbers",
"parameters": {
"type": "object",
"properties": {
"x": {"type": "number"},
"y": {"type": "number"}
},
"required": ["x", "y"]
}
}
)
# Functions can call other functions through the AI model
def multi_step_analysis(user_query):
"""Example of chained function calls"""
# Step 1: AI decides to get stock price
# Step 2: AI gets news about the company
# Step 3: AI analyzes both and provides recommendation
pass
# Functions with conditional logic
def smart_weather_advice(location, activity):
"""Get weather and provide activity-specific advice"""
weather = get_weather(location)
if weather["temperature"] > 25:
if activity == "running":
return {"advice": "Great weather for running! Stay hydrated."}
elif activity == "skiing":
return {"advice": "Too warm for skiing. Consider other activities."}
return {"advice": "Check current conditions and dress appropriately."}