max_turns and Server/Client Tools
On this page
Server Tools and Client Tools
The xAI platform distinguishes two types of tools Grok can use in a conversation:
- Server-side tools: web search, code execution, X search. These tools run automatically on xAI’s servers. Grok invokes them, gets the result, and continues without any intervention from you.
- Client-side tools: your custom functions (function calling). When Grok wants to call one of your functions, the API returns a function call to you. Your code executes it, then sends the result back to the API.
This distinction is key to understanding max_turns behavior.
The max_turns Parameter
max_turns controls the number of assistant/tool turns Grok can perform in a single API request. Each use of a server tool consumes one turn.
response = await client.chat.completions.create(
model="grok-4.5",
messages=[{"role": "user", "content": "Search for the latest news on Python 3.13"}],
tools=[...],
max_turns=5 # Grok can use up to 5 server tools
)
If Grok needs to run a web search, then execute code to analyze the results, then run a second search to wrap up, that consumes 3 turns. With max_turns=5, it has 2 turns remaining.
Resetting via Client Tools
Key behavior to remember: client-side tool invocations reset the max_turns counter. When your code handles a function call and returns the result in a new API request, Grok gets its full turn allocation back.
# First request: max_turns=3
response = await client.chat.completions.create(
model="grok-4.5",
messages=messages,
tools=my_tools,
max_turns=3
)
# Grok requests a client function call
if response.choices[0].message.tool_calls:
# You execute the function locally
tool_result = execute_tool(response.choices[0].message.tool_calls[0])
# Second request: max_turns resets to 3
messages.append(response.choices[0].message)
messages.append({"role": "tool", "content": tool_result, ...})
response = await client.chat.completions.create(
model="grok-4.5",
messages=messages,
tools=my_tools,
max_turns=3 # new counter
)
This reset makes sense: each API request is independent. The max_turns counter applies only to turns performed within the same request.
Hybrid Workflows
Combining server and client tools enables complex workflows. For example, Grok can:
- Run a web search (server tool, 1 turn)
- Execute code to analyze the results (server tool, 1 turn)
- Ask your custom function to save the results (client tool, reset)
- Run a new search based on the saved results (server tool, 1 turn with new counter)
async def hybrid_workflow(question: str) -> str:
messages = [{"role": "user", "content": question}]
while True:
response = await client.chat.completions.create(
model="grok-4.5",
messages=messages,
tools=server_and_client_tools,
max_turns=5
)
message = response.choices[0].message
# If no client tool call, we have the final answer
if not message.tool_calls:
return message.content
# Process client tool calls
messages.append(message)
for tool_call in message.tool_calls:
result = await execute_local_tool(tool_call)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
This loop pattern automatically handles the back-and-forth between Grok and your local functions. The loop continues as long as Grok needs to call your tools. It stops when it provides a final text response.
Setting max_turns
- max_turns=1: Grok can use only one server tool. Sufficient for a simple web search.
- max_turns=3-5: good balance for most cases. Grok can chain search + analysis + verification.
- max_turns=10+: for complex tasks requiring many iterations. Watch out for token costs.
A max_turns value that’s too high costs nothing if unused, but a max_turns value that’s too low can truncate Grok’s reasoning mid-task.
Key Takeaways
- Server tools (web search, code execution) consume
max_turnsturns - Client tools (your functions) reset the counter with each new request
- The
while Trueloop pattern handles back-and-forth until the final response - Start with
max_turns=5and adjust based on your task complexity - Each server turn consumes additional tokens (cumulative context)