Tools

Function Calling

Define custom tools that the model can invoke during a conversation. The model requests the call, you execute it locally, and return the result. This enables integration with databases, APIs, and any external system.

  1. Define tools with a name, description, and JSON schema for parameters

  2. Include tools in your request

  3. Model returns a tool_call when it needs external data

  4. Execute the function locally and return the result

  5. Model continues with your result


How it works

Developer
Grok
Execute tool
{ temp: "73", condition: "sunny" }
User query and tool definition
"Is it warm in Palo Alto?"
get_weather(location)
Tool call
get_weather("PA")
Tool result
...all previous messages
{ temp: "73", condition: "sunny" }
Model response
"It's a nice 73 °F in PA!"

Quick Start

curl https://api.x.ai/v1/responses \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $XAI_API_KEY" \
  -d '{
  "model": "grok-4.7",
  "input": [
    {"role": "user", "content": "What is the temperature in San Francisco?"}
  ],
  "tools": [
    {
      "type": "function",
      "name": "get_temperature",
      "description": "Get current temperature for a location",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {"type": "string", "description": "City name"},
          "unit": {"type": "string", "enum": ["celsius", "fahrenheit"], "default": "fahrenheit"}
        },
        "required": ["location"]
      }
    }
  ]
}'

Defining Tools with Pydantic

Use Pydantic models for type-safe parameter schemas:

from typing import Literal
from pydantic import BaseModel, Field
from xai_sdk.chat import tool

class TemperatureRequest(BaseModel):
    location: str = Field(description="City and state, e.g. San Francisco, CA")
    unit: Literal["celsius", "fahrenheit"] = Field("fahrenheit", description="Temperature unit")

class CeilingRequest(BaseModel):
    location: str = Field(description="City and state, e.g. San Francisco, CA")

# Generate JSON schema from Pydantic models
tools = [
    tool(
        name="get_temperature",
        description="Get current temperature for a location",
        parameters=TemperatureRequest.model_json_schema(),
    ),
    tool(
        name="get_ceiling",
        description="Get current cloud ceiling for a location",
        parameters=CeilingRequest.model_json_schema(),
    ),
]

Handling Tool Calls

When the model wants to use your tool, execute the function and return the result:

import json

def get_temperature(location: str, unit: str = "fahrenheit") -> dict:
    # In production, call a real weather API
    temp = 59 if unit == "fahrenheit" else 15
    return {"location": location, "temperature": temp, "unit": unit}

def get_ceiling(location: str) -> dict:
    return {"location": location, "ceiling": 15000, "unit": "ft"}

tools_map = {
    "get_temperature": get_temperature,
    "get_ceiling": get_ceiling,
}

chat.append(user("What's the weather in Denver?"))
response = chat.sample()

# Process tool calls
if response.tool_calls:
    chat.append(response)

    for tool_call in response.tool_calls:
        name = tool_call.function.name
        args = json.loads(tool_call.function.arguments)

        result = tools_map[name](**args)
        chat.append(tool_result(json.dumps(result)))

    response = chat.sample()

print(response.content)

Combining with Built-in Tools

Function calling works alongside built-in agentic tools. The model can use web search, then call your custom function:

from xai_sdk.chat import tool
from xai_sdk.tools import web_search, x_search

tools = [
    web_search(),                    # Built-in: runs on xAI servers
    x_search(),                      # Built-in: runs on xAI servers
    tool(                            # Custom: runs on your side
        name="save_to_database",
        description="Save research results to the database",
        parameters={
            "type": "object",
            "properties": {
                "data": {"type": "string", "description": "Data to save"}
            },
            "required": ["data"]
        },
    ),
]

chat = client.chat.create(
    model="grok-4.7",
    tools=tools,
)

When mixing tools:

  • Built-in tools execute automatically on xAI servers

  • Custom tools pause execution and return to you for handling

See Advanced Usage for complete examples with tool loops.


Tool Choice

Control when the model uses tools:

ValueBehavior
"auto"Model decides whether to call a tool (default)
"required"Model must call at least one tool
"none"Disable tool calling
{"type": "function", "function": {"name": "..."}}Force a specific tool

Parallel Function Calling

By default, parallel function calling is enabled — the model can request multiple tool calls in a single response. Process all of them before continuing:

Python

# response.tool_calls may contain multiple calls
for tool_call in response.tool_calls:
    result = tools_map[tool_call.function.name](**json.loads(tool_call.function.arguments))
    # Append each result...

Disable with parallel_tool_calls: false in your request.


Tool Schema Reference

FieldRequiredDescription
nameYesUnique identifier (max 350 tools per request)
descriptionYesWhat the tool does — helps the model decide when to use it
parametersYesJSON Schema defining function inputs

Parameter Schema

JSON

{
  "type": "object",
  "properties": {
    "location": {
      "type": "string",
      "description": "City name"
    },
    "unit": {
      "type": "string",
      "enum": ["celsius", "fahrenheit"],
      "default": "celsius"
    }
  },
  "required": ["location"]
}

The root of a parameters schema must be an object ("type": "object"); nest any other types inside properties. A root anyOf or oneOf also works when every branch is itself an object, letting you define a tool that accepts one of several object variants:

JSON

{
  "oneOf": [
    {
      "type": "object",
      "properties": {
        "kind": { "const": "email" },
        "address": { "type": "string" }
      },
      "required": ["kind", "address"]
    },
    {
      "type": "object",
      "properties": {
        "kind": { "const": "sms" },
        "phone": { "type": "string" }
      },
      "required": ["kind", "phone"]
    }
  ]
}

Complete Vercel AI SDK Example

The Vercel AI SDK handles tool definition, execution, and the request/response loop automatically:

JavaScript

import { xai } from '@ai-sdk/xai';
import { streamText, tool, stepCountIs } from 'ai';
import { z } from 'zod';

const result = streamText({
  model: xai.responses('grok-4.7'),
  tools: {
    getCurrentTemperature: tool({
      description: 'Get current temperature for a location',
      inputSchema: z.object({
        location: z.string().describe('City and state, e.g. San Francisco, CA'),
        unit: z.enum(['celsius', 'fahrenheit']).default('fahrenheit'),
      }),
      execute: async ({ location, unit }) => ({
        location,
        temperature: unit === 'fahrenheit' ? 59 : 15,
        unit,
      }),
    }),
    getCurrentCeiling: tool({
      description: 'Get current cloud ceiling for a location',
      inputSchema: z.object({
        location: z.string().describe('City and state'),
      }),
      execute: async ({ location }) => ({
        location,
        ceiling: 15000,
        ceiling_type: 'broken',
        unit: 'ft',
      }),
    }),
  },
  stopWhen: stepCountIs(5),
  prompt: "What's the temperature and cloud ceiling in San Francisco?",
});

for await (const chunk of result.fullStream) {
  switch (chunk.type) {
    case 'text-delta':
      process.stdout.write(chunk.text);
      break;
    case 'tool-call':
      console.log(`Tool call: ${chunk.toolName}`, chunk.input);
      break;
    case 'tool-result':
      console.log(`Tool result: ${chunk.toolName}`, chunk.output);
      break;
  }
}

Last updated:September 4, 2026