Custom functions (function calling)
On this page
Connect Grok to your own services
Server tools (web_search, x_search, code_interpreter) are handy but limited to xAI services. With custom function tools, you can connect Grok to any API or service in your infrastructure.
How it works
Function calling follows a three-step cycle:
- Declaration: You describe your functions (name, description, parameters) in the request
- Call: The model generates a function call with the appropriate arguments and pauses generation
- Result: Your code executes the function, then you send the result back to the model so it can formulate its response
Declare a function
{
"model": "grok-4.20-0309-reasoning",
"input": "Book me a table for 2 people tonight at 8 PM.",
"tools": [{
"type": "function",
"name": "book_restaurant",
"description": "Books a table at a restaurant",
"parameters": {
"type": "object",
"properties": {
"restaurant_name": {
"type": "string",
"description": "Restaurant name"
},
"date": {
"type": "string",
"description": "Date in YYYY-MM-DD format"
},
"time": {
"type": "string",
"description": "Time in HH:MM format"
},
"guests": {
"type": "integer",
"description": "Number of guests"
}
},
"required": ["date", "time", "guests"]
}
}]
}
The description of each function and parameter is crucial. The model uses them to decide when to call the function and how to fill the arguments.
Receive the function call
When the model decides to call your function, the response contains a function_call item:
{
"id": "resp-xyz789",
"status": "completed",
"output": [{
"type": "function_call",
"name": "book_restaurant",
"arguments": "{\"date\": \"2026-04-03\", \"time\": \"20:00\", \"guests\": 2}",
"call_id": "call-abc123"
}]
}
The arguments field is a JSON string that you must parse. The call_id identifies this specific call.
Return the result
After executing the function in your code, return the result:
import json
# 1. Initial request
response = client.responses.create(
model="grok-4.20-0309-reasoning",
input="What's the weather like in Paris?",
tools=[{
"type": "function",
"name": "get_weather",
"description": "Retrieves current weather",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"}
},
"required": ["city"]
}
}]
)
# 2. Check if the model wants to call a function
for item in response.output:
if item.type == "function_call":
args = json.loads(item.arguments)
# 3. Execute your function
weather_data = get_weather_from_api(args["city"])
# 4. Return the result to the model
final = client.responses.create(
model="grok-4.20-0309-reasoning",
input=[{
"type": "function_call_output",
"call_id": item.call_id,
"output": json.dumps(weather_data)
}],
previous_response_id=response.id
)
print(final.output[0].content[0].text)
Best practices for descriptions
The model relies on descriptions to understand your functions. Be precise:
{
"name": "search_products",
"description": "Searches for products in the e-commerce catalog. Returns the top 10 results sorted by relevance. Supports search by name, category, or price range.",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Search terms (product name, brand, keyword)"
},
"category": {
"type": "string",
"enum": ["electronics", "clothing", "home", "sports"],
"description": "Product category to filter"
},
"max_price": {
"type": "number",
"description": "Maximum price in euros"
}
},
"required": ["query"]
}
}
Use enum for predefined values, detailed description for each parameter, and mark only essential parameters as required.
Error handling
If your function fails, return the error as the result:
try:
result = call_external_api(args)
output = json.dumps(result)
except Exception as e:
output = json.dumps({"error": str(e)})
final = client.responses.create(
model="grok-4.20-0309-reasoning",
input=[{
"type": "function_call_output",
"call_id": call_id,
"output": output
}],
previous_response_id=response.id
)
The model interprets the error and can rephrase its response or try a different approach.
Key takeaways
- Custom functions connect Grok to your own services
- The cycle is: declare, receive the call, execute, return the result
- Function and parameter descriptions guide the model’s choice
- The
argumentsfield is a JSON string to parse on the client side - Return errors as results so the model can adapt