Function Calling allows AI models to call external functions and APIs, greatly expanding the capability boundaries of intelligent agents, enabling them to perform specific operations and obtain real-time data.
Features
Function calling provides AI models with the ability to interact with external systems, supporting various complex application scenarios and integration requirements.
Core Parameter Description
tools : Defines the list of callable functions, including function names, descriptions, and parameter specifications
tool_choice : Controls function calling strategy, can be set to auto, none, or specify a function name
model : Uses models that support function calling, such as glm-4-plus, glm-4.6, etc.
Response Parameter Description
Key fields in function calling responses:
tool_calls : Contains information about functions the model decides to call
function.name : Name of the called function
function.arguments : Function call parameters (JSON format string)
id : Unique identifier for the tool call
Features
Structured Output
Automatic function parameter parsing
Type validation and conversion
Error handling and retry
Result formatting
Multi-function Support
Define multiple functions simultaneously
Function chaining calls
Conditional function selection
Parallel function execution
Flexible Integration
RESTful API integration
Database operations
File system access
Third-party service calls
Code Examples
By defining function tools and handling function calls, AI models can perform various external operations:
Install SDK # Install latest version
pip install zai-sdk
# Or specify version
pip install zai-sdk== 0.0.4
Verify Installation import zai
print (zai. __version__ )
Complete Example import json
from zai import ZaiClient
# Initialize client
client = ZaiClient( api_key = 'your_api_key' )
# Define weather query function
def get_weather ( city : str ) -> dict :
"""Get weather information for specified city"""
# This should call a real weather API
weather_data = {
"city" : city,
"temperature" : "22Β°C" ,
"condition" : "Sunny" ,
"humidity" : "65%" ,
"wind_speed" : "5 km/h"
}
return weather_data
# Define function tools
tools = [
{
"type" : "function" ,
"function" : {
"name" : "get_weather" ,
"description" : "Get current weather information for specified city" ,
"parameters" : {
"type" : "object" ,
"properties" : {
"city" : {
"type" : "string" ,
"description" : "City name, e.g.: Beijing, Shanghai"
}
},
"required" : [ "city" ]
}
}
}
]
# Make conversation request
response = client.chat.completions.create(
model = "glm-4-plus" , # Use model that supports function calling
messages = [
{ "role" : "user" , "content" : "How's the weather in Beijing today?" }
],
tools = tools, # Pass function tools
tool_choice = "auto" # Automatically choose whether to call functions
)
# Handle function calls
message = response.choices[ 0 ].message
messages = [{ "role" : "user" , "content" : "How's the weather in Beijing today?" }]
messages.append(message.model_dump())
if message.tool_calls:
for tool_call in message.tool_calls:
if tool_call.function.name == "get_weather" :
# Parse parameters and call function
args = json.loads(tool_call.function.arguments)
weather_result = get_weather(args.get( "city" ))
# Return function result to model
messages.append({
"role" : "tool" ,
"content" : json.dumps(weather_result, ensure_ascii = False ),
"tool_call_id" : tool_call.id
})
# Get final answer
final_response = client.chat.completions.create(
model = "glm-4-plus" ,
messages = messages,
tools = tools
)
print (final_response.choices[ 0 ].message.content)
else :
print (message.content)
Scenario Examples
When using function calling, please ensure proper security validation and permission control for external APIs and database operations.
import json
import requests
from datetime import datetime
from zai import ZaiClient
class FunctionAgent :
def __init__ ( self , api_key ):
self .client = ZaiClient( api_key = api_key)
self .tools = self ._define_tools()
def _define_tools ( self ):
return [
{
"type" : "function" ,
"function" : {
"name" : "get_current_time" ,
"description" : "Get current time" ,
"parameters" : {
"type" : "object" ,
"properties" : {},
"required" : []
}
}
},
{
"type" : "function" ,
"function" : {
"name" : "calculate" ,
"description" : "Perform mathematical calculations" ,
"parameters" : {
"type" : "object" ,
"properties" : {
"expression" : {
"type" : "string" ,
"description" : "Mathematical expression, e.g.: 2+3*4"
}
},
"required" : [ "expression" ]
}
}
},
{
"type" : "function" ,
"function" : {
"name" : "search_web" ,
"description" : "Search web information" ,
"parameters" : {
"type" : "object" ,
"properties" : {
"query" : {
"type" : "string" ,
"description" : "Search keywords"
}
},
"required" : [ "query" ]
}
}
}
]
def get_current_time ( self ):
"""Get current time"""
return {
"current_time" : datetime.now().strftime( "%Y-%m- %d %H:%M:%S" ),
"timezone" : "Asia/Shanghai"
}
def calculate ( self , expression : str ):
"""Safe mathematical calculation"""
try :
# Simple security check
allowed_chars = set ( '0123456789+-*/().' )
if not all (c in allowed_chars or c.isspace() for c in expression):
return { "error" : "Expression contains disallowed characters" }
result = eval (expression)
return {
"expression" : expression,
"result" : result
}
except Exception as e:
return { "error" : f "Calculation error: { str (e) } " }
def search_web ( self , query : str ):
"""Simulate web search"""
# This should call a real search API
return {
"query" : query,
"results" : [
{ "title" : f "Search result 1 about { query } " , "url" : "https://example1.com" },
{ "title" : f "Search result 2 about { query } " , "url" : "https://example2.com" }
]
}
def execute_function ( self , function_name : str , arguments : dict ):
"""Execute function call"""
if function_name == "get_current_time" :
return self .get_current_time()
elif function_name == "calculate" :
return self .calculate(arguments.get( "expression" , "" ))
elif function_name == "search_web" :
return self .search_web(arguments.get( "query" , "" ))
else :
return { "error" : f "Unknown function: { function_name } " }
def chat ( self , user_message : str ):
"""Handle user message"""
messages = [{ "role" : "user" , "content" : user_message}]
response = self .client.chat.completions.create(
model = "glm-4-plus" ,
messages = messages,
tools = self .tools,
tool_choice = "auto"
)
message = response.choices[ 0 ].message
messages.append(message.model_dump())
# Handle function calls
if message.tool_calls:
for tool_call in message.tool_calls:
function_name = tool_call.function.name
arguments = json.loads(tool_call.function.arguments)
# Execute function
result = self .execute_function(function_name, arguments)
# Add function result
messages.append({
"role" : "tool" ,
"content" : json.dumps(result, ensure_ascii = False ),
"tool_call_id" : tool_call.id
})
# Get final answer
final_response = self .client.chat.completions.create(
model = "glm-4-plus" ,
messages = messages,
tools = self .tools
)
return final_response.choices[ 0 ].message.content
else :
return message.content
# Usage example
agent = FunctionAgent( "your_api_key" )
# Test different types of requests
print (agent.chat( "What time is it now?" ))
print (agent.chat( "Help me calculate 15 * 23 + 7" ))
print (agent.chat( "Search for the latest developments in artificial intelligence" ))
import sqlite3
def query_database ( sql : str ) -> dict :
"""Execute database query"""
try :
conn = sqlite3.connect( 'example.db' )
cursor = conn.cursor()
cursor.execute(sql)
results = cursor.fetchall()
conn.close()
return {
"success" : True ,
"data" : results,
"row_count" : len (results)
}
except Exception as e:
return {
"success" : False ,
"error" : str (e)
}
# Function definition
db_tool = {
"type" : "function" ,
"function" : {
"name" : "query_database" ,
"description" : "Execute SQL query" ,
"parameters" : {
"type" : "object" ,
"properties" : {
"sql" : {
"type" : "string" ,
"description" : "SQL query statement"
}
},
"required" : [ "sql" ]
}
}
}
import os
import json
def file_operations ( operation : str , file_path : str , content : str = None ) -> dict :
"""File operation function"""
try :
if operation == "read" :
with open (file_path, 'r' , encoding = 'utf-8' ) as f:
content = f.read()
return { "success" : True , "content" : content}
elif operation == "write" :
with open (file_path, 'w' , encoding = 'utf-8' ) as f:
f.write(content)
return { "success" : True , "message" : "File written successfully" }
elif operation == "list" :
files = os.listdir(file_path)
return { "success" : True , "files" : files}
else :
return { "success" : False , "error" : "Unsupported operation" }
except Exception as e:
return { "success" : False , "error" : str (e)}
# Function definition
file_tool = {
"type" : "function" ,
"function" : {
"name" : "file_operations" ,
"description" : "Execute file operations" ,
"parameters" : {
"type" : "object" ,
"properties" : {
"operation" : {
"type" : "string" ,
"enum" : [ "read" , "write" , "list" ],
"description" : "Operation type"
},
"file_path" : {
"type" : "string" ,
"description" : "File path"
},
"content" : {
"type" : "string" ,
"description" : "Content to write (only required for write operation)"
}
},
"required" : [ "operation" , "file_path" ]
}
}
}
import requests
def call_external_api ( url : str , method : str = "GET" , headers : dict = None , data : dict = None ) -> dict :
"""Call external API"""
try :
if method.upper() == "GET" :
response = requests.get(url, headers = headers, params = data)
elif method.upper() == "POST" :
response = requests.post(url, headers = headers, json = data)
else :
return { "success" : False , "error" : "Unsupported HTTP method" }
return {
"success" : True ,
"status_code" : response.status_code,
"data" : response.json() if response.headers.get( 'content-type' , '' ).startswith( 'application/json' ) else response.text
}
except Exception as e:
return { "success" : False , "error" : str (e)}
# Function definition
api_tool = {
"type" : "function" ,
"function" : {
"name" : "call_external_api" ,
"description" : "Call external API" ,
"parameters" : {
"type" : "object" ,
"properties" : {
"url" : {
"type" : "string" ,
"description" : "API endpoint URL"
},
"method" : {
"type" : "string" ,
"enum" : [ "GET" , "POST" ],
"description" : "HTTP method"
},
"headers" : {
"type" : "object" ,
"description" : "Request headers"
},
"data" : {
"type" : "object" ,
"description" : "Request data"
}
},
"required" : [ "url" ]
}
}
}
Best Practices
Function Design Principles
Single responsibility: Each function should do one thing
Clear naming: Function and parameter names should be meaningful
Complete description: Provide detailed function and parameter descriptions
Security Considerations
Input validation: Strictly validate all input parameters
Permission control: Limit function access permissions
Logging: Record function call logs
Parameter Design
# Good parameter design
{
"type" : "object" ,
"properties" : {
"city" : {
"type" : "string" ,
"description" : "City name, supports Chinese and English, e.g.: Beijing, Shanghai, New York" ,
"examples" : [ "Beijing" , "Shanghai" , "New York" ]
},
"unit" : {
"type" : "string" ,
"enum" : [ "celsius" , "fahrenheit" ],
"description" : "Temperature unit" ,
"default" : "celsius"
}
},
"required" : [ "city" ]
}
Error Handling
def robust_function ( param : str ) -> dict :
"""Robust function implementation"""
try :
# Parameter validation
if not param or not isinstance (param, str ):
return {
"success" : False ,
"error" : "Invalid parameter" ,
"error_code" : "INVALID_PARAM"
}
# Business logic
result = process_data(param)
return {
"success" : True ,
"data" : result,
"timestamp" : datetime.now().isoformat()
}
except ValueError as e:
return {
"success" : False ,
"error" : f "Data error: { str (e) } " ,
"error_code" : "DATA_ERROR"
}
except Exception as e:
return {
"success" : False ,
"error" : f "System error: { str (e) } " ,
"error_code" : "SYSTEM_ERROR"
}
def secure_function ( user_input : str ) -> dict :
"""Secure function implementation"""
# Input length limit
if len (user_input) > 1000 :
return { "error" : "Input too long" }
# Dangerous character filtering
dangerous_chars = [ '<' , '>' , '&' , '"' , "'" ]
if any (char in user_input for char in dangerous_chars):
return { "error" : "Input contains dangerous characters" }
# SQL injection protection
sql_keywords = [ 'DROP' , 'DELETE' , 'UPDATE' , 'INSERT' ]
if any (keyword in user_input.upper() for keyword in sql_keywords):
return { "error" : "Input contains dangerous keywords" }
return { "success" : True , "processed_input" : user_input}
Permission Control
def check_permissions ( user_id : str , operation : str ) -> bool :
"""Check user permissions"""
user_permissions = get_user_permissions(user_id)
return operation in user_permissions
def protected_function ( user_id : str , operation : str , data : dict ) -> dict :
"""Function requiring permission validation"""
if not check_permissions(user_id, operation):
return {
"success" : False ,
"error" : "Insufficient permissions" ,
"error_code" : "PERMISSION_DENIED"
}
# Execute operation
return perform_operation(operation, data)
It is recommended to provide detailed documentation and examples for each function to help the model better understand the functionβs purpose and usage.
Function calling involves code execution. Please ensure appropriate security measures are implemented, including input validation, permission control, and error handling.