Learn how to use tool use (function calling) with TensorZero Gateway.
chat can call tools.A tool definition has the following properties:name: The name of the tool.description: A description of the tool. The description helps models understand the tool’s purpose and usage.parameters: The path to a file containing a JSON Schema for the tool’s parameters.strict property to enforce type checking for the tool’s parameters.This setting is only supported by some model providers, and will be ignored otherwise.[tools.get_temperature]description ="Get the current temperature for a given location."parameters ="tools/get_temperature.json"strict =true # optional, defaults to false[functions.weather_chatbot]type ="chat"tools = ["get_temperature"]# ...Example: JSON Schema for the `get_temperature` tool
get_temperature tool to take a mandatorylocation parameter and an optionalunits parameter, we could use the following JSON Schema:{ "$schema":"http://json-schema.org/draft-07/schema#", "type":"object", "description":"Get the current temperature for a given location.", "properties": { "location": { "type":"string", "description":"The location to get the temperature for (e.g.\"New York\")" }, "units": { "type":"string", "description":"The units to get the temperature in (must be\"fahrenheit\" or\"celsius\"). Defaults to\"fahrenheit\".", "enum": ["fahrenheit","celsius"] } }, "required": ["location"], "additionalProperties":false}tool_call content blocks in the response.For multi-turn conversations supporting tool use, you can provide tool results in subsequent inference requests with atool_result content block.Example: Multi-turn conversation with tool use
from tensorzeroimport TensorZeroGateway, ToolCall# or AsyncTensorZeroGatewaywith TensorZeroGateway.build_http( gateway_url="http://localhost:3000",)as t0: messages= [{"role":"user","content":"What is the weather in Tokyo (°F)?"}] response= t0.inference( function_name="weather_chatbot", input={"messages": messages}, ) print(response) # The model can return multiple content blocks, including tool calls # In a real application, you'd be stricter about validating the response tool_calls= [ content_block for content_blockin response.content if isinstance(content_block, ToolCall) ] assert len(tool_calls)== 1,"Expected the model to return exactly one tool call" # Add the tool call to the message history messages.append( { "role":"assistant", "content": response.content, } ) # Pretend we've called the tool and got a response messages.append( { "role":"user", "content": [ { "type":"tool_result", "id": tool_calls[0].id, "name": tool_calls[0].name, "result":"70",# imagine it's 70°F in Tokyo } ], } ) response= t0.inference( function_name="weather_chatbot", input={"messages": messages}, ) print(response)from openaiimport OpenAI# or AsyncOpenAIclient= OpenAI( base_url="http://localhost:3000/openai/v1",)messages= [{"role":"user","content":"What is the weather in Tokyo (°F)?"}]response= client.chat.completions.create( model="tensorzero::function_name::weather_chatbot", messages=messages,)print(response)# The model can return multiple content blocks, including tool calls# In a real application, you'd be stricter about validating the responsetool_calls= response.choices[0].message.tool_callsassert len(tool_calls)== 1,"Expected the model to return exactly one tool call"# Add the tool call to the message historymessages.append(response.choices[0].message)# Pretend we've called the tool and got a responsemessages.append( { "role":"tool", "tool_call_id": tool_calls[0].id, "content":"70",# imagine it's 70°F in Tokyo })response= client.chat.completions.create( model="tensorzero::function_name::weather_chatbot", messages=messages,)print(response)import OpenAI from "openai";const client = new OpenAI({ baseURL: "http://localhost:3000/openai/v1",});const messages: any[]= [ {role: "user",content: "What is the weather in Tokyo (°F)?" },];const response = await client.chat.completions.create({ model: "tensorzero::function_name::weather_chatbot", messages,});console.log(JSON.stringify(response,null,2));// The model can return multiple content blocks, including tool calls// In a real application, you'd be stricter about validating the responseconst toolCalls = response.choices[0].message.tool_calls;if (!toolCalls || toolCalls.length !== 1) { throw new Error("Expected the model to return exactly one tool call");}// Add the tool call to the message historymessages.push(response.choices[0].message);// Pretend we've called the tool and got a responsemessages.push({ role: "tool", tool_call_id: toolCalls[0].id, content: "70",// imagine it's 70°F in Tokyo});const response2 = await client.chat.completions.create({ model: "tensorzero::function_name::weather_chatbot", messages,});console.log(JSON.stringify(response2,null,2));#!/bin/bashcurl http://localhost:3000/inference \ -H "Content-Type: application/json" \ -d '{ "function_name": "weather_chatbot", "input": {"messages": [{"role": "user", "content": "What is the weather in Tokyo (°F)?"}]} }'echo "\n"curl http://localhost:3000/inference \ -H "Content-Type: application/json" \ -d '{ "function_name": "weather_chatbot", "input": { "messages": [ { "role": "user", "content": "What is the weather in Tokyo (°F)?" }, { "role": "assistant", "content": [ { "type": "tool_call", "id": "123", "name": "get_temperature", "arguments": { "location": "Tokyo" } } ] }, { "role": "user", "content": [ { "type": "tool_result", "id": "123", "name": "get_temperature", "result": "70" } ] } ] } }'allowed_tools parameter.For example, suppose your TensorZero function has access to several tools, but you only want to allow theget_temperature tool to be called during a particular inference.You can achieve this by settingallowed_tools=["get_temperature"] in your inference request.additional_tools property.(In the OpenAI-compatible API, you can use thetools property instead.)You should only use dynamic tools if your use case requires it.Otherwise, it’s recommended to define tools in the configuration file.You can define a tool dynamically with theadditional_tools property.This field accepts a list of objects with the same structure as the tools defined in the configuration file, except that theparameters field should contain the JSON Schema itself (rather than a path to a file with the schema).tool_choice parameter.The supported tool choice strategies are:none: The function should not use any tools.auto: The model decides whether or not to use a tool. If it decides to use a tool, it also decides which tools to use.required: The model should use a tool. If multiple tools are available, the model decides which tool to use.{ specific = "tool_name" }: The model should use a specific tool. The tool must be defined in thetools section of the configuration file or provided inadditional_tools.tool_choice parameter can be set either in your configuration file or directly in your inference request.parallel_tool_calls parameter totrue.If enabled, the models will be able to request multiple tool calls in a single inference request (conversation turn).You can specifyparallel_tool_calls in the configuration file or in the inference request.web_search tool that enables models to search the web for information.You can configure provider tools in your model provider configuration:[models.gpt-5-mini-responses.providers.openai]type ="openai"model_name ="gpt-5-mini"api_type ="responses"provider_tools = [{type ="web_search"}]provider_tools parameter.additional_tools withtype: "openai_custom":{ "model_name":"openai::gpt-5-mini", "input": { "messages": [ { "role":"user", "content":"Generate Python code to print 'Hello, World!'" } ] }, "additional_tools": [ { "type":"openai_custom", "name":"code_generator", "description":"Generates Python code snippets", "format": {"type":"text" } } ]}