SPB Git

Repository Public

tools-tool-search.md 38.4 KB 1,145 lines markdown

1# Tool search23> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.45Tool search allows the model to dynamically search for and load tools into the model's context as needed. This allows you to avoid loading all tool definitions into the model's context up front and **may help reduce overall token usage and cost**. For optimal cost and latency, tool search is designed to **preserve the model’s cache**. When new tools are discovered by the model, they are injected at the end of the context window.67In the Responses API, only `gpt-5.4` and later models support `tool_search`.89The following configuration and examples use the Responses API. For session-based function loading and automatic MCP discovery, see [Agents API](#agents-api).1011To activate tool search in the Responses API, you must do two things:12131. Add `tool_search` as a tool in your `tools` array.142. If you are using [functions](https://developers.openai.com/api/docs/guides/function-calling#defining-functions), mark the ones you want to defer with `defer_loading: true`. If you are using [MCP servers](https://developers.openai.com/api/docs/guides/tools-connectors-mcp), set `defer_loading: true` on the MCP server tool definition.1516### Use namespaces where possible1718You can use tool search with deferred [functions](https://developers.openai.com/api/docs/guides/function-calling#defining-functions), [namespaces](https://developers.openai.com/api/docs/guides/function-calling#defining-namespaces), or [MCP servers](https://developers.openai.com/api/docs/guides/tools-connectors-mcp), but we recommend using namespaces or MCP servers when possible. Our models have primarily been trained to search those surfaces, and token savings are usually more material there.1920For namespaces, `defer_loading` applies to the functions inside the namespace, not to the namespace object itself.2122At the start of a request, the model still sees the name and description of whatever is searchable. For a namespace or MCP server, that means the model sees only the namespace or server name and description at the beginning, without showing details of the individual functions contained within it until the tool search tool loads them. For an individual deferred function, the model still sees the function name and description, so in practice tool search is mostly deferring the parameter schema.2324For maximum token savings, we recommend grouping deferred functions into namespaces or MCP servers with clear, high-level descriptions that give the model a strong overview of what is contained within them, so it can effectively search and load only the relevant functions. As a best practice, aim to keep each namespace to fewer than 10 functions for better token efficiency and model performance.2526```json27{28    "tools": [29      {30// highlight-start:subtle31        "type": "namespace",32// highlight-end33        "name": "crm",34        "description": "CRM tools for customer lookup and order management.",35        "tools": [36          {37            "type": "function",38            "name": "list_open_orders",39            "description": "List open orders for a customer ID.",40// highlight-start:subtle41            "defer_loading": true,42// highlight-end43            "parameters": {44              "type": "object",45              "properties": {46                "customer_id": { "type": "string" }47              },48              "required": ["customer_id"],49              "additionalProperties": false50            }51          }52        ]53      },54      {55        "type": "tool_search"56      }57    ]58  }59```606162Namespaces can have a mix of tools that are deferred and not deferred. Tools without `defer_loading: true` are callable immediately, while deferred tools in the same namespace are loaded through tool search.6364### Tool search types6566Choose between two types of tool search:6768- **Hosted tool search:** OpenAI searches across the deferred tools you declared in the request and returns the loaded subset in the same response.69- **Client-executed tool search:** The model emits a `tool_search_call`, your application performs the lookup, and you return a matching `tool_search_output`.7071Start with hosted tool search if the candidate tools are already known when72  you create the request. Use client-executed tool search when tool discovery73  depends on project state, tenant state, or another system your application74  controls.7576## Hosted tool search7778Hosted tool search is the simplest path when you already know the full inventory of [functions](https://developers.openai.com/api/docs/guides/function-calling#defining-functions), [namespaces](https://developers.openai.com/api/docs/guides/function-calling#defining-namespaces), or [MCP servers](https://developers.openai.com/api/docs/guides/tools-connectors-mcp) you want the model to search. You declare them up front, add `{"type": "tool_search"}`, and let the API decide what to load.7980Configure hosted tool search8182```javascript83import OpenAI from "openai";8485const client = new OpenAI();8687const crmNamespace = {88  type: "namespace",89  name: "crm",90  description: "CRM tools for customer lookup and order management.",91  tools: [92    {93      type: "function",94      name: "get_customer_profile",95      description: "Fetch a customer profile by customer ID.",96      parameters: {97        type: "object",98        properties: {99          customer_id: { type: "string" },100        },101        required: ["customer_id"],102        additionalProperties: false,103      },104    },105    {106      type: "function",107      name: "list_open_orders",108      description: "List open orders for a customer ID.",109      // highlight-start:subtle110      defer_loading: true,111      // highlight-end112      parameters: {113        type: "object",114        properties: {115          customer_id: { type: "string" },116        },117        required: ["customer_id"],118        additionalProperties: false,119      },120    },121  ],122};123124const response = await client.responses.create({125  model: "gpt-6-astra",126  input: "List open orders for customer CUST-12345.",127  // highlight-start:subtle128  tools: [crmNamespace, { type: "tool_search" }],129  // highlight-end130  parallel_tool_calls: false,131});132133console.log(response.output);134```135136```python137from openai import OpenAI138139client = OpenAI()140141crm_namespace = {142    "type": "namespace",143    "name": "crm",144    "description": "CRM tools for customer lookup and order management.",145    "tools": [146        {147            "type": "function",148            "name": "get_customer_profile",149            "description": "Fetch a customer profile by customer ID.",150            "parameters": {151                "type": "object",152                "properties": {153                    "customer_id": {"type": "string"},154                },155                "required": ["customer_id"],156                "additionalProperties": False,157            },158        },159        {160            "type": "function",161            "name": "list_open_orders",162            "description": "List open orders for a customer ID.",163            # highlight-start:subtle164            "defer_loading": True,165            # highlight-end166            "parameters": {167                "type": "object",168                "properties": {169                    "customer_id": {"type": "string"},170                },171                "required": ["customer_id"],172                "additionalProperties": False,173            },174        },175    ],176}177178response = client.responses.create(179    model="gpt-6-astra",180    input="List open orders for customer CUST-12345.",181    tools=[182        crm_namespace,183        # highlight-start:subtle184        {"type": "tool_search"},185        # highlight-end186    ],187    parallel_tool_calls=False,188)189190print(response.output)191```192193```go194package main195196import (197	"context"198	"fmt"199200	"github.com/openai/openai-go/v3"201	"github.com/openai/openai-go/v3/responses"202)203204func main() {205	client := openai.NewClient()206	parameters := map[string]any{207		"type":                 "object",208		"properties":           map[string]any{"customer_id": map[string]any{"type": "string"}},209		"required":             []string{"customer_id"},210		"additionalProperties": false,211	}212	namespace := responses.ToolParamOfNamespace(213		"CRM tools for customer lookup and order management.",214		"crm",215		[]responses.NamespaceToolToolUnionParam{216			{OfFunction: &responses.NamespaceToolToolFunctionParam{217				Name: "get_customer_profile", Description: openai.String("Fetch a customer profile by customer ID."), Parameters: parameters,218			}},219			{OfFunction: &responses.NamespaceToolToolFunctionParam{220				Name: "list_open_orders", Description: openai.String("List open orders for a customer ID."), DeferLoading: openai.Bool(true), Parameters: parameters,221			}},222		},223	)224	response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{225		Model:             "gpt-6-astra",226		Input:             responses.ResponseNewParamsInputUnion{OfString: openai.String("List open orders for customer CUST-12345.")},227		Tools:             []responses.ToolUnionParam{namespace, {OfToolSearch: &responses.ToolSearchToolParam{}}},228		ParallelToolCalls: openai.Bool(false),229	})230	if err != nil {231		panic(err)232	}233	fmt.Println(response.Output)234}235```236237```java238import com.openai.client.OpenAIClient;239import com.openai.client.okhttp.OpenAIOkHttpClient;240import com.openai.core.JsonValue;241import com.openai.models.responses.NamespaceTool;242import com.openai.models.responses.ResponseCreateParams;243import com.openai.models.responses.ToolSearchTool;244import java.util.List;245import java.util.Map;246247ResponseCreateParams params =248    ResponseCreateParams.builder()249        .model("gpt-6-astra")250        .input("List open orders for customer CUST-12345.")251        .parallelToolCalls(false)252        .addTool(253            NamespaceTool.builder()254                .name("crm")255                .description("CRM tools for customer lookup and order management.")256                .addTool(257                    NamespaceTool.Tool.Function.builder()258                        .name("get_customer_profile")259                        .description("Fetch a customer profile by customer ID.")260                        .strict(true)261                        .parameters(262                            JsonValue.from(263                                Map.of(264                                    "type",265                                    "object",266                                    "properties",267                                    Map.of("customer_id", Map.of("type", "string")),268                                    "required",269                                    List.of("customer_id"),270                                    "additionalProperties",271                                    false)))272                        .build())273                .addTool(274                    NamespaceTool.Tool.Function.builder()275                        .name("list_open_orders")276                        .description("List open orders for a customer ID.")277                        .deferLoading(true)278                        .strict(true)279                        .parameters(280                            JsonValue.from(281                                Map.of(282                                    "type",283                                    "object",284                                    "properties",285                                    Map.of("customer_id", Map.of("type", "string")),286                                    "required",287                                    List.of("customer_id"),288                                    "additionalProperties",289                                    false)))290                        .build())291                .build())292        .addTool(ToolSearchTool.builder().execution(ToolSearchTool.Execution.SERVER).build())293        .build();294295client.responses().create(params).output().forEach(System.out::println);296```297298```ruby299require "openai"300301client = OpenAI::Client.new302parameters = {303  type: :object,304  properties: { customer_id: { type: :string } },305  required: ["customer_id"],306  additionalProperties: false307}308response = client.responses.create(309  model: "gpt-6-astra",310  input: "List open orders for customer CUST-12345.",311  parallel_tool_calls: false,312  tools: [313    {314      type: :namespace,315      name: "crm",316      description: "CRM tools for customer lookup and order management.",317      tools: [318        {319          type: :function,320          name: "get_customer_profile",321          description: "Fetch a customer profile by customer ID.",322          parameters: parameters323        },324        {325          type: :function,326          name: "list_open_orders",327          description: "List open orders for a customer ID.",328          defer_loading: true,329          parameters: parameters330        }331      ]332    },333    { type: :tool_search }334  ]335)336337puts(response.output)338```339340341If the model decides it needs a deferred tool, the response includes two additional output items before the eventual function call:342343- `tool_search_call`, which records the hosted search step.344- `tool_search_output`, which contains the loaded subset that becomes callable.345346Hosted tool search response347348```json349[350  {351    // highlight-start:subtle352    "type": "tool_search_call",353    // highlight-end354    "execution": "server",355    "call_id": null,356    "status": "completed",357    "arguments": {358      "paths": ["crm"]359    }360  },361  {362    // highlight-start:subtle363    "type": "tool_search_output",364    // highlight-end365    "execution": "server",366    "call_id": null,367    "status": "completed",368    "tools": [369      {370        "type": "namespace",371        "name": "crm",372        "description": "CRM tools for customer lookup and order management.",373        "tools": [374          {375            "type": "function",376            "name": "list_open_orders",377            "description": "List open orders for a customer ID.",378            "defer_loading": true,379            "parameters": {380              "type": "object",381              "properties": {382                "customer_id": { "type": "string" }383              },384              "required": ["customer_id"],385              "additionalProperties": false386            }387          }388        ]389      }390    ]391  },392  {393    "type": "function_call",394    "name": "list_open_orders",395    "namespace": "crm",396    "call_id": "call_abc123",397    "arguments": "{\"customer_id\":\"CUST-12345\"}"398  }399]400```401402403In hosted mode, `execution` is set to `server` and `call_id` is set to `null`.404405For more complex tasks, the model can also load multiple namespaces or MCP servers in the same `tool_search_call`. For example, if it needs functions from different namespaces to complete one task, it may choose to search and load those surfaces together before making the subsequent function calls.406407## Client-executed tool search408409Client-executed tool search gives your application full control over how tool discovery works. This is useful when the available tools depend on information that is not practical to declare in the initial `tools` list.410411Configure the `tool_search` tool with `execution: "client"` and a schema for the search arguments your application expects:412413Configure client-executed tool search414415```javascript416import OpenAI from "openai";417import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";418419const client = new OpenAI();420421const firstResponse = await client.responses.create({422  model: "gpt-6-astra",423  input: "Find the shipping ETA tool first, then use it for order_42.",424  tools: [425    {426      type: "tool_search",427      // highlight-start:subtle428      execution: "client",429      // highlight-end430      description:431        "Find the project-specific tools needed to continue the task.",432      parameters: {433        type: "object",434        properties: {435          goal: { type: "string" },436        },437        required: ["goal"],438        additionalProperties: false,439      },440    },441  ],442  parallel_tool_calls: false,443});444445const searchCall = firstResponse.output.find(446  (item) => item.type === "tool_search_call"447);448449if (!searchCall) {450  throw new Error("The response did not include a tool search call.");451}452453const loadedTools = [454  {455    type: "function",456    name: "get_shipping_eta",457    description: "Look up shipping ETA details for an order.",458    defer_loading: true,459    parameters: {460      type: "object",461      properties: {462        order_id: { type: "string" },463      },464      required: ["order_id"],465      additionalProperties: false,466    },467    strict: true,468  },469];470471const searchOutput = {472  type: "tool_search_output",473  execution: "client",474  call_id: searchCall.call_id,475  status: "completed",476  tools: loadedTools,477};478479const secondResponse = await client.responses.create({480  model: "gpt-6-astra",481  input: [482    ...toResponseInputItems(firstResponse.output),483    // highlight-start:subtle484    searchOutput,485    // highlight-end486  ],487});488489console.log(secondResponse.output);490```491492```python493from openai import OpenAI494495client = OpenAI()496497first_response = client.responses.create(498    model="gpt-6-astra",499    input="Find the shipping ETA tool first, then use it for order_42.",500    tools=[501        {502            "type": "tool_search",503            # highlight-start:subtle504            "execution": "client",505            # highlight-end506            "description": "Find the project-specific tools needed to continue the task.",507            "parameters": {508                "type": "object",509                "properties": {510                    "goal": {"type": "string"},511                },512                "required": ["goal"],513                "additionalProperties": False,514            },515        }516    ],517    parallel_tool_calls=False,518)519520search_call = next(521    item for item in first_response.output if item.type == "tool_search_call"522)523524loaded_tools = [525    {526        "type": "function",527        "name": "get_shipping_eta",528        "description": "Look up shipping ETA details for an order.",529        "defer_loading": True,530        "parameters": {531            "type": "object",532            "properties": {533                "order_id": {"type": "string"},534            },535            "required": ["order_id"],536            "additionalProperties": False,537        },538    }539]540541second_response = client.responses.create(542    model="gpt-6-astra",543    input=[544        *first_response.output,545        {546            # highlight-start:subtle547            "type": "tool_search_output",548            # highlight-end549            "execution": "client",550            "call_id": search_call.call_id,551            "status": "completed",552            # highlight-start:subtle553            "tools": loaded_tools,554            # highlight-end555        },556    ],557)558559print(second_response.output)560```561562```go563package main564565import (566	"context"567	"fmt"568569	"github.com/openai/openai-go/v3"570	"github.com/openai/openai-go/v3/responses"571)572573func main() {574	client := openai.NewClient()575	searchTool := responses.ToolUnionParam{OfToolSearch: &responses.ToolSearchToolParam{576		Execution:   responses.ToolSearchToolExecutionClient,577		Description: openai.String("Find the project-specific tools needed to continue the task."),578		Parameters: map[string]any{579			"type":                 "object",580			"properties":           map[string]any{"goal": map[string]any{"type": "string"}},581			"required":             []string{"goal"},582			"additionalProperties": false,583		},584	}}585	first, err := client.Responses.New(context.Background(), responses.ResponseNewParams{586		Model:             "gpt-6-astra",587		Input:             responses.ResponseNewParamsInputUnion{OfString: openai.String("Find the shipping ETA tool first, then use it for order_42.")},588		Tools:             []responses.ToolUnionParam{searchTool},589		ParallelToolCalls: openai.Bool(false),590	})591	if err != nil {592		panic(err)593	}594595	callID := ""596	for _, item := range first.Output {597		if item.Type == "tool_search_call" {598			callID = item.CallID599			break600		}601	}602	if callID == "" {603		panic("the response did not include a tool search call")604	}605	loadedTool := responses.ToolParamOfFunction("get_shipping_eta", map[string]any{606		"type":                 "object",607		"properties":           map[string]any{"order_id": map[string]any{"type": "string"}},608		"required":             []string{"order_id"},609		"additionalProperties": false,610	}, true)611	loadedTool.OfFunction.Description = openai.String("Look up shipping ETA details for an order.")612	loadedTool.OfFunction.DeferLoading = openai.Bool(true)613	searchOutput := responses.ResponseInputItemParamOfToolSearchOutput([]responses.ToolUnionParam{loadedTool})614	searchOutput.OfToolSearchOutput.CallID = openai.String(callID)615	searchOutput.OfToolSearchOutput.Execution = responses.ResponseToolSearchOutputItemParamExecutionClient616	searchOutput.OfToolSearchOutput.Status = responses.ResponseToolSearchOutputItemParamStatusCompleted617618	second, err := client.Responses.New(context.Background(), responses.ResponseNewParams{619		Model:              "gpt-6-astra",620		PreviousResponseID: openai.String(first.ID),621		Input:              responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{searchOutput}},622	})623	if err != nil {624		panic(err)625	}626	fmt.Println(second.Output)627}628```629630```java631import com.openai.client.OpenAIClient;632import com.openai.client.okhttp.OpenAIOkHttpClient;633import com.openai.core.JsonValue;634import com.openai.models.responses.FunctionTool;635import com.openai.models.responses.ResponseCreateParams;636import com.openai.models.responses.ResponseInputItem;637import com.openai.models.responses.ResponseToolSearchOutputItemParam;638import com.openai.models.responses.ToolSearchTool;639import java.util.List;640import java.util.Map;641642ResponseCreateParams searchRequest =643    ResponseCreateParams.builder()644        .model("gpt-6-astra")645        .input("Find the shipping ETA tool, then use it for order_42.")646        .parallelToolCalls(false)647        .addTool(648            ToolSearchTool.builder()649                .execution(ToolSearchTool.Execution.CLIENT)650                .description("Find the project tools needed to continue the task.")651                .parameters(652                    JsonValue.from(653                        Map.of(654                            "type",655                            "object",656                            "properties",657                            Map.of("goal", Map.of("type", "string")),658                            "required",659                            List.of("goal"),660                            "additionalProperties",661                            false)))662                .build())663        .build();664665var search = client.responses().create(searchRequest);666var searchCall =667    search.output().stream()668        .flatMap(item -> item.toolSearchCall().stream())669        .findFirst()670        .orElseThrow(() -> new IllegalStateException("No tool search call returned"));671672FunctionTool shippingTool =673    FunctionTool.builder()674        .name("get_shipping_eta")675        .description("Look up shipping details for an order.")676        .deferLoading(true)677        .strict(true)678        .parameters(679            FunctionTool.Parameters.builder()680                .putAdditionalProperty("type", JsonValue.from("object"))681                .putAdditionalProperty(682                    "properties", JsonValue.from(Map.of("order_id", Map.of("type", "string"))))683                .putAdditionalProperty("required", JsonValue.from(List.of("order_id")))684                .putAdditionalProperty("additionalProperties", JsonValue.from(false))685                .build())686        .build();687688var searchOutput =689    ResponseToolSearchOutputItemParam.builder()690        .callId(searchCall.callId().orElseThrow())691        .execution(ResponseToolSearchOutputItemParam.Execution.CLIENT)692        .status(ResponseToolSearchOutputItemParam.Status.COMPLETED)693        .addTool(shippingTool)694        .build();695696var response =697    client698        .responses()699        .create(700            ResponseCreateParams.builder()701                .model("gpt-6-astra")702                .previousResponseId(search.id())703                .inputOfResponse(List.of(ResponseInputItem.ofToolSearchOutput(searchOutput)))704                .build());705706var loadedCalls =707    response.output().stream().flatMap(item -> item.functionCall().stream()).toList();708if (loadedCalls.isEmpty()) {709  throw new IllegalStateException("No loaded function call returned");710}711loadedCalls.forEach(call -> System.out.println(call.name() + "(" + call.arguments() + ")"));712```713714```ruby715require "openai"716717client = OpenAI::Client.new718search = client.responses.create(719  model: "gpt-6-astra",720  input: "Find the shipping ETA tool, then use it for order_42.",721  parallel_tool_calls: false,722  tools: [723    {724      type: :tool_search,725      execution: :client,726      description: "Find the project tools needed to continue the task.",727      parameters: {728        type: :object,729        properties: { goal: { type: :string } },730        required: ["goal"],731        additionalProperties: false732      }733    }734  ]735)736call = search.output.find do |item|737  item.is_a?(OpenAI::Models::Responses::ResponseToolSearchCall)738end739unless call.is_a?(OpenAI::Models::Responses::ResponseToolSearchCall)740  raise "No tool search call returned"741end742743response = client.responses.create(744  model: "gpt-6-astra",745  previous_response_id: search.id,746  input: [747    {748      type: :tool_search_output,749      call_id: call.call_id,750      execution: :client,751      status: :completed,752      tools: [753        {754          type: :function,755          name: "get_shipping_eta",756          description: "Look up shipping details for an order.",757          defer_loading: true,758          strict: true,759          parameters: {760            type: :object,761            properties: { order_id: { type: :string } },762            required: ["order_id"],763            additionalProperties: false764          }765        }766      ]767    }768  ]769)770771function_calls = response.output.grep(772  OpenAI::Models::Responses::ResponseFunctionToolCall773)774raise "No loaded function call returned" if function_calls.empty?775776function_calls.each do |function_call|777  puts("#{function_call.name}(#{function_call.arguments})")778end779```780781782On the first turn, the model emits a `tool_search_call` and stops there:783784Client tool search call785786```json787[788  {789    "type": "tool_search_call",790    "execution": "client",791    "call_id": "call_abc123",792    "status": "completed",793    "arguments": {794      "goal": "Find the shipping ETA tool for order_42."795    }796  }797]798```799800801Your application then performs the search and returns a `tool_search_output` with the tools it wants to load:802803Return tool_search_output804805```json806[807  {808    "type": "tool_search_output",809    "execution": "client",810    "call_id": "call_abc123",811    "status": "completed",812    "tools": [813      {814        "type": "function",815        "name": "get_shipping_eta",816        "description": "Look up shipping ETA details for an order.",817        "defer_loading": true,818        "parameters": {819          "type": "object",820          "properties": {821            "order_id": { "type": "string" }822          },823          "required": ["order_id"],824          "additionalProperties": false825        }826      }827    ]828  }829]830```831832833On the next turn, the loaded tool is callable like a normal function:834835Loaded function call836837```json838[839  {840    "type": "function_call",841    "name": "get_shipping_eta",842    "namespace": "get_shipping_eta",843    "call_id": "call_xyz456",844    "arguments": "{\"order_id\":\"order_42\"}"845  }846]847```848849850In client mode, `execution` is set to `client` and `call_id` is defined. Echo the same `call_id` from the `tool_search_call` in your `tool_search_output`.851852## Advanced usage853854### Keep namespace descriptions clear855856Make namespace descriptions clear and descriptive of the use case, because the model relies on this description to decide when to load a subset of functions in that namespace. Avoid overly long descriptions. Instead, put richer detail in the deferred function descriptions that are loaded only when needed.857858### Understand what gets loaded859860`tool_search_output.tools` contains the list of tools that were dynamically loaded by the model. The model will be able to call any of these tools in future turns, so in client mode you do not need to load the same tool again across turns. Tools that were not listed as part of this array will not be available to the model. If you want to disable a loaded tool, you can remove it from the `tool_search_output` item where you define the loaded tool set, but note that changing the loaded tool set will break the model's cache from that point forward.861862### Advanced injection patterns863864Most integrations declare tools in the request's `tools` parameter. Client-executed tool search also supports more advanced patterns where your application returns tools that were not present in the original request. Treat this as an advanced workflow: validate the returned schemas carefully and only expose trusted tool definitions.865866### Tool search and caching867868All tools are loaded at the end of the model's context window. This holds true for both hosted tool search and client-executed tool search. This allows the model's cache to be preserved from one request to another, lowering overall costs and boosting speed.869870### Add tools at a specific point in the input871872For advanced workflows, you can use an `additional_tools` input item to make tools available at a specific point in the conversation. This is useful when your application loads tools outside the normal tool search flow or needs to preserve the ordering of tools added during a previous response.873874Set `role` to `developer` and include the tools to add in the item's `tools` array:875876```json877{878    "type": "additional_tools",879    "role": "developer",880    "tools": [881      {882        "type": "function",883        "name": "get_customer",884        "description": "Look up a customer by ID.",885        "parameters": {886          "type": "object",887          "properties": {888            "customer_id": { "type": "string" }889          },890          "required": ["customer_id"],891          "additionalProperties": false892        }893      }894    ]895  }896```897898899Tools in an `additional_tools` item become available only after that item appears in the input. When you manually round-trip conversation items, preserve the item's position so the model sees the same tools at the same point in the conversation.900901## Agents API902903The [Agents API](https://developers.openai.com/api/docs/guides/agents-api/overview) loads function definitions eagerly by default. To defer selected functions, include `{ "type": "tool_search" }` in `agent.tools` and set `defer_loading: true` on each function you want the agent to discover on demand. Adding `tool_search` does not defer every function.904905Your session request still supplies the full function definition, including its name, description, and argument schema. Tool search changes when that definition reaches the model. After discovery, your application handles the function call and returns its result as usual. See [Functions](https://developers.openai.com/api/docs/guides/agents-api/tools/functions) for result handling.906907Set `OPENAI_API_KEY` before running this example:908909Load function tools only when needed910911```javascript912import OpenAI from "openai";913const client = new OpenAI();914915const result = await client.beta.agents.sessions.create({916  agent: {917    model: "gpt-6-astra",918    tools: [919      {920        type: "tool_search",921      },922      {923        type: "function",924        name: "lookup_account",925        description: "Find an account by its account number.",926        parameters: {927          type: "object",928          properties: {929            account_id: {930              type: "string",931            },932          },933          required: ["account_id"],934          additionalProperties: false,935        },936        defer_loading: true,937      },938    ],939  },940  environment: {941    type: "none",942  },943  input: [944    {945      role: "user",946      content: [947        {948          type: "input_text",949          text: "Look up account 42.",950        },951      ],952    },953  ],954});955console.log(result.id);956```957958```python959from openai import OpenAI960961client = OpenAI()962963result = client.beta.agents.sessions.create(964    agent={965        "model": "gpt-6-astra",966        "tools": [967            {"type": "tool_search"},968            {969                "type": "function",970                "name": "lookup_account",971                "description": "Find an account by its account number.",972                "parameters": {973                    "type": "object",974                    "properties": {"account_id": {"type": "string"}},975                    "required": ["account_id"],976                    "additionalProperties": False,977                },978                "defer_loading": True,979            },980        ],981    },982    environment={"type": "none"},983    input=[984        {985            "role": "user",986            "content": [{"type": "input_text", "text": "Look up account 42."}],987        }988    ],989)990print(result.id)991```992993```go994import (995	"context"996	"fmt"997998	"github.com/openai/openai-go/v3"999)10001001ctx := context.Background()1002client := openai.NewClient()1003result, err := client.Beta.Agents.Sessions.New(ctx,1004	openai.BetaAgentSessionNewParams{1005		Agent: openai.BetaAgentSessionNewParamsAgent{1006			Model: openai.String("gpt-6-astra"),1007			Tools: []openai.AgentToolParamUnion{1008				{OfParamToolSearch: &openai.AgentToolParamToolSearch{}},1009				{1010					OfParamFunction: &openai.AgentToolParamFunction{1011						Name:        "lookup_account",1012						Description: "Find an account by its account number.",1013						Parameters: map[string]any{1014							"type":                 "object",1015							"properties":           map[string]any{"account_id": map[string]any{"type": "string"}},1016							"required":             []any{"account_id"},1017							"additionalProperties": false,1018						},1019						DeferLoading: openai.Bool(true),1020					},1021				},1022			},1023		},1024		Environment: openai.EnvironmentParamUnion{OfParamNone: &openai.EnvironmentParamNone{}},1025		Input: openai.BetaAgentSessionNewParamsInputUnion{1026			OfArrayOfInputMessages: []openai.AgentSessionInputMessageParam{1027				{1028					Content: []openai.InputContentParamUnion{1029						{OfParamInputText: &openai.InputContentParamInputText{Text: "Look up account 42."}},1030					},1031				},1032			},1033		},1034	})1035if err != nil {1036	panic(err)1037}1038fmt.Println(result.ID)1039```10401041```java1042import com.openai.client.OpenAIClient;1043import com.openai.client.okhttp.OpenAIOkHttpClient;1044import com.openai.core.JsonValue;1045import com.openai.models.beta.agents.AgentToolParam;1046import com.openai.models.beta.agents.sessions.SessionCreateParams;1047import java.util.List;1048import java.util.Map;10491050OpenAIClient client = OpenAIOkHttpClient.fromEnv();1051var result =1052    client1053        .beta()1054        .agents()1055        .sessions()1056        .create(1057            SessionCreateParams.builder()1058                .agent(1059                    SessionCreateParams.Agent.builder()1060                        .model("gpt-6-astra")1061                        .addToolToolSearch()1062                        .addTool(1063                            AgentToolParam.Function.builder()1064                                .name("lookup_account")1065                                .description("Find an account by its account number.")1066                                .parameters(1067                                    AgentToolParam.Function.Parameters.builder()1068                                        .putAdditionalProperty("type", JsonValue.from("object"))1069                                        .putAdditionalProperty(1070                                            "properties",1071                                            JsonValue.from(1072                                                Map.of("account_id", Map.of("type", "string"))))1073                                        .putAdditionalProperty(1074                                            "required", JsonValue.from(List.of("account_id")))1075                                        .putAdditionalProperty(1076                                            "additionalProperties", JsonValue.from(false))1077                                        .build())1078                                .deferLoading(true)1079                                .build())1080                        .build())1081                .environmentNone()1082                .input("Look up account 42.")1083                .build());1084System.out.println(result.id());1085```10861087```ruby1088require "openai"10891090client = OpenAI::Client.new1091result = client.beta.agents.sessions.create(1092  agent: {1093    model: "gpt-6-astra",1094    tools: [1095      { type: "tool_search" },1096      {1097        type: "function",1098        name: "lookup_account",1099        description: "Find an account by its account number.",1100        parameters: {1101          type: "object",1102          properties: { account_id: { type: "string" } },1103          required: ["account_id"],1104          additionalProperties: false1105        },1106        defer_loading: true1107      }1108    ]1109  },1110  environment: { type: "none" },1111  input: [1112    {1113      role: "user",1114      content: [1115        {1116          type: "input_text",1117          text: "Look up account 42."1118        }1119      ]1120    }1121  ]1122)1123puts result.id1124```112511261127### Choose a function loading strategy11281129| Strategy         | Configuration                                        | Useful for                                                    | Tradeoff                                                                                 |1130| ---------------- | ---------------------------------------------------- | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |1131| Eager loading    | Omit `defer_loading` or set it to `false`.           | A small set of functions, or functions needed for most tasks. | Unused definitions occupy context. Changing a definition can invalidate a cached prefix. |1132| Deferred loading | Set `defer_loading: true` and include `tool_search`. | A large catalog where each task needs only a few functions.   | Discovery adds a step and depends on finding the relevant tool.                          |11331134Mixing eager and deferred functions in an Agents API session is supported but generally not recommended. Give deferred functions clear names and descriptions. Compare task completion, input-token usage, and latency with representative requests before choosing a default.11351136### MCP and plugin tools11371138MCP tools use automatic discovery in the Agents API when the model and provider support tool search. The runtime defers MCP tools and adds tool search when searchable deferred tools are available. This applies to remote MCPs, executor MCPs, and MCP tools supplied by plugins.11391140You do not need to add `{ "type": "tool_search" }` just for MCP tools or set a function-level `defer_loading` flag on an MCP server. Configure the server using [MCP connections](https://developers.openai.com/api/docs/guides/agents-api/tools/mcp). The Responses API configuration earlier in this guide does not apply to Agents API MCP servers.11411142## Related guides11431144- Use [function calling](https://developers.openai.com/api/docs/guides/function-calling) to define callable functions and custom tools.1145- Use [Using tools](https://developers.openai.com/api/docs/guides/tools) for the broader tool landscape across Responses.
Files main
Menu

Theme