API / force-a-specific-tool-with-tool-choice

API

Force a specific tool with tool_choice

Make the model call a named function (or require any tool) on this Responses turn when “maybe later” is the wrong outcome for your workflow. Official Function Calling documents the tool_choice request field with four shapes: "auto" (default — the model decides), "required" (at least one tool call), "none" (disable tools for this turn), and {"type": "function", "function": {"name": "..."}} to force one specific tool by name. Pair this with tools you already defined in tools[]. Create a key and load credits at console.x.ai.

What you need

An XAI_API_KEY, at least one custom function tool (name, description, JSON Schema parameters with an object root), and a product rule that needs deterministic tool use — for example always logging a ticket before the assistant answers, or disabling tools on a pure-summarize turn. Neighboring jobs include Call a function with the Grok API for the define-and-return loop, Use the image generation tool in a conversation when the server-side Imagine tool is in the same request, and Configure image generation tool action for gating generate vs edit. More API jobs live on the API hub.

Set tool_choice on the request

  1. Export the key:
export XAI_API_KEY="your_api_key"
  1. Force a named function by passing the object form of tool_choice alongside your tools array. The name must match a tool you listed:
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"]
      }
    }
  ],
  "tool_choice": {
    "type": "function",
    "function": {"name": "get_temperature"}
  }
}'
  1. Require any tool without naming one by setting "tool_choice": "required", or silence tools for this turn with "tool_choice": "none" while still sending the same tools definitions for later turns that reuse previous_response_id.

  2. When the model returns multiple client-side calls in one response (parallel function calling is enabled by default), execute every call before you continue — official docs show iterating response.tool_calls / function_call output items and appending each result. Disable parallelism for this request with "parallel_tool_calls": false when your backend cannot handle concurrent tool work safely.

import json
import os
from openai import OpenAI

client = OpenAI(api_key=os.getenv("XAI_API_KEY"), base_url="https://api.x.ai/v1")

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"],
        },
    }
]

response = client.responses.create(
    model="grok-4.7",
    input=[{"role": "user", "content": "What is the temperature in San Francisco?"}],
    tools=tools,
    tool_choice={"type": "function", "function": {"name": "get_temperature"}},
    parallel_tool_calls=False,
)

for item in response.output:
    if item.type == "function_call":
        args = json.loads(item.arguments)
        # Run your real function, then send function_call_output with item.call_id
        print(item.name, args)

Mixing with built-in tools

tool_choice applies to the whole turn. Built-in server-side tools (web search, X search, and similar) still execute on xAI’s side when the model selects them; custom type: "function" tools still pause for your local execution. Forcing a custom function name does not run that function for you — you still handle the function_call / tool_call and return function_call_output / tool_result before the model can finish the answer.

Pitfalls

Forcing a name that is missing from tools[] fails validation or yields an empty/error tool path — keep the catalogs identical. Using "required" without any tools defined cannot satisfy the constraint. Leaving parallel calls enabled while your handler only processes the first function_call drops sibling results and confuses the next turn. Parameter schemas still need an object root (or a oneOf/anyOf of objects); a scalar root is rejected with 400 regardless of tool_choice.