Passa al contenuto principale

Tool Search e Deferred Loading

Avanzato
What you'll learn
  • Capire l'unica cosa che quasi tutti sbagliano su defer_loading: non rende la richiesta più piccola
  • Scegliere tra le varianti regex e BM25 della ricerca, conoscendo il limite di lunghezza della query di ciascuna
  • Leggere il trio di blocchi server_tool_use / tool_search_tool_result / tool_reference e sapere esattamente cosa rimandare indietro
  • Evitare le cinque forme di richiesta che restituiscono un 400, incluso il conflitto con cache_control
  • Integrare il deferred loading in un toolset del connettore MCP e sostituire la ricerca integrata con i tuoi embedding

I due problemi, e perché solo uno riguarda i soldi​

Caricare in anticipo tutte le definizioni dei tool si rompe in due modi distinti man mano che il catalogo cresce.

Il primo è quello ovvio. L'esempio di Anthropic: una configurazione MCP con cinque server — GitHub, Slack, Sentry, Grafana, Splunk — brucia circa 55k token in definizioni di tool prima che Claude faccia qualsiasi lavoro. È una tassa che paghi a ogni turno della conversazione.

Il secondo è quello che cambia davvero la tua architettura: l'accuratezza nella scelta del tool peggiora oltre i 30–50 tool disponibili. Oltre quella soglia, più tool non significa più capacità: significa un modello che sceglie da un menu affollato. Il deferred loading risolve il problema dei costi e quello dell'accuratezza con la stessa mossa, perché il modello vede sempre e solo i 3–5 tool rilevanti per la richiesta corrente. Anthropic riporta una riduzione del contesto di oltre l'85 percento su quella configurazione multiserver.

Se vuoi l'economia e i delta di accuratezza pubblicati, AILmanac li tratta in Costo in token di MCP. Questa pagina riguarda il cablaggio.

Il modello mentale che la gente sbaglia​

Ecco l'idea sbagliata da correggere prima di scrivere codice:

defer_loading non riduce ciò che invii. Continui a mettere la definizione completa di ogni tool — nomi, descrizioni, input_schema completo — nell'array tools a ogni singola richiesta, compresi i tool differiti.

Il corpo della tua richiesta HTTP non si restringe. La banda di upload non cambia. L'API ha bisogno di quelle definizioni lato server per eseguire la ricerca ed espandere i riferimenti che trova.

Ciò che cambia è cosa entra nella finestra di contesto, e quindi cosa ti viene fatturato. Le definizioni differite sono escluse dal prefisso del system prompt. Quando Claude ne scopre una, l'API aggiunge un blocco tool_reference in linea nella conversazione e lo espande nella definizione completa prima che il modello lo veda.

Quel dettaglio dell'aggiunta in linea è la seconda cosa non ovvia: poiché l'espansione avviene nella conversazione e non nel prefisso, il prefisso in cache non viene mai invalidato. Deferred loading e prompt caching si combinano. Lo stesso vale per lo strict tool use: la grammatica che vincola l'output delle chiamate ai tool è costruita sull'intero toolset, quindi nulla viene ricompilato quando un tool arriva a metà conversazione.

Attivarlo​

Guided walkthrough1 of 5
  1. Scegli una variante: tool_search_tool_regex_20251119 oppure tool_search_tool_bm25_20251119. È un server tool: gira sull'infrastruttura di Anthropic e non richiede alcun header beta.

Richiesta minima funzionante — un tool di ricerca, due tool differiti

curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
  "model": "claude-opus-5-5",
  "max_tokens": 2048,
  "messages": [{"role": "user", "content": "What is the weather in San Francisco?"}],
  "tools": [
    {
      "type": "tool_search_tool_regex_20251119",
      "name": "tool_search_tool_regex"
    },
    {
      "name": "get_weather",
      "description": "Get the weather at a specific location",
      "input_schema": {
        "type": "object",
        "properties": {
          "location": {"type": "string"},
          "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
        },
        "required": ["location"]
      },
      "defer_loading": true
    },
    {
      "name": "search_files",
      "description": "Search through files in the workspace",
      "input_schema": {
        "type": "object",
        "properties": {
          "query": {"type": "string"},
          "file_types": {"type": "array", "items": {"type": "string"}}
        },
        "required": ["query"]
      },
      "defer_loading": true
    }
  ]
}'

Nota cosa ti costa il tool di ricerca nel prefisso: nient'altro che la sua voce. Le due definizioni differite sono nel corpo ma non nel contesto.

Regex o BM25​

Entrambe le varianti cercano negli stessi quattro campi — nomi dei tool, descrizioni, nomi degli argomenti e descrizioni degli argomenti — ed entrambe sono disponibili su ogni modello che supporta la funzione. Differiscono solo in ciò che Claude scrive nella query.

tool_search_tool_regex_20251119tool_search_tool_bm25_20251119
Claude scrivepattern Python re.search()query in linguaggio naturale
Campo di inputpatternquery
Lunghezza massima200 caratteri500 caratteri
Corrispondenzasenza distinzione tra maiuscole e minuscoleranking BM25
Va bene quandoi tuoi nomi hanno un namespace (github_, slack_)le tue descrizioni si leggono come prosa

La variante regex è quella che la gente configura male, perché il nome fa pensare a una ricerca per parole chiave e non lo è. Claude scrive pattern veri: "weather", "get_.*_data", "database.*query|query.*database". Se il modello non trova un tool che ti aspetti, prova tu stesso il pattern prima di dare la colpa al modello:

Riprodurre in locale una corrispondenza regex fallita

import re
# Claude writes broad patterns, e.g. ".*weather.*" — not exact names.
# Search the same four fields the API searches.
haystacks = ["get_weather", "Get the weather at a specific location", "location", "unit"]
print(any(re.search(r"weather", h, re.IGNORECASE) for h in haystacks))

Il rimedio pratico a una corrispondenza mancata non è quasi mai un pattern più furbo: sono le parole chiave nella descrizione. Scrivi le parole che userebbero i tuoi utenti. Dai ai nomi dei tool un namespace per servizio, così un solo pattern ne spazza via un intero gruppo.

Leggere la risposta​

Una ricerca riuscita produce tre nuovi tipi di blocco nel turno dell'assistente, in quest'ordine:

{
"role": "assistant",
"content": [
{ "type": "text", "text": "I'll search for tools to help with the weather information." },
{
"type": "server_tool_use",
"id": "srvtoolu_01ABC123",
"name": "tool_search_tool_regex",
"input": { "pattern": "weather", "limit": 10 }
},
{
"type": "tool_search_tool_result",
"tool_use_id": "srvtoolu_01ABC123",
"content": {
"type": "tool_search_tool_search_result",
"tool_references": [{ "type": "tool_reference", "tool_name": "get_weather" }]
}
},
{
"type": "tool_use",
"id": "toolu_01XYZ789",
"name": "get_weather",
"input": { "location": "San Francisco", "unit": "fahrenheit" }
}
],
"stop_reason": "tool_use"
}

Tre regole per gestirla:

  1. Non restituire mai un tool_result per l'ID srvtoolu_.... La ricerca è già stata eseguita sui server di Anthropic. Se rispondi, l'API rifiuta la richiesta. Il tuo tool_result va solo all'ID toolu_...: da lì in poi è il normale uso dei tool.
  2. Non espandere mai tu i blocchi tool_reference. Lo fa l'API, purché la definizione corrispondente sia presente in tools.
  3. Lascia tool_search_tool_result nella cronologia così com'è. È il modo in cui i turni successivi sanno quali tool sono già stati scoperti.

Una ricerca senza risultati non è un errore: ricevi un tool_search_tool_search_result con un array tool_references vuoto, e Claude decide cosa fare dopo.

Un dettaglio sottile su limit: il valore predefinito è 5 risultati, ma Claude può impostare qualsiasi valore da 1 a 10.000 nel proprio input di ricerca. Non lo controlli direttamente. Se ti serve un tetto rigido al numero di definizioni che possono arrivare in massa, è un argomento a favore dell'implementazione personalizzata qui sotto.

I cinque 400​

Quattro sono errori di forma della richiesta che avvengono prima di qualsiasi inferenza, e uno è il conflitto che nessuno si aspetta.

Guided walkthrough1 of 5
  1. "At least one tool must have defer_loading=false. All tools cannot be deferred." La causa tipica è un ciclo che applica defer_loading: true all'intero array, tool di ricerca incluso. Non differire mai il tool di ricerca.

I fallimenti della ricerca durante l'esecuzione sono diversi: tornano con HTTP 200 e l'errore dentro un oggetto tool_search_tool_result_error.

error_codeCosa è successo
invalid_tool_inputRegex malformata, o pattern oltre il limite di 200 caratteri
unavailableLa ricerca non è potuta partire: timeout o servizio non disponibile
too_many_requestsRate limit specifico sulle operazioni di tool search
execution_time_exceededLa ricerca ha superato il limite di tempo di esecuzione

Trattali come recuperabili: la conversazione è intatta, e la mossa onesta è di solito lasciare che Claude riprovi con un pattern diverso invece di far fallire l'intero turno. Per la politica di retry circostante vedi Errori e rate limit.

Prompt caching​

Il titolo è positivo: le definizioni differite vivono fuori dal prefisso in cache, quindi aggiungere e scoprire tool a metà conversazione non lo invalida. Vedi Prompt caching per le regole sul prefisso, e Diagnostica della cache se devi dimostrare un hit.

La trappola è quella elencata sopra: defer_loading: true e cache_control si escludono a vicenda sullo stesso tool. Se il tuo breakpoint sta ora sull'ultimo tool di un array lungo e poi differisci quell'array, sei passato in silenzio da "in cache" a "400". Ancora il breakpoint a un tool che avresti comunque tenuto caricato.

Connettore MCP: impostalo sul toolset, non sul tool​

Con i tool che arrivano da server remoti tramite il connettore MCP, non tocchi le singole definizioni: non sono tue. Lo configuri sulla voce mcp_toolset: una volta per l'intero server tramite default_config, oppure per singolo tool in configs.

Differire un intero server MCP tranne l'unico tool che ti serve sempre

{
"type": "mcp_toolset",
"mcp_server_name": "observability",
"default_config": { "defer_loading": true },
"configs": {
  "search_events": { "defer_loading": false }
}
}

È la forma che ripaga più in fretta nella pratica: aggregare più server è esattamente la situazione da oltre 200 tool per cui la funzione esiste, e quasi sempre hai uno o due tool d'ingresso che vale la pena tenere caldi.

Sostituire la ricerca con la tua​

Entrambe le varianti integrate sono lessicali. Se i tuoi tool si trovano meglio per significato che per formulazione, implementa tu la ricerca: definisci un normale tool personalizzato e restituisci blocchi tool_reference in un tool_result ordinario.

Un risultato di ricerca lato client che l'API espanderà

{
"type": "tool_result",
"tool_use_id": "toolu_your_tool_id",
"content": [
  { "type": "tool_reference", "tool_name": "discovered_tool_name" }
]
}

Ogni nome che referenzi ha comunque bisogno della sua definizione completa nell'array tools di primo livello, di norma con defer_loading: true. Il percorso di espansione è identico: hai cambiato solo il recupero. Nota la differenza di formato: tool_search_tool_result è la forma lato server, interna alle varianti integrate. Il tuo tool personalizzato restituisce la forma standard tool_result mostrata sopra. Anthropic pubblica una ricetta completa con gli embedding.

È anche la tua via di fuga per il problema di limit: la tua ricerca decide quanti riferimenti tornano indietro.

Quando evitarlo​

Il deferred loading non ti dà nulla — e ti costa un round-trip di ricerca — quando la premessa non regge. Usalo quando almeno una di queste condizioni è vera:

  • 10 o più tool disponibili
  • definizioni dei tool sopra circa 10k token
  • accuratezza di selezione in calo visibile al crescere del catalogo
  • più server MCP aggregati (oltre 200 tool)
  • una libreria di tool che continua a crescere

Resta sulle normali chiamate ai tool quando hai meno di 10 tool, o ogni tool viene usato a ogni richiesta, o l'intero catalogo sta sotto i 100 token circa. E nota la forma della fatturazione: la tool search non è conteggiata come server tool separato. Non esiste alcun campo tool-search in usage.server_tool_use. Gli unici token che costa sono le definizioni che porta nel contesto, tariffate come qualsiasi altra definizione di tool.

I limiti rigidi, per la pianificazione della capacità: 10.000 tool differiti per richiesta, pattern regex da 200 caratteri, query BM25 da 500 caratteri.

Avvertenze di piattaforma​

Due note di deployment in cui è facile perdere una giornata. Su Amazon Bedrock, la tool search lato server funziona solo tramite l'API InvokeModel, non tramite l'API Converse. Su Claude Platform on AWS si comporta esattamente come la Claude API, perché quel percorso usa direttamente la Messages API e non ha la divisione InvokeModel/Converse. Claude Opus 4.1 e precedenti non supportano affatto la funzione.

Vocabolario della tool search
Premi Invio o Spazio per girare la carta. Usa le frecce sinistra e destra per spostarti tra le carte.Termine mostrato.
1 / 8

Verifica la tua comprensione

0/6
  1. Imposti defer_loading: true su 400 dei tuoi 405 tool. Cosa succede alla dimensione del JSON che invii con POST?
  2. Un ciclo applica defer_loading: true all'intero array tools. Cosa restituisce l'API?
  3. La tua risposta contiene un blocco server_tool_use con id srvtoolu_01ABC e un blocco tool_use con id toolu_01XYZ. Cosa rimandi indietro?
  4. Avevi già un breakpoint di cache sull'ultimo tool del tuo array. Ora differisci quell'array. Cosa si rompe?
  5. Claude non riesce a trovare i tuoi tool Grafana con la variante regex. Qual è la prima mossa migliore?
  6. Come viene fatturata la tool search?

Fonti e letture di approfondimento​

Prossimi passi​

  • Programmatic Tool Calling — l'altra metà dell'uso avanzato dei tool: la ricerca trova il tool giusto, la chiamata programmatica lo esegue senza trascinare i risultati nel contesto.
  • Costo in token di MCP — l'economia e i delta di accuratezza pubblicati dietro questa funzione.
  • Memoria ed editing del contesto — cosa fare per i risultati che riempiono il contesto, una volta gestite le definizioni.