---
title: Messaggi di sistema e modifiche agli strumenti a metà conversazione
url: https://platform.claude.com/docs/it/build-with-claude/mid-conversation-system-messages
description: Modifica le istruzioni di sistema o la disponibilità degli strumenti a metà di una conversazione senza invalidare il prefisso in cache che le precede.
---

<Note>
  Per scoprire come la "zero data retention" (conservazione zero dei dati), o ZDR, si applica a questa funzionalità, consulta [API e conservazione dei dati](https://platform.claude.com/docs/it/manage-claude/api-and-data-retention).
</Note>

Le istruzioni di sistema si trovano normalmente nel campo di primo livello `system`, prima di ogni messaggio della conversazione. Questa posizione è ottima per il "prompt caching" ([cache dei prompt](https://platform.claude.com/docs/it/build-with-claude/prompt-caching)): il "system prompt" (prompt di sistema) fa parte del prefisso stabile, quindi i turni successivi trovano una corrispondenza nella cache. È invece poco adatta alle istruzioni di cui scopri di aver bisogno solo a metà di una sessione. Modificare il campo di primo livello `system` cambia infatti l'inizio stesso del prompt e invalida la cache per tutto ciò che segue.

I messaggi di sistema a metà conversazione colmano questa lacuna. Invece di modificare il campo di primo livello `system`, aggiungi un messaggio `{"role": "system"}` nel punto della conversazione in cui la nuova istruzione diventa rilevante. Il prefisso memorizzato nella cache resta invariato, quindi la richiesta successiva lo legge ancora dalla cache. La nuova istruzione viene comunque applicata come istruzione di sistema e non come normale testo dell'utente.

<Note>
  I messaggi di sistema a metà conversazione sono disponibili sulla Claude API, su [Claude in Amazon Bedrock](https://platform.claude.com/docs/it/build-with-claude/claude-in-amazon-bedrock) e su [Google Cloud](https://platform.claude.com/docs/it/build-with-claude/claude-on-vertex-ai).

  Questa funzionalità è disponibile su Claude Fable 5.1, [Claude Mythos 5.1](https://platform.claude.com/docs/it/models/mythos-5-1/overview), Claude Fable 5, [Claude Mythos 5](https://platform.claude.com/docs/it/models/mythos-5/overview), Claude Opus 5.5, Claude Opus 4.8, Claude Opus 5, Claude Sonnet 5.5 e Claude Haiku 5.5. Non è richiesto alcun "beta header" (header beta) per i messaggi di sistema a metà conversazione. Questa funzionalità non è disponibile su Claude Sonnet 5. Lì usa invece il campo `system` di primo livello.

  Le [modifiche agli strumenti a metà conversazione](https://platform.claude.com/docs/it/build-with-claude/mid-conversation-system-messages#mid-conversation-tool-changes) sono in beta sugli stessi modelli. Sulla Claude API, invia l'header beta `inline-tools-2026-09-15`, che copre anche la [definizione di uno strumento all'interno di un blocco `tool_addition`](https://platform.claude.com/docs/it/build-with-claude/mid-conversation-system-messages#define-tools-in-a-message-beta). [Aggiungere un server MCP in questo modo](https://platform.claude.com/docs/it/build-with-claude/mid-conversation-system-messages#add-an-mcp-server-mid-conversation-beta) richiede un secondo header beta, `mcp-client-2026-09-15`, disponibile sulla Claude API. L'header `mid-conversation-tool-changes-2026-07-01` funziona per le modifiche che nominano uno strumento per riferimento, sulla Claude API, su Amazon Bedrock e su Google Cloud.

  I [messaggi di sistema limitati al turno](https://platform.claude.com/docs/it/build-with-claude/mid-conversation-system-messages#turn-scoped-system-messages) (`clear_at`) sono in beta e richiedono l'header beta `mid-conversation-system-clear-at-2026-08-21`. Sono disponibili sugli stessi modelli e sulle stesse piattaforme dei messaggi di sistema a metà conversazione.
</Note>

## Modifiche agli strumenti a metà conversazione

L'array `tools` si trova ancora prima del campo `system` di primo livello nel prefisso della richiesta sottoposto a hash, quindi modificarlo invalida la [cache dei prompt](https://platform.claude.com/docs/it/build-with-claude/prompt-caching) per l'intera conversazione. Le modifiche agli strumenti a metà conversazione sono l'equivalente, per gli strumenti, dei messaggi di sistema a metà conversazione. Invece di fissare l'elenco degli strumenti per tutta la durata della conversazione, cambi quali strumenti vengono offerti al modello tra un turno e l'altro: dichiara l'intero set di strumenti in `tools` fin dall'inizio, poi usa i blocchi `tool_addition` e `tool_removal` per offrire uno strumento al modello, o ritirarlo, da un punto specifico della conversazione in poi. L'array `tools` stesso non cambia mai, quindi il prefisso memorizzato nella cache rimane intatto. Le modifiche agli strumenti a metà conversazione sono in beta e usano l'header beta `inline-tools-2026-09-15` sulla Claude API.

`tool_addition` e `tool_removal` sono blocchi di contenuto nell'array `content` di un messaggio `role: "system"` e possono essere combinati con blocchi `text` nello stesso messaggio. Il messaggio segue le regole di posizionamento di qualsiasi messaggio di sistema a metà conversazione, con una restrizione aggiuntiva dopo un turno in pausa (vedi [Limitazioni](https://platform.claude.com/docs/it/build-with-claude/mid-conversation-system-messages#limitations)), e la modifica si applica da quel punto della conversazione in poi. Il campo `tool` di ogni blocco fa riferimento a uno strumento anziché definirlo: `{"type": "tool_reference", "name": "..."}` nomina uno strumento dichiarato nell'array `tools` della richiesta, e gli strumenti del [connettore MCP](https://platform.claude.com/docs/it/agents-and-tools/mcp-connector) possono essere referenziati singolarmente con `mcp_tool_reference` (`server_name` e `name`) oppure come intero set di strumenti con `mcp_toolset_reference` (`server_name`). Fare riferimento a un nome non dichiarato in `tools` restituisce un errore 400 (sulla Claude API, con `error.details.error_code` impostato su `tool_reference_unresolved`). Un blocco `tool_addition` può invece [contenere la definizione completa dello strumento](https://platform.claude.com/docs/it/build-with-claude/mid-conversation-system-messages#define-tools-in-a-message-beta), cosa che l'header `mid-conversation-tool-changes-2026-07-01` non supporta.

Ogni strumento dichiarato in `tools` viene offerto al modello dall'inizio della conversazione, a meno che non sia dichiarato con `defer_loading: true`, che lo mantiene nascosto finché un blocco `tool_addition` non lo rende disponibile. `tool_addition` serve anche a offrire di nuovo uno strumento che un precedente `tool_removal` ha ritirato.

La seguente richiesta dichiara `get_weather` in `tools`, poi lo ritira dopo il primo turno dell'utente con un blocco `tool_removal`. La richiesta invia l'header beta `inline-tools-2026-09-15`.

<CodeGroup>
  ```bash cURL
  curl https://api.anthropic.com/v1/messages \
    -H "content-type: application/json" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: inline-tools-2026-09-15" \
    -d '{
      "model": "claude-opus-5-5",
      "max_tokens": 1024,
      "tools": [
        {
          "name": "get_weather",
          "description": "Get the current weather for a location.",
          "input_schema": {
            "type": "object",
            "properties": {
              "location": {"type": "string", "description": "City name"}
            },
            "required": ["location"]
          }
        }
      ],
      "messages": [
        {
          "role": "user",
          "content": "Say OK."
        },
        {
          "role": "system",
          "content": [
            {
              "type": "tool_removal",
              "tool": {"type": "tool_reference", "name": "get_weather"}
            }
          ]
        }
      ]
    }'
  ```

  ```bash CLI
  ant beta:messages create --beta inline-tools-2026-09-15 \
    --transform 'content.#(type=="text").text' --raw-output <<'YAML'
  model: claude-opus-5-5
  max_tokens: 1024
  tools:
    - name: get_weather
      description: Get the current weather for a location.
      input_schema:
        type: object
        properties:
          location:
            type: string
            description: City name
        required:
          - location
  messages:
    - role: user
      content: Say OK.
    - role: system
      content:
        - type: tool_removal
          tool:
            type: tool_reference
            name: get_weather
  YAML
  ```

  ```python Python
  client = anthropic.Anthropic()

  response = client.beta.messages.create(
      model="claude-opus-5-5",
      max_tokens=1024,
      betas=["inline-tools-2026-09-15"],
      # L'intero set di strumenti è dichiarato all'inizio e non cambia mai, quindi il
      # prefisso in cache resta intatto.
      tools=[
          {
              "name": "get_weather",
              "description": "Get the current weather for a location.",
              "input_schema": {
                  "type": "object",
                  "properties": {
                      "location": {"type": "string", "description": "City name"},
                  },
                  "required": ["location"],
              },
          },
      ],
      messages=[
          {
              "role": "user",
              "content": "Say OK.",
          },
          # Ritira get_weather da questo punto in poi. Il blocco fa riferimento
          # allo strumento per nome invece di modificare `tools`, così i turni precedenti restano
          # identici byte per byte e la cache viene comunque colpita.
          {
              "role": "system",
              "content": [
                  {
                      "type": "tool_removal",
                      "tool": {"type": "tool_reference", "name": "get_weather"},
                  },
              ],
          },
      ],
  )

  for block in response.content:
      if block.type == "text":
          print(block.text)
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  const response = await client.beta.messages.create({
    model: "claude-opus-5-5",
    max_tokens: 1024,
    betas: ["inline-tools-2026-09-15"],
    // L'intero set di strumenti è dichiarato all'inizio e non cambia mai, quindi il
    // prefisso in cache resta intatto.
    tools: [
      {
        name: "get_weather",
        description: "Get the current weather for a location.",
        input_schema: {
          type: "object",
          properties: {
            location: {
              type: "string",
              description: "City name"
            }
          },
          required: ["location"]
        }
      }
    ],
    messages: [
      { role: "user", content: "Say OK." },
      // Ritira get_weather da questo punto in poi. Il blocco fa riferimento allo
      // strumento per nome invece di modificare `tools`, così i turni precedenti restano
      // identici byte per byte e la cache viene comunque colpita.
      {
        role: "system",
        content: [
          {
            type: "tool_removal",
            tool: { type: "tool_reference", name: "get_weather" }
          }
        ]
      }
    ]
  });

  for (const block of response.content) {
    if (block.type === "text") {
      console.log(block.text);
    }
  }
  ```

  ```csharp C#
  using Anthropic.Models.Beta;
  using Anthropic.Models.Beta.Messages;
  using Messages = Anthropic.Models.Messages;

  AnthropicClient client = new();

  var response = await client.Beta.Messages.Create(new MessageCreateParams
  {
      Model = Messages::Model.ClaudeOpus5_5,
      MaxTokens = 1024,
      Betas = [AnthropicBeta.InlineTools2026_09_15],
      // L'intero set di strumenti è dichiarato in anticipo e non cambia mai, quindi il
      // prefisso in cache resta intatto.
      Tools =
      [
          new BetaTool
          {
              Name = "get_weather",
              Description = "Get the current weather for a location.",
              InputSchema = new InputSchema
              {
                  Properties = new Dictionary<string, JsonElement>
                  {
                      ["location"] = JsonSerializer.SerializeToElement(new { type = "string", description = "City name" }),
                  },
                  Required = ["location"],
              },
          },
      ],
      Messages =
      [
          new() { Role = Role.User, Content = "Say OK." },
          // Ritira get_weather da questo punto in poi. Il blocco fa riferimento
          // allo strumento per nome invece di modificare `Tools`, così i turni precedenti restano
          // identici byte per byte e la cache viene comunque colpita.
          new()
          {
              Role = Role.System,
              Content = new(
              [
                  new BetaRequestToolRemovalBlock
                  {
                      Tool = new BetaToolChangeToolReference { Name = "get_weather" },
                  },
              ]),
          },
      ],
  });

  foreach (var block in response.Content)
  {
      if (block.TryPickText(out var text))
      {
          Console.WriteLine(text.Text);
      }
  }
  ```

  ```go Go
  client := anthropic.NewClient()

  response, err := client.Beta.Messages.New(context.TODO(), anthropic.BetaMessageNewParams{
  	Model:     anthropic.ModelClaudeOpus5_5,
  	MaxTokens: 1024,
  	Betas:     []anthropic.AnthropicBeta{anthropic.AnthropicBetaInlineTools2026_09_15},
  	// Il set completo di strumenti è dichiarato all'inizio e non cambia mai, quindi il
  	// prefisso in cache resta intatto.
  	Tools: []anthropic.BetaToolUnionParam{
  		{OfTool: &anthropic.BetaToolParam{
  			Name:        "get_weather",
  			Description: anthropic.String("Get the current weather for a location."),
  			InputSchema: anthropic.BetaToolInputSchemaParam{
  				Properties: map[string]any{
  					"location": map[string]any{
  						"type":        "string",
  						"description": "City name",
  					},
  				},
  				Required: []string{"location"},
  			},
  		}},
  	},
  	Messages: []anthropic.BetaMessageParam{
  		anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("Say OK.")),
  		// Ritira get_weather da questo punto in poi. Il blocco fa riferimento
  		// allo strumento per nome invece di modificare Tools, così i turni precedenti restano
  		// identici byte per byte e la cache viene comunque colpita.
  		{
  			Role: anthropic.BetaMessageParamRoleSystem,
  			Content: []anthropic.BetaContentBlockParamUnion{
  				anthropic.NewBetaToolRemovalBlock(anthropic.BetaToolChangeToolReferenceParam{
  					Name: "get_weather",
  				}),
  			},
  		},
  	},
  })
  if err != nil {
  	log.Fatal(err)
  }

  for _, block := range response.Content {
  	if textBlock, ok := block.AsAny().(anthropic.BetaTextBlock); ok {
  		fmt.Println(textBlock.Text)
  	}
  }
  ```

  ```java Java
  import com.anthropic.models.beta.AnthropicBeta;
  import com.anthropic.models.beta.messages.BetaContentBlockParam;
  import com.anthropic.models.beta.messages.BetaMessage;
  import com.anthropic.models.beta.messages.BetaMessageParam;
  import com.anthropic.models.beta.messages.BetaRequestToolRemovalBlock;
  import com.anthropic.models.beta.messages.BetaTool;
  import com.anthropic.models.beta.messages.MessageCreateParams;
  // ...
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

      // L'intero set di strumenti è dichiarato all'inizio e non cambia mai, quindi il
      // prefisso in cache resta intatto.
      BetaTool weatherTool = BetaTool.builder()
          .name("get_weather")
          .description("Get the current weather for a location.")
          .inputSchema(BetaTool.InputSchema.builder()
              .properties(BetaTool.InputSchema.Properties.builder()
                  .putAdditionalProperty("location", JsonValue.from(Map.of(
                      "type", "string",
                      "description", "City name")))
                  .build())
              .addRequired("location")
              .build())
          .build();

      MessageCreateParams params = MessageCreateParams.builder()
          .model(Model.CLAUDE_OPUS_5_5)
          .maxTokens(1024)
          .addBeta(AnthropicBeta.INLINE_TOOLS_2026_09_15)
          .addTool(weatherTool)
          .addUserMessage("Say OK.")
          // Ritira get_weather da questo punto in poi. Il blocco fa riferimento
          // allo strumento per nome invece di modificare `tools`, così i turni precedenti restano
          // identici byte per byte e la cache viene ancora colpita.
          .addMessage(BetaMessageParam.builder()
              .role(BetaMessageParam.Role.SYSTEM)
              .contentOfBetaContentBlockParams(List.of(
                  BetaContentBlockParam.ofToolRemoval(BetaRequestToolRemovalBlock.builder()
                      .referenceTool("get_weather")
                      .build())))
              .build())
          .build();

      BetaMessage response = client.beta().messages().create(params);
      response.content().stream()
          .flatMap(block -> block.text().stream())
          .forEach(textBlock -> IO.println(textBlock.text()));
  ```

  ```php PHP
  use Anthropic\Beta\AnthropicBeta;
  // ...

  $client = new Client();

  $response = $client->beta->messages->create(
      model: Model::CLAUDE_OPUS_5_5,
      maxTokens: 1024,
      betas: [AnthropicBeta::INLINE_TOOLS_2026_09_15],
      // L'intero set di strumenti è dichiarato all'inizio e non cambia mai, quindi il
      // prefisso in cache resta intatto.
      tools: [
          [
              'name' => 'get_weather',
              'description' => 'Get the current weather for a location.',
              'input_schema' => [
                  'type' => 'object',
                  'properties' => [
                      'location' => [
                          'type' => 'string',
                          'description' => 'City name',
                      ],
                  ],
                  'required' => ['location'],
              ],
          ],
      ],
      messages: [
          ['role' => 'user', 'content' => 'Say OK.'],
          // Ritira get_weather da questo punto in poi. Il blocco fa riferimento
          // allo strumento per nome invece di modificare `tools`, così i turni precedenti restano
          // identici byte per byte e la cache viene comunque colpita.
          [
              'role' => 'system',
              'content' => [
                  [
                      'type' => 'tool_removal',
                      'tool' => ['type' => 'tool_reference', 'name' => 'get_weather'],
                  ],
              ],
          ],
      ],
  );

  foreach ($response->content as $block) {
      if ($block->type === 'text') {
          echo $block->text, PHP_EOL;
      }
  }
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  response = client.beta.messages.create(
    model: Anthropic::Model::CLAUDE_OPUS_5_5,
    max_tokens: 1024,
    betas: [Anthropic::AnthropicBeta::INLINE_TOOLS_2026_09_15],
    # Il set completo di strumenti è dichiarato all'inizio e non cambia mai, così il
    # prefisso in cache resta intatto.
    tools: [
      {
        name: "get_weather",
        description: "Get the current weather for a location.",
        input_schema: {
          type: "object",
          properties: {
            location: { type: "string", description: "City name" }
          },
          required: ["location"]
        }
      }
    ],
    messages: [
      { role: "user", content: "Say OK." },
      # Ritira get_weather da questo punto in poi. Il blocco fa riferimento
      # allo strumento per nome invece di modificare `tools`, così i turni precedenti restano
      # identici byte per byte e la cache viene comunque colpita.
      {
        role: "system",
        content: [
          {
            type: "tool_removal",
            tool: { type: "tool_reference", name: "get_weather" }
          }
        ]
      }
    ]
  )

  response.content.each do |block|
    puts block.text if block.type == :text
  end
  ```
</CodeGroup>

### Definire strumenti in un messaggio (beta)

Con l'header beta `inline-tools-2026-09-15`, un blocco `tool_addition` può definire uno strumento per valore, contenendone la definizione completa, invece di indicarlo per riferimento. Questo ti consente di introdurre uno strumento sconosciuto all'inizio della conversazione, o il cui schema cambia in seguito, aggiungendo un messaggio `role: "system"`. L'array `tools` e ogni messaggio precedente rimangono esattamente come inviati, quindi la cache dei prompt trova ancora corrispondenza e solo il messaggio aggiunto viene elaborato come nuovo input. L'unica eccezione, un array `tools` senza alcuno strumento non differito, è trattata nelle regole seguenti. L'header copre anche l'aggiunta e la rimozione di strumenti per riferimento, quindi non è necessario inviare anche `mid-conversation-tool-changes-2026-07-01`.

Racchiudi la definizione in un oggetto `tool` di tipo `tool_definition`. La `definition` è una voce di `tools`, come uno strumento personalizzato o uno strumento client o server definito da Anthropic, con la sua consueta configurazione, inclusi `cache_control` e `defer_loading`. Durante la beta, alcuni tipi di strumenti (tra cui lo strumento computer use) non possono ancora essere definiti in un messaggio e restituiscono un errore 400 che lo indica; dichiarali in `tools` e aggiungili per riferimento. Ad esempio, per definire uno strumento personalizzato a metà conversazione:

```json
{
  "role": "system",
  "content": [
    {
      "type": "tool_addition",
      "tool": {
        "type": "tool_definition",
        "definition": {
          "name": "db_query",
          "description": "Run a read-only SQL query against the analytics database.",
          "input_schema": {
            "type": "object",
            "properties": { "sql": { "type": "string" } },
            "required": ["sql"]
          }
        }
      }
    }
  ]
}
```

Da quella posizione in poi, il modello può chiamare lo strumento nello stesso modo in cui chiama uno strumento dichiarato in `tools`. Inviare di nuovo una definizione identica non cambia nulla, quindi un client può reinviarla in sicurezza, ad esempio in caso di nuovo tentativo.

La seguente richiesta mantiene `get_weather` in `tools` e definisce `db_query` dopo il primo turno dell'utente:

<CodeGroup>
  ```bash cURL
  curl https://api.anthropic.com/v1/messages \
    -H "content-type: application/json" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: inline-tools-2026-09-15" \
    -d '{
      "model": "claude-opus-5-5",
      "max_tokens": 1024,
      "tools": [
        {
          "name": "get_weather",
          "description": "Get the current weather for a location.",
          "input_schema": {
            "type": "object",
            "properties": {
              "location": {"type": "string", "description": "City name"}
            },
            "required": ["location"]
          }
        }
      ],
      "messages": [
        {
          "role": "user",
          "content": "How many orders shipped yesterday?"
        },
        {
          "role": "system",
          "content": [
            {
              "type": "tool_addition",
              "tool": {
                "type": "tool_definition",
                "definition": {
                  "name": "db_query",
                  "description": "Run a read-only SQL query against the analytics database.",
                  "input_schema": {
                    "type": "object",
                    "properties": {"sql": {"type": "string"}},
                    "required": ["sql"]
                  }
                }
              }
            }
          ]
        }
      ]
    }'
  ```

  ```bash CLI
  ant beta:messages create --beta inline-tools-2026-09-15 <<'YAML'
  model: claude-opus-5-5
  max_tokens: 1024
  # Mantieni almeno uno strumento non differito in `tools`, così uno strumento definito
  # in seguito non modifica l'inizio del prompt renderizzato.
  tools:
    - name: get_weather
      description: Get the current weather for a location.
      input_schema:
        type: object
        properties:
          location:
            type: string
            description: City name
        required:
          - location
  messages:
    - role: user
      content: How many orders shipped yesterday?
    # Da qui in poi definisci db_query per valore. `tools` e i
    # messaggi precedenti restano identici a quelli inviati, quindi la cache va ancora a segno.
    - role: system
      content:
        - type: tool_addition
          tool:
            type: tool_definition
            definition:
              name: db_query
              description: Run a read-only SQL query against the analytics database.
              input_schema:
                type: object
                properties:
                  sql:
                    type: string
                required:
                  - sql
  YAML
  ```

  ```python Python
  client = anthropic.Anthropic()

  response = client.beta.messages.create(
      model="claude-opus-5-5",
      max_tokens=1024,
      betas=["inline-tools-2026-09-15"],
      # Mantieni almeno uno strumento non differito in `tools`, così uno strumento definito
      # in seguito non modifica l'inizio del prompt renderizzato.
      tools=[
          {
              "name": "get_weather",
              "description": "Get the current weather for a location.",
              "input_schema": {
                  "type": "object",
                  "properties": {
                      "location": {"type": "string", "description": "City name"},
                  },
                  "required": ["location"],
              },
          },
      ],
      messages=[
          {"role": "user", "content": "How many orders shipped yesterday?"},
          # Da qui in poi definisci db_query per valore. `tools` e i
          # messaggi precedenti restano identici a quelli inviati, quindi la cache viene comunque colpita.
          {
              "role": "system",
              "content": [
                  {
                      "type": "tool_addition",
                      "tool": {
                          "type": "tool_definition",
                          "definition": {
                              "name": "db_query",
                              "description": "Run a read-only SQL query against the analytics database.",
                              "input_schema": {
                                  "type": "object",
                                  "properties": {"sql": {"type": "string"}},
                                  "required": ["sql"],
                              },
                          },
                      },
                  },
              ],
          },
      ],
  )

  for block in response.content:
      if block.type == "tool_use":
          print(block.name, block.input)
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  const response = await client.beta.messages.create({
    model: "claude-opus-5-5",
    max_tokens: 1024,
    betas: ["inline-tools-2026-09-15"],
    // Mantieni almeno uno strumento non differito in `tools`, così uno strumento definito
    // in seguito non modifica l'inizio del prompt renderizzato.
    tools: [
      {
        name: "get_weather",
        description: "Get the current weather for a location.",
        input_schema: {
          type: "object",
          properties: {
            location: { type: "string", description: "City name" }
          },
          required: ["location"]
        }
      }
    ],
    messages: [
      { role: "user", content: "How many orders shipped yesterday?" },
      // Da qui in poi definisci db_query per valore. `tools` e i
      // messaggi precedenti restano identici a quelli inviati, quindi la cache va ancora a segno.
      {
        role: "system",
        content: [
          {
            type: "tool_addition",
            tool: {
              type: "tool_definition",
              definition: {
                name: "db_query",
                description: "Run a read-only SQL query against the analytics database.",
                input_schema: {
                  type: "object",
                  properties: { sql: { type: "string" } },
                  required: ["sql"]
                }
              }
            }
          }
        ]
      }
    ]
  });

  for (const block of response.content) {
    if (block.type === "tool_use") {
      console.log(block.name, JSON.stringify(block.input));
    }
  }
  ```

  ```csharp C#
  using Anthropic.Models.Beta;
  using Anthropic.Models.Beta.Messages;
  using Messages = Anthropic.Models.Messages;

  AnthropicClient client = new();

  var response = await client.Beta.Messages.Create(new MessageCreateParams
  {
      Model = Messages::Model.ClaudeOpus5_5,
      MaxTokens = 1024,
      Betas = [AnthropicBeta.InlineTools2026_09_15],
      // Mantieni almeno uno strumento non differito in `Tools`, così uno strumento definito
      // in seguito non modifica l'inizio del prompt renderizzato.
      Tools =
      [
          new BetaTool
          {
              Name = "get_weather",
              Description = "Get the current weather for a location.",
              InputSchema = new InputSchema
              {
                  Properties = new Dictionary<string, JsonElement>
                  {
                      ["location"] = JsonSerializer.SerializeToElement(new { type = "string", description = "City name" }),
                  },
                  Required = ["location"],
              },
          },
      ],
      Messages =
      [
          new() { Role = Role.User, Content = "How many orders shipped yesterday?" },
          // Da qui in poi definisci db_query per valore. `Tools` e i
          // messaggi precedenti restano identici a quelli inviati, quindi la cache viene ancora colpita.
          new()
          {
              Role = Role.System,
              Content = new(
              [
                  new BetaRequestToolAdditionBlock
                  {
                      Tool = new BetaToolChangeToolDefinitionParam
                      {
                          Definition = new BetaTool
                          {
                              Name = "db_query",
                              Description = "Run a read-only SQL query against the analytics database.",
                              InputSchema = new InputSchema
                              {
                                  Properties = new Dictionary<string, JsonElement>
                                  {
                                      ["sql"] = JsonSerializer.SerializeToElement(new { type = "string" }),
                                  },
                                  Required = ["sql"],
                              },
                          },
                      },
                  },
              ]),
          },
      ],
  });

  foreach (var block in response.Content)
  {
      if (block.TryPickToolUse(out var toolUse))
      {
          Console.WriteLine($"{toolUse.Name} {JsonSerializer.Serialize(toolUse.Input)}");
      }
  }
  ```

  ```go Go
  client := anthropic.NewClient()

  response, err := client.Beta.Messages.New(context.TODO(), anthropic.BetaMessageNewParams{
  	Model:     anthropic.ModelClaudeOpus5_5,
  	MaxTokens: 1024,
  	Betas:     []anthropic.AnthropicBeta{anthropic.AnthropicBetaInlineTools2026_09_15},
  	// Mantieni almeno uno strumento non differito in Tools, così uno strumento definito
  	// in seguito non modifica l'inizio del prompt renderizzato.
  	Tools: []anthropic.BetaToolUnionParam{
  		{OfTool: &anthropic.BetaToolParam{
  			Name:        "get_weather",
  			Description: anthropic.String("Get the current weather for a location."),
  			InputSchema: anthropic.BetaToolInputSchemaParam{
  				Properties: map[string]any{
  					"location": map[string]any{
  						"type":        "string",
  						"description": "City name",
  					},
  				},
  				Required: []string{"location"},
  			},
  		}},
  	},
  	Messages: []anthropic.BetaMessageParam{
  		anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("How many orders shipped yesterday?")),
  		// Da qui in poi definisci db_query per valore. Tools e i
  		// messaggi precedenti restano identici a quelli inviati, quindi la cache va a segno.
  		{
  			Role: anthropic.BetaMessageParamRoleSystem,
  			Content: []anthropic.BetaContentBlockParamUnion{
  				anthropic.NewBetaToolAdditionBlock(anthropic.BetaToolChangeToolDefinitionParam{
  					Definition: anthropic.BetaToolUnionParam{OfTool: &anthropic.BetaToolParam{
  						Name:        "db_query",
  						Description: anthropic.String("Run a read-only SQL query against the analytics database."),
  						InputSchema: anthropic.BetaToolInputSchemaParam{
  							Properties: map[string]any{
  								"sql": map[string]any{"type": "string"},
  							},
  							Required: []string{"sql"},
  						},
  					}},
  				}),
  			},
  		},
  	},
  })
  if err != nil {
  	log.Fatal(err)
  }

  for _, block := range response.Content {
  	if toolUse, ok := block.AsAny().(anthropic.BetaToolUseBlock); ok {
  		fmt.Println(toolUse.Name, toolUse.Input)
  	}
  }
  ```

  ```java Java
  import com.anthropic.models.beta.AnthropicBeta;
  import com.anthropic.models.beta.messages.BetaContentBlockParam;
  import com.anthropic.models.beta.messages.BetaMessage;
  import com.anthropic.models.beta.messages.BetaRequestToolAdditionBlock;
  import com.anthropic.models.beta.messages.BetaTool;
  import com.anthropic.models.beta.messages.MessageCreateParams;
  // ...

  void main() {
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

      BetaTool weatherTool = BetaTool.builder()
          .name("get_weather")
          .description("Get the current weather for a location.")
          .inputSchema(BetaTool.InputSchema.builder()
              .properties(BetaTool.InputSchema.Properties.builder()
                  .putAdditionalProperty("location", JsonValue.from(Map.of(
                      "type", "string",
                      "description", "City name")))
                  .build())
              .addRequired("location")
              .build())
          .build();

      BetaTool dbQueryTool = BetaTool.builder()
          .name("db_query")
          .description("Run a read-only SQL query against the analytics database.")
          .inputSchema(BetaTool.InputSchema.builder()
              .properties(BetaTool.InputSchema.Properties.builder()
                  .putAdditionalProperty("sql", JsonValue.from(Map.of("type", "string")))
                  .build())
              .addRequired("sql")
              .build())
          .build();

      MessageCreateParams params = MessageCreateParams.builder()
          .model(Model.CLAUDE_OPUS_5_5)
          .maxTokens(1024)
          .addBeta(AnthropicBeta.INLINE_TOOLS_2026_09_15)
          // Mantieni almeno uno strumento non differito in `tools`, così uno strumento definito
          // in seguito non modifica l'inizio del prompt renderizzato.
          .addTool(weatherTool)
          .addUserMessage("How many orders shipped yesterday?")
          // Da qui in poi definisci db_query per valore. `tools` e i
          // messaggi precedenti restano identici a quelli inviati, quindi la cache va ancora a segno.
          .addSystemMessageOfBetaContentBlockParams(List.of(
              BetaContentBlockParam.ofToolAddition(BetaRequestToolAdditionBlock.builder()
                  .definitionTool(dbQueryTool)
                  .build())))
          .build();

      BetaMessage response = client.beta().messages().create(params);
      response.content().stream()
          .flatMap(block -> block.toolUse().stream())
          .forEach(toolUse -> IO.println(toolUse.name() + " " + toolUse._input()));
  }
  ```

  ```php PHP
  use Anthropic\Beta\AnthropicBeta;
  use Anthropic\Beta\Messages\BetaToolUseBlock;
  // ...

  $client = new Client();

  $response = $client->beta->messages->create(
      model: Model::CLAUDE_OPUS_5_5,
      maxTokens: 1024,
      betas: [AnthropicBeta::INLINE_TOOLS_2026_09_15],
      // Mantieni almeno uno strumento non differito in `tools`, così uno strumento definito
      // in seguito non modifica l'inizio del prompt renderizzato.
      tools: [
          [
              'name' => 'get_weather',
              'description' => 'Get the current weather for a location.',
              'input_schema' => [
                  'type' => 'object',
                  'properties' => [
                      'location' => [
                          'type' => 'string',
                          'description' => 'City name',
                      ],
                  ],
                  'required' => ['location'],
              ],
          ],
      ],
      messages: [
          ['role' => 'user', 'content' => 'How many orders shipped yesterday?'],
          // Da qui in poi definisci db_query per valore. `tools` e i
          // messaggi precedenti restano identici a quelli inviati, quindi la cache va a segno.
          [
              'role' => 'system',
              'content' => [
                  [
                      'type' => 'tool_addition',
                      'tool' => [
                          'type' => 'tool_definition',
                          'definition' => [
                              'name' => 'db_query',
                              'description' => 'Run a read-only SQL query against the analytics database.',
                              'input_schema' => [
                                  'type' => 'object',
                                  'properties' => ['sql' => ['type' => 'string']],
                                  'required' => ['sql'],
                              ],
                          ],
                      ],
                  ],
              ],
          ],
      ],
  );

  foreach ($response->content as $block) {
      if ($block instanceof BetaToolUseBlock) {
          echo $block->name, ' ', json_encode($block->input), PHP_EOL;
      }
  }
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  response = client.beta.messages.create(
    model: Anthropic::Model::CLAUDE_OPUS_5_5,
    max_tokens: 1024,
    betas: [Anthropic::AnthropicBeta::INLINE_TOOLS_2026_09_15],
    # Mantieni almeno uno strumento non differito in `tools`, così uno strumento definito
    # in seguito non modifica l'inizio del prompt renderizzato.
    tools: [
      {
        name: "get_weather",
        description: "Get the current weather for a location.",
        input_schema: {
          type: "object",
          properties: {
            location: { type: "string", description: "City name" }
          },
          required: ["location"]
        }
      }
    ],
    messages: [
      { role: "user", content: "How many orders shipped yesterday?" },
      # Da qui in poi definisci db_query per valore. `tools` e i
      # messaggi precedenti restano identici a quelli inviati, quindi la cache va ancora a segno.
      {
        role: "system",
        content: [
          {
            type: "tool_addition",
            tool: {
              type: "tool_definition",
              definition: {
                name: "db_query",
                description: "Run a read-only SQL query against the analytics database.",
                input_schema: {
                  type: "object",
                  properties: { sql: { type: "string" } },
                  required: ["sql"]
                }
              }
            }
          }
        ]
      }
    ]
  )

  response.content.each do |block|
    puts "#{block.name} #{block.input}" if block.is_a?(Anthropic::Beta::BetaToolUseBlock)
  end
  ```
</CodeGroup>

Il `content` della risposta include un blocco `tool_use` per il nuovo strumento, ad esempio:

```json
{
  "type": "tool_use",
  "id": "toolu_01A09q90qw90lq917835lq9",
  "name": "db_query",
  "input": {
    "sql": "SELECT COUNT(*) FROM orders WHERE shipped_at::date = CURRENT_DATE - 1"
  }
}
```

Per cambiare lo schema di uno strumento, o per passare a una versione più recente di uno strumento server, invia una definizione diversa con lo stesso nome. La nuova definizione sostituisce quella precedente da quella posizione in poi. Una definizione che riutilizza il nome di uno strumento di tipo diverso restituisce un errore 400 con `error.details.error_code` impostato su `tool_name_conflict`. Una versione più recente dello stesso strumento non conta come tipo diverso. `tool_removal` accetta comunque un riferimento, e uno strumento rimosso può essere definito od offerto di nuovo in seguito.

Alcune regole derivano dal punto in cui viene resa la definizione:

* **Dichiara in anticipo ciò che conosci.** Uno strumento che conosci al momento della prima richiesta va in `tools`, con `defer_loading: true` e un successivo riferimento `tool_addition` se il modello non deve ancora vederlo. Definisci per valore solo ciò che è sconosciuto alla prima richiesta o che cambia in seguito.
* **Mantieni almeno uno strumento non differito in `tools`.** Una conversazione il cui array `tools` non contiene alcuno strumento non differito viene accettata, ma il primo strumento che definisce per valore cambia l'inizio del prompt reso, il che comporta un "cache miss" (mancata corrispondenza nella cache) completo su quella richiesta. Uno [strumento di ricerca degli strumenti](https://platform.claude.com/docs/it/agents-and-tools/tool-use/tool-search-tool) conta come non differito.
* **I tipi di strumenti con data mantengono i propri header beta.** Se uno strumento server che definisci per valore richiede un proprio header beta, invia quell'header in ogni richiesta successiva della conversazione.
* **`cache_control` va sul blocco o nella definizione, non in entrambi,** e conta ai fini del limite di "breakpoint" (punti di interruzione) della richiesta. Una definizione differita non può contenere `cache_control`.

Una richiesta restituisce un errore 400 con `error.details.error_code` impostato su `available_tools_limit_exceeded` quando viene superato uno qualsiasi di questi limiti:

* Più di 10.000 strumenti differiti sono disponibili dopo un qualsiasi messaggio.
* Più di 10.000 strumenti definiti dopo il primo messaggio dell'utente sono disponibili dopo un qualsiasi messaggio.
* Le definizioni degli strumenti inviate dopo il primo messaggio dell'utente che sono ancora disponibili dopo un qualsiasi messaggio superano in totale 4 MB (4.194.304 byte).
* Il testo reso degli strumenti supera i 4 MB (4.194.304 byte).

### Aggiungere un server MCP a metà conversazione (beta)

Per aggiungere un server del [connettore MCP](https://platform.claude.com/docs/it/agents-and-tools/mcp-connector) a metà di una conversazione, invia l'header beta `mcp-client-2026-09-15` insieme a `inline-tools-2026-09-15`. La `definition` in un blocco `tool_addition` può quindi essere un `mcp_toolset`, così gli strumenti del server diventano disponibili senza modificare `tools`. Elenca come di consueto i dettagli di connessione del server in `mcp_servers`, poi aggiungi il toolset nel punto in cui il server è diventato disponibile:

```json
{
  "role": "system",
  "content": [
    {
      "type": "tool_addition",
      "tool": {
        "type": "tool_definition",
        "definition": { "type": "mcp_toolset", "mcp_server_name": "calendar" }
      }
    }
  ]
}
```

L'oggetto `mcp_toolset` è lo stesso che inseriresti in `tools`, inclusi `default_config` e `configs`. Un blocco `tool_addition` non contiene mai un URL o un token del server. Questi rimangono in `mcp_servers`.

La seguente richiesta mantiene `get_weather` in `tools`, elenca il server del calendario in `mcp_servers` e aggiunge il toolset del server dopo il primo turno dell'utente:

<CodeGroup>
  ```bash cURL
  curl https://api.anthropic.com/v1/messages \
    -H "content-type: application/json" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: inline-tools-2026-09-15,mcp-client-2026-09-15" \
    -d '{
      "model": "claude-opus-5-5",
      "max_tokens": 1024,
      "mcp_servers": [
        {
          "type": "url",
          "url": "https://mcp.example.com/calendar",
          "name": "calendar",
          "authorization_token": "YOUR_TOKEN"
        }
      ],
      "tools": [
        {
          "name": "get_weather",
          "description": "Get the current weather for a location.",
          "input_schema": {
            "type": "object",
            "properties": {
              "location": {"type": "string", "description": "City name"}
            },
            "required": ["location"]
          }
        }
      ],
      "messages": [
        {
          "role": "user",
          "content": "What'\''s on my calendar tomorrow?"
        },
        {
          "role": "system",
          "content": [
            {
              "type": "tool_addition",
              "tool": {
                "type": "tool_definition",
                "definition": {
                  "type": "mcp_toolset",
                  "mcp_server_name": "calendar"
                }
              }
            }
          ]
        }
      ]
    }'
  ```

  ```bash CLI
  ant beta:messages create \
    --beta inline-tools-2026-09-15,mcp-client-2026-09-15 <<'YAML'
  model: claude-opus-5-5
  max_tokens: 1024
  mcp_servers:
    - type: url
      url: https://mcp.example.com/calendar
      name: calendar
      authorization_token: YOUR_TOKEN
  tools:
    - name: get_weather
      description: Get the current weather for a location.
      input_schema:
        type: object
        properties:
          location:
            type: string
            description: City name
        required:
          - location
  messages:
    - role: user
      content: What's on my calendar tomorrow?
    # Rendi disponibili gli strumenti del server del calendario da questo punto in poi.
    # Il blocco indica il nome del server; non contiene mai un URL o un token.
    - role: system
      content:
        - type: tool_addition
          tool:
            type: tool_definition
            definition:
              type: mcp_toolset
              mcp_server_name: calendar
  YAML
  ```

  ```python Python
  client = anthropic.Anthropic()

  response = client.beta.messages.create(
      model="claude-opus-5-5",
      max_tokens=1024,
      betas=["inline-tools-2026-09-15", "mcp-client-2026-09-15"],
      mcp_servers=[
          {
              "type": "url",
              "url": "https://mcp.example.com/calendar",
              "name": "calendar",
              "authorization_token": "YOUR_TOKEN",
          },
      ],
      tools=[
          {
              "name": "get_weather",
              "description": "Get the current weather for a location.",
              "input_schema": {
                  "type": "object",
                  "properties": {
                      "location": {"type": "string", "description": "City name"},
                  },
                  "required": ["location"],
              },
          },
      ],
      messages=[
          {"role": "user", "content": "What's on my calendar tomorrow?"},
          # Rendi disponibili gli strumenti del server del calendario da questo punto in poi.
          # Il blocco indica il nome del server; non contiene mai un URL o un token.
          {
              "role": "system",
              "content": [
                  {
                      "type": "tool_addition",
                      "tool": {
                          "type": "tool_definition",
                          "definition": {
                              "type": "mcp_toolset",
                              "mcp_server_name": "calendar",
                          },
                      },
                  },
              ],
          },
      ],
  )

  # La risposta inizia con un blocco mcp_tool_listing per il server del calendario,
  # quindi controlla il tipo di ogni blocco invece di leggere content[0].
  for block in response.content:
      match block.type:
          case "mcp_tool_listing":
              print(block.mcp_server_name, [tool.name for tool in block.tools])
          case "text":
              print(block.text)
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  const response = await client.beta.messages.create({
    model: "claude-opus-5-5",
    max_tokens: 1024,
    betas: ["inline-tools-2026-09-15", "mcp-client-2026-09-15"],
    mcp_servers: [
      {
        type: "url",
        url: "https://mcp.example.com/calendar",
        name: "calendar",
        authorization_token: "YOUR_TOKEN"
      }
    ],
    tools: [
      {
        name: "get_weather",
        description: "Get the current weather for a location.",
        input_schema: {
          type: "object",
          properties: {
            location: { type: "string", description: "City name" }
          },
          required: ["location"]
        }
      }
    ],
    messages: [
      { role: "user", content: "What's on my calendar tomorrow?" },
      // Rendi disponibili gli strumenti del server del calendario da questo punto in poi.
      // Il blocco indica il nome del server; non contiene mai un URL o un token.
      {
        role: "system",
        content: [
          {
            type: "tool_addition",
            tool: {
              type: "tool_definition",
              definition: { type: "mcp_toolset", mcp_server_name: "calendar" }
            }
          }
        ]
      }
    ]
  });

  // La risposta inizia con un blocco mcp_tool_listing per il server del calendario,
  // quindi controlla il tipo di ogni blocco invece di leggere content[0].
  for (const block of response.content) {
    switch (block.type) {
      case "mcp_tool_listing":
        console.log(
          block.mcp_server_name,
          block.tools.map((tool) => tool.name)
        );
        break;
      case "text":
        console.log(block.text);
        break;
    }
  }
  ```

  ```csharp C#
  using Anthropic.Models.Beta;
  using Anthropic.Models.Beta.Messages;
  using Messages = Anthropic.Models.Messages;

  AnthropicClient client = new();

  var response = await client.Beta.Messages.Create(new MessageCreateParams
  {
      Model = Messages::Model.ClaudeOpus5_5,
      MaxTokens = 1024,
      Betas = [AnthropicBeta.InlineTools2026_09_15, AnthropicBeta.McpClient2026_09_15],
      McpServers =
      [
          new BetaRequestMcpServerUrlDefinition
          {
              Url = "https://mcp.example.com/calendar",
              Name = "calendar",
              AuthorizationToken = "YOUR_TOKEN",
          },
      ],
      Tools =
      [
          new BetaTool
          {
              Name = "get_weather",
              Description = "Get the current weather for a location.",
              InputSchema = new InputSchema
              {
                  Properties = new Dictionary<string, JsonElement>
                  {
                      ["location"] = JsonSerializer.SerializeToElement(new { type = "string", description = "City name" }),
                  },
                  Required = ["location"],
              },
          },
      ],
      Messages =
      [
          new() { Role = Role.User, Content = "What's on my calendar tomorrow?" },
          // Rendi disponibili gli strumenti del server del calendario da questo punto in poi.
          // Il blocco indica il nome del server; non contiene mai un URL o un token.
          new()
          {
              Role = Role.System,
              Content = new(
              [
                  new BetaRequestToolAdditionBlock
                  {
                      Tool = new BetaToolChangeToolDefinitionParam
                      {
                          Definition = new BetaMcpToolset("calendar"),
                      },
                  },
              ]),
          },
      ],
  });

  // La risposta inizia con un blocco mcp_tool_listing per il server del calendario,
  // quindi controlla il tipo di ogni blocco invece di leggere Content[0].
  foreach (var block in response.Content)
  {
      if (block.TryPickMcpToolListing(out var listing))
      {
          Console.WriteLine($"{listing.McpServerName} {JsonSerializer.Serialize(listing.Tools.Select(tool => tool.Name))}");
      }
      else if (block.TryPickText(out var text))
      {
          Console.WriteLine(text.Text);
      }
  }
  ```

  ```go Go
  client := anthropic.NewClient()

  response, err := client.Beta.Messages.New(context.TODO(), anthropic.BetaMessageNewParams{
  	Model:     anthropic.ModelClaudeOpus5_5,
  	MaxTokens: 1024,
  	Betas: []anthropic.AnthropicBeta{
  		anthropic.AnthropicBetaInlineTools2026_09_15,
  		anthropic.AnthropicBetaMCPClient2026_09_15,
  	},
  	MCPServers: []anthropic.BetaRequestMCPServerURLDefinitionParam{
  		{
  			URL:                "https://mcp.example.com/calendar",
  			Name:               "calendar",
  			AuthorizationToken: anthropic.String("YOUR_TOKEN"),
  		},
  	},
  	Tools: []anthropic.BetaToolUnionParam{
  		{OfTool: &anthropic.BetaToolParam{
  			Name:        "get_weather",
  			Description: anthropic.String("Get the current weather for a location."),
  			InputSchema: anthropic.BetaToolInputSchemaParam{
  				Properties: map[string]any{
  					"location": map[string]any{
  						"type":        "string",
  						"description": "City name",
  					},
  				},
  				Required: []string{"location"},
  			},
  		}},
  	},
  	Messages: []anthropic.BetaMessageParam{
  		anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("What's on my calendar tomorrow?")),
  		// Rendi disponibili gli strumenti del server del calendario da questo punto in poi.
  		// Il blocco indica il nome del server; non contiene mai un URL o un token.
  		{
  			Role: anthropic.BetaMessageParamRoleSystem,
  			Content: []anthropic.BetaContentBlockParamUnion{
  				anthropic.NewBetaToolAdditionBlock(anthropic.BetaToolChangeToolDefinitionParam{
  					Definition: anthropic.BetaToolUnionParam{OfMCPToolset: &anthropic.BetaMCPToolsetParam{
  						MCPServerName: "calendar",
  					}},
  				}),
  			},
  		},
  	},
  })
  if err != nil {
  	log.Fatal(err)
  }

  // La risposta inizia con un blocco mcp_tool_listing per il server del calendario,
  // quindi controlla il tipo di ogni blocco invece di leggere Content[0].
  for _, block := range response.Content {
  	switch variant := block.AsAny().(type) {
  	case anthropic.BetaMCPToolListingBlock:
  		var toolNames []string
  		for _, tool := range variant.Tools {
  			toolNames = append(toolNames, tool.Name)
  		}
  		fmt.Println(variant.MCPServerName, toolNames)
  	case anthropic.BetaTextBlock:
  		fmt.Println(variant.Text)
  	}
  }
  ```

  ```java Java
  import com.anthropic.models.beta.AnthropicBeta;
  import com.anthropic.models.beta.messages.BetaContentBlockParam;
  import com.anthropic.models.beta.messages.BetaMcpTool;
  import com.anthropic.models.beta.messages.BetaMcpToolset;
  import com.anthropic.models.beta.messages.BetaMessage;
  import com.anthropic.models.beta.messages.BetaRequestMcpServerUrlDefinition;
  import com.anthropic.models.beta.messages.BetaRequestToolAdditionBlock;
  import com.anthropic.models.beta.messages.BetaTool;
  import com.anthropic.models.beta.messages.MessageCreateParams;
  // ...

  void main() {
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

      BetaTool weatherTool = BetaTool.builder()
          .name("get_weather")
          .description("Get the current weather for a location.")
          .inputSchema(BetaTool.InputSchema.builder()
              .properties(BetaTool.InputSchema.Properties.builder()
                  .putAdditionalProperty("location", JsonValue.from(Map.of(
                      "type", "string",
                      "description", "City name")))
                  .build())
              .addRequired("location")
              .build())
          .build();

      MessageCreateParams params = MessageCreateParams.builder()
          .model(Model.CLAUDE_OPUS_5_5)
          .maxTokens(1024)
          .addBeta(AnthropicBeta.INLINE_TOOLS_2026_09_15)
          .addBeta(AnthropicBeta.MCP_CLIENT_2026_09_15)
          .addMcpServer(BetaRequestMcpServerUrlDefinition.builder()
              .url("https://mcp.example.com/calendar")
              .name("calendar")
              .authorizationToken("YOUR_TOKEN")
              .build())
          .addTool(weatherTool)
          .addUserMessage("What's on my calendar tomorrow?")
          // Rendi disponibili gli strumenti del server del calendario da questo punto in poi.
          // Il blocco indica il nome del server; non contiene mai un URL o un token.
          .addSystemMessageOfBetaContentBlockParams(List.of(
              BetaContentBlockParam.ofToolAddition(BetaRequestToolAdditionBlock.builder()
                  .definitionTool(BetaMcpToolset.builder()
                      .mcpServerName("calendar")
                      .build())
                  .build())))
          .build();

      BetaMessage response = client.beta().messages().create(params);

      // La risposta inizia con un blocco mcp_tool_listing per il server del calendario,
      // quindi controlla il tipo di ogni blocco invece di leggere il primo blocco.
      for (var block : response.content()) {
          switch (block.type().value()) {
              case MCP_TOOL_LISTING -> {
                  var listing = block.asMcpToolListing();
                  var toolNames = listing.tools().stream().map(BetaMcpTool::name).toList();
                  IO.println(listing.mcpServerName() + " " + toolNames);
              }
              case TEXT -> IO.println(block.asText().text());
          }
      }
  }
  ```

  ```php PHP
  use Anthropic\Beta\AnthropicBeta;
  use Anthropic\Beta\Messages\BetaMCPTool;
  use Anthropic\Beta\Messages\BetaMCPToolListingBlock;
  use Anthropic\Beta\Messages\BetaTextBlock;
  // ...

  $client = new Client();

  $response = $client->beta->messages->create(
      model: Model::CLAUDE_OPUS_5_5,
      maxTokens: 1024,
      betas: [
          AnthropicBeta::INLINE_TOOLS_2026_09_15,
          AnthropicBeta::MCP_CLIENT_2026_09_15,
      ],
      mcpServers: [
          [
              'type' => 'url',
              'url' => 'https://mcp.example.com/calendar',
              'name' => 'calendar',
              'authorization_token' => 'YOUR_TOKEN',
          ],
      ],
      tools: [
          [
              'name' => 'get_weather',
              'description' => 'Get the current weather for a location.',
              'input_schema' => [
                  'type' => 'object',
                  'properties' => [
                      'location' => [
                          'type' => 'string',
                          'description' => 'City name',
                      ],
                  ],
                  'required' => ['location'],
              ],
          ],
      ],
      messages: [
          ['role' => 'user', 'content' => "What's on my calendar tomorrow?"],
          // Rendi disponibili gli strumenti del server del calendario da questo punto in poi.
          // Il blocco indica il nome del server; non contiene mai un URL o un token.
          [
              'role' => 'system',
              'content' => [
                  [
                      'type' => 'tool_addition',
                      'tool' => [
                          'type' => 'tool_definition',
                          'definition' => [
                              'type' => 'mcp_toolset',
                              'mcp_server_name' => 'calendar',
                          ],
                      ],
                  ],
              ],
          ],
      ],
  );

  // La risposta inizia con un blocco mcp_tool_listing per il server del calendario,
  // quindi controlla il tipo di ogni blocco invece di leggere content[0].
  foreach ($response->content as $block) {
      switch (true) {
          case $block instanceof BetaMCPToolListingBlock:
              $toolNames = array_map(fn (BetaMCPTool $tool) => $tool->name, $block->tools);
              echo $block->mcpServerName, ' ', json_encode($toolNames), PHP_EOL;
              break;
          case $block instanceof BetaTextBlock:
              echo $block->text, PHP_EOL;
              break;
      }
  }
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  response = client.beta.messages.create(
    model: Anthropic::Model::CLAUDE_OPUS_5_5,
    max_tokens: 1024,
    betas: [
      Anthropic::AnthropicBeta::INLINE_TOOLS_2026_09_15,
      Anthropic::AnthropicBeta::MCP_CLIENT_2026_09_15
    ],
    mcp_servers: [
      {
        type: "url",
        url: "https://mcp.example.com/calendar",
        name: "calendar",
        authorization_token: "YOUR_TOKEN"
      }
    ],
    tools: [
      {
        name: "get_weather",
        description: "Get the current weather for a location.",
        input_schema: {
          type: "object",
          properties: {
            location: { type: "string", description: "City name" }
          },
          required: ["location"]
        }
      }
    ],
    messages: [
      { role: "user", content: "What's on my calendar tomorrow?" },
      # Rendi disponibili gli strumenti del server del calendario da questo punto in poi.
      # Il blocco indica il nome del server; non contiene mai un URL o un token.
      {
        role: "system",
        content: [
          {
            type: "tool_addition",
            tool: {
              type: "tool_definition",
              definition: { type: "mcp_toolset", mcp_server_name: "calendar" }
            }
          }
        ]
      }
    ]
  )

  # La risposta inizia con un blocco mcp_tool_listing per il server del calendario,
  # quindi controlla il tipo di ogni blocco invece di leggere content[0].
  response.content.each do |block|
    case block
    when Anthropic::Beta::BetaMCPToolListingBlock
      puts "#{block.mcp_server_name} #{block.tools.map(&:name)}"
    when Anthropic::Beta::BetaTextBlock
      puts block.text
    end
  end
  ```
</CodeGroup>

Con `mcp-client-2026-09-15`, una risposta per la quale l'API ha recuperato l'elenco degli strumenti di un server inizia con un blocco `mcp_tool_listing`, uno per ogni server recuperato. Se il tuo codice legge `content[0]`, salta questi blocchi. Reinvia il messaggio dell'assistente invariato, incluso questo blocco, e continua a inviare `mcp-client-2026-09-15` in ogni richiesta che lo contiene. Le richieste successive useranno quindi l'elenco registrato invece di interrogare di nuovo il server. Per fissare tu stesso un toolset, copia quell'elenco nel campo `tools` del `mcp_toolset`, come descritto in [Fissare l'elenco degli strumenti di un server MCP](https://platform.claude.com/docs/it/agents-and-tools/mcp-connector#pin-mcp-tool-list).

`mcp-client-2026-09-15` include tutto ciò che include `mcp-client-2025-11-20`, quindi non è necessario inviarli entrambi. Queste funzionalità sono disponibili sulla Claude API. Le richieste che usano il connettore MCP mantengono i suoi termini di [conservazione dei dati](https://platform.claude.com/docs/it/agents-and-tools/mcp-connector#data-retention).

## Quando usare un messaggio di sistema a metà conversazione

La [cache dei prompt](https://platform.claude.com/docs/it/build-with-claude/prompt-caching) calcola l'hash del prefisso della richiesta in ordine: `tools`, poi `system`, poi `messages`. Un riscontro nella cache richiede che il prefisso corrisponda esattamente, byte per byte, a una richiesta recente fino al breakpoint della cache.

Questo ordinamento significa che il campo `system` di primo livello si trova quasi all'inizio del prefisso sottoposto a hash. Qualsiasi modifica, anche l'aggiunta di una frase, produce un hash diverso, e la richiesta manca la cache per il prompt di sistema e per ogni messaggio in cache successivo.

I messaggi di sistema a metà conversazione ti permettono invece di aggiungere l'istruzione alla **fine** della cronologia dei messaggi. Tutto ciò che precede la nuova istruzione rimane invariato, quindi la voce di cache esistente corrisponde ancora, e solo il nuovo messaggio viene elaborato come input nuovo.

Alcune situazioni in cui questo è importante:

* **Cambi di policy o di persona a metà sessione.** Una lunga sessione agentica ha bisogno di un nuovo vincolo ("da ora in poi, scrivi tutto l'SQL come query parametrizzate") dopo decine di turni in cache. Aggiungerlo al campo `system` di primo livello rielaborerebbe l'intera cronologia.
* **Contesto per turno che deve essere autorevole.** Vuoi iniettare una nota di aggiornamento, una scadenza di sessione o un cambiamento nella disponibilità degli strumenti con peso a livello di sistema, e cambia troppo spesso per risiedere nel prefisso in cache.
* **Promemoria per turno che non devono accumularsi.** Un harness sollecita il modello dopo ogni gruppo di risultati degli strumenti ("richiedi insieme le letture indipendenti", "l'utente non ha tue notizie da un po'") e vuole che il modello veda solo la copia più recente. Un [messaggio di sistema limitato al turno](https://platform.claude.com/docs/it/build-with-claude/mid-conversation-system-messages#turn-scoped-system-messages) viene reso per un turno e poi non costa nulla, senza eliminare nulla dalla cronologia.
* **Cambiamenti di stato osservati dalla tua applicazione.** La tua applicazione nota qualcosa che Claude dovrebbe trattare come un fatto a livello di operatore: file modificati su disco, l'utente ha attivato o disattivato un'impostazione di approvazione automatica, gli strumenti disponibili sono cambiati, oppure il budget di token rimanente è sceso sotto una soglia.
* **Input dell'utente che non deve interrompere un ciclo agentico.** Un utente digita un messaggio di follow-up mentre Claude sta ancora eseguendo strumenti per la richiesta precedente. Inoltrarlo come messaggio di sistema dopo il successivo risultato dello strumento permette a Claude di integrare il nuovo input nel lavoro che sta già svolgendo, invece di trattarlo come una nuova richiesta a cui passare. Su Claude Sonnet 5.5 e Claude Haiku 5.5, aggiungi invece le parole dell'utente come blocco `text` dopo l'ultimo `tool_result` nello stesso messaggio `user`. Vedi [Posizionamento dopo i risultati degli strumenti](https://platform.claude.com/docs/it/build-with-claude/mid-conversation-system-messages#placement-after-tool-results).
* **Cambi di modalità che concedono permessi permanenti.** Una modalità a livello di sessione può usare un messaggio di sistema a metà conversazione per concedere un consenso permanente a una capacità costosa, come l'avvio automatico di flussi di lavoro multiagente, con un breve promemoria ogni tot turni e un avviso di uscita quando la modalità viene disattivata. Per un esempio completo, vedi [Costruire una modalità di orchestrazione](https://platform.claude.com/docs/it/build-with-claude/mid-conversation-effort-example).

In tutti questi casi potresti inserire l'istruzione in un normale messaggio `user`, e Claude segue effettivamente le istruzioni che arrivano nei turni utente. La differenza è la priorità: un messaggio `user` viene trattato come proveniente dall'utente finale, mentre un messaggio `system` viene trattato come proveniente da te, l'operatore dell'applicazione. Quando i due sono in conflitto, le istruzioni di sistema hanno la precedenza, quindi usa il ruolo `system` per fatti e vincoli a livello di operatore che devono valere anche se l'utente finale chiede qualcosa di diverso. Un messaggio di sistema a metà conversazione mantiene quella priorità a livello di operatore senza pagare il costo del mancato riscontro in cache dovuto alla modifica del campo `system` di primo livello.

## Come funziona

Aggiungi un messaggio con `"role": "system"` all'array `messages`. Usa una semplice stringa o blocchi di contenuto per `content`, come per un turno `user` o `assistant`. L'istruzione si applica da quel punto della conversazione in poi. Quando le istruzioni sono in conflitto, i messaggi di sistema successivi hanno la precedenza su quelli precedenti, e i messaggi di sistema a metà conversazione hanno la precedenza sul campo `system` di primo livello per i turni che li seguono.

Puoi comunque impostare il campo `system` di primo livello per le istruzioni che devono applicarsi all'intera conversazione. Riserva i messaggi di sistema a metà conversazione alle istruzioni che diventano rilevanti solo in seguito, o che vuoi aggiungere senza invalidare il prefisso memorizzato nella cache.

Un messaggio `role: "system"` può anche contenere `output_config.effort` per modificare il livello di [effort](https://platform.claude.com/docs/it/build-with-claude/effort) a metà di una conversazione. Questa funzionalità è in beta su Claude Fable 5.1, Claude Mythos 5.1, Claude Opus 5.5, Claude Opus 5, Claude Sonnet 5.5 e Claude Haiku 5.5 sulla Claude API e su Google Cloud, e richiede l'header beta `mid-conversation-output-config-2026-07-01`. Su Amazon Bedrock, è in beta su Claude Fable 5.1, Claude Mythos 5.1 e Claude Opus 5.5, con lo stesso valore beta. Claude Opus 5 non la supporta su Amazon Bedrock. Vedi [Effort per messaggio](https://platform.claude.com/docs/it/build-with-claude/effort#change-effort-mid-conversation-beta).

<CodeGroup>
  ```bash cURL
  curl https://api.anthropic.com/v1/messages \
    -H "content-type: application/json" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -d '{
      "model": "claude-opus-5-5",
      "max_tokens": 1024,
      "cache_control": {"type": "ephemeral"},
      "system": "You are a code review assistant. Be concise.",
      "messages": [
        {
          "role": "user",
          "content": "Review process() in utils.py for performance issues."
        },
        {
          "role": "assistant",
          "content": "The list comprehension is fine for small inputs. For large inputs, consider a generator to avoid materializing the full list."
        },
        {
          "role": "user",
          "content": "Now review the calling code that invokes process()."
        },
        {
          "role": "system",
          "content": "From now on, every suggestion must include explicit type annotations."
        }
      ]
    }'
  ```

  ```bash CLI
  ant messages create --transform 'content.#(type=="text").text' --raw-output <<'YAML'
  model: claude-opus-5-5
  max_tokens: 1024
  cache_control:
    type: ephemeral
  system: You are a code review assistant. Be concise.
  messages:
    - role: user
      content: Review process() in utils.py for performance issues.
    - role: assistant
      content: >-
        The list comprehension is fine for small inputs. For large inputs,
        consider a generator to avoid materializing the full list.
    - role: user
      content: Now review the calling code that invokes process().
    - role: system
      content: From now on, every suggestion must include explicit type annotations.
  YAML
  ```

  ```python Python
  client = anthropic.Anthropic()

  response = client.messages.create(
      model="claude-opus-5-5",
      max_tokens=1024,
      # "Prompt caching" (cache dei prompt) automatica: ogni richiesta mette in cache la conversazione finora,
      # e la richiesta successiva legge dalla cache il prefisso invariato.
      cache_control={"type": "ephemeral"},
      system="You are a code review assistant. Be concise.",
      messages=[
          {
              "role": "user",
              "content": "Review process() in utils.py for performance issues.",
          },
          {
              "role": "assistant",
              "content": "The list comprehension is fine for small inputs. For large inputs, consider a generator to avoid materializing the full list.",
          },
          {
              "role": "user",
              "content": "Now review the calling code that invokes process().",
          },
          # A metà sessione il revisore si accorge che tutti i suggerimenti devono
          # rispettare anche la rigida policy di tipizzazione del team. Aggiungere qui
          # l'istruzione mantiene i turni precedenti identici byte per byte, quindi il
          # prefisso messo in cache dalla richiesta precedente viene ancora letto dalla cache.
          {
              "role": "system",
              "content": "From now on, every suggestion must include explicit type annotations.",
          },
      ],
  )

  for block in response.content:
      if block.type == "text":
          print(block.text)
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  const response = await client.messages.create({
    model: "claude-opus-5-5",
    max_tokens: 1024,
    // "Prompt caching" (cache dei prompt) automatico: ogni richiesta salva in cache la conversazione finora,
    // e la richiesta successiva legge dalla cache il prefisso invariato.
    cache_control: { type: "ephemeral" },
    system: "You are a code review assistant. Be concise.",
    messages: [
      {
        role: "user",
        content: "Review process() in utils.py for performance issues."
      },
      {
        role: "assistant",
        content:
          "The list comprehension is fine for small inputs. For large inputs, consider a generator to avoid materializing the full list."
      },
      {
        role: "user",
        content: "Now review the calling code that invokes process()."
      },
      // A metà sessione il revisore si accorge che tutti i suggerimenti devono anche rispettare
      // la rigida policy di tipizzazione del team. Aggiungere qui l'istruzione mantiene
      // i turni precedenti identici byte per byte, quindi il prefisso salvato in cache dalla
      // richiesta precedente viene ancora letto dalla cache.
      {
        role: "system",
        content: "From now on, every suggestion must include explicit type annotations."
      }
    ]
  });

  const textBlock = response.content.find(
    (block): block is Anthropic.TextBlock => block.type === "text"
  );
  console.log(textBlock?.text);
  ```

  ```csharp C#
  AnthropicClient client = new();

  var parameters = new MessageCreateParams
  {
      Model = Model.ClaudeOpus5_5,
      MaxTokens = 1024,
      // "Prompt caching" (cache dei prompt) automatica: ogni richiesta mette in cache la conversazione fin qui,
      // e la richiesta successiva legge dalla cache il prefisso invariato.
      CacheControl = new CacheControlEphemeral(),
      System = "You are a code review assistant. Be concise.",
      Messages =
      [
          new()
          {
              Role = Role.User,
              Content = "Review process() in utils.py for performance issues."
          },
          new()
          {
              Role = Role.Assistant,
              Content = "The list comprehension is fine for small inputs. For large inputs, consider a generator to avoid materializing the full list."
          },
          new()
          {
              Role = Role.User,
              Content = "Now review the calling code that invokes process()."
          },
          // A metà sessione il revisore si accorge che tutti i suggerimenti devono rispettare anche
          // la rigida policy di tipizzazione del team. Aggiungere qui l'istruzione mantiene
          // i turni precedenti identici byte per byte, quindi il prefisso messo in cache dalla
          // richiesta precedente viene ancora letto dalla cache.
          new()
          {
              Role = Role.System,
              Content = "From now on, every suggestion must include explicit type annotations."
          }
      ]
  };

  var response = await client.Messages.Create(parameters);
  Console.WriteLine(response);
  ```

  ```go Go
  client := anthropic.NewClient()

  response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
  	Model:     anthropic.ModelClaudeOpus5_5,
  	MaxTokens: 1024,
  	// Prompt caching automatico (cache dei prompt): ogni richiesta mette in cache la conversazione fin qui,
  	// e la richiesta successiva legge dalla cache il prefisso invariato.
  	CacheControl: anthropic.NewCacheControlEphemeralParam(),
  	System: []anthropic.TextBlockParam{
  		{Text: "You are a code review assistant. Be concise."},
  	},
  	Messages: []anthropic.MessageParam{
  		anthropic.NewUserMessage(anthropic.NewTextBlock("Review process() in utils.py for performance issues.")),
  		anthropic.NewAssistantMessage(anthropic.NewTextBlock("The list comprehension is fine for small inputs. For large inputs, consider a generator to avoid materializing the full list.")),
  		anthropic.NewUserMessage(anthropic.NewTextBlock("Now review the calling code that invokes process().")),
  		// A metà sessione il revisore si accorge che tutti i suggerimenti devono anche
  		// rispettare la rigida policy di tipizzazione del team. Aggiungere l'istruzione
  		// qui mantiene i turni precedenti identici byte per byte, quindi il prefisso messo in cache dalla
  		// richiesta precedente viene ancora letto dalla cache.
  		{
  			Role: anthropic.MessageParamRoleSystem,
  			Content: []anthropic.ContentBlockParamUnion{
  				anthropic.NewTextBlock("From now on, every suggestion must include explicit type annotations."),
  			},
  		},
  	},
  })
  if err != nil {
  	log.Fatal(err)
  }
  for _, block := range response.Content {
  	if textBlock, ok := block.AsAny().(anthropic.TextBlock); ok {
  		fmt.Println(textBlock.Text)
  	}
  }
  ```

  ```java Java
  import com.anthropic.models.messages.CacheControlEphemeral;
  // ...
  import com.anthropic.models.messages.MessageParam;
  // ...
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

      MessageCreateParams params = MessageCreateParams.builder()
          .model(Model.CLAUDE_OPUS_5_5)
          .maxTokens(1024)
          // "Prompt caching" (cache dei prompt) automatico: ogni richiesta mette in cache la conversazione fin qui,
          // e la richiesta successiva legge dalla cache il prefisso invariato.
          .cacheControl(CacheControlEphemeral.builder().build())
          .system("You are a code review assistant. Be concise.")
          .addUserMessage("Review process() in utils.py for performance issues.")
          .addAssistantMessage("The list comprehension is fine for small inputs. For large inputs, consider a generator to avoid materializing the full list.")
          .addUserMessage("Now review the calling code that invokes process().")
          // A metà sessione il revisore si accorge che tutti i suggerimenti devono anche rispettare
          // la rigida policy di tipizzazione del team. Aggiungere qui l'istruzione mantiene
          // i turni precedenti identici byte per byte, quindi il prefisso messo in cache dalla
          // richiesta precedente viene ancora letto dalla cache.
          .addMessage(MessageParam.builder()
              .role(MessageParam.Role.SYSTEM)
              .content("From now on, every suggestion must include explicit type annotations.")
              .build())
          .build();

      Message response = client.messages().create(params);
      response.content().stream()
          .flatMap(block -> block.text().stream())
          .forEach(textBlock -> IO.println(textBlock.text()));
  ```

  ```php PHP
  use Anthropic\Messages\CacheControlEphemeral;
  // ...
  $client = new Client();

  $response = $client->messages->create(
      maxTokens: 1024,
      messages: [
          ['role' => 'user', 'content' => 'Review process() in utils.py for performance issues.'],
          ['role' => 'assistant', 'content' => 'The list comprehension is fine for small inputs. For large inputs, consider a generator to avoid materializing the full list.'],
          ['role' => 'user', 'content' => 'Now review the calling code that invokes process().'],
          // A metà sessione il revisore si accorge che tutti i suggerimenti devono rispettare anche
          // la rigida policy di tipizzazione del team. Aggiungere qui l'istruzione mantiene
          // i turni precedenti identici byte per byte, quindi il prefisso messo in cache dalla
          // richiesta precedente viene ancora letto dalla cache.
          ['role' => 'system', 'content' => 'From now on, every suggestion must include explicit type annotations.']
      ],
      model: 'claude-opus-5-5',
      // Cache dei prompt automatica: ogni richiesta mette in cache la conversazione fin qui,
      // e la richiesta successiva legge dalla cache il prefisso invariato.
      cacheControl: CacheControlEphemeral::with(),
      system: 'You are a code review assistant. Be concise.',
  );

  foreach ($response->content as $block) {
      if ($block->type === 'text') {
          echo $block->text, PHP_EOL;
      }
  }
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  response = client.messages.create(
    model: "claude-opus-5-5",
    max_tokens: 1024,
    # Cache dei prompt automatica: ogni richiesta memorizza in cache la conversazione finora,
    # e la richiesta successiva legge dalla cache il prefisso invariato.
    cache_control: { type: "ephemeral" },
    system: "You are a code review assistant. Be concise.",
    messages: [
      { role: "user", content: "Review process() in utils.py for performance issues." },
      { role: "assistant", content: "The list comprehension is fine for small inputs. For large inputs, consider a generator to avoid materializing the full list." },
      { role: "user", content: "Now review the calling code that invokes process()." },
      # A metà sessione il revisore si accorge che tutti i suggerimenti devono rispettare anche
      # la rigida policy di tipizzazione del team. Aggiungere qui l'istruzione mantiene
      # i turni precedenti identici byte per byte, quindi il prefisso messo in cache dalla
      # richiesta precedente viene ancora letto dalla cache.
      { role: "system", content: "From now on, every suggestion must include explicit type annotations." }
    ]
  )

  response.content.each do |block|
    puts block.text if block.type == :text
  end
  ```
</CodeGroup>

Questo esempio abilita la [cache automatica](https://platform.claude.com/docs/it/build-with-claude/prompt-caching#automatic-caching) con il campo `cache_control` di primo livello. La cache dei prompt è facoltativa (opt-in): se una richiesta non ha alcun campo `cache_control` (automatico o un [breakpoint esplicito](https://platform.claude.com/docs/it/build-with-claude/prompt-caching#explicit-cache-breakpoints)), non viene memorizzato nulla nella cache e ogni richiesta paga il prezzo normale dei token di input per l'intera conversazione. Con la cache abilitata, l'aggiunta del messaggio di sistema lascia invariati i turni già memorizzati nella cache, quindi la richiesta che contiene la nuova istruzione li legge ancora dalla cache invece di elaborarli di nuovo. La cache richiede inoltre che la conversazione raggiunga la [lunghezza minima del prompt memorizzabile nella cache](https://platform.claude.com/docs/it/build-with-claude/prompt-caching#cache-limitations); un esempio breve come questo è al di sotto di tale soglia, quindi `cache_creation_input_tokens` e `cache_read_input_tokens` restano a 0 finché la conversazione non cresce.

Un messaggio di sistema a metà conversazione che contiene contenuto (blocchi `text`, `tool_addition` o `tool_removal`) deve seguire immediatamente un turno `user` (o un turno `assistant` che termina con il risultato di uno strumento server) e deve essere l'ultima voce in `messages` oppure essere immediatamente seguito da un turno `assistant`. Un messaggio `user` che contiene blocchi `tool_result` conta: in un ciclo agentico puoi posizionare il messaggio di sistema subito dopo i risultati degli strumenti, prima del turno successivo di Claude. Qualsiasi altra posizione per un messaggio che contiene contenuto, inclusa quella tra un blocco `tool_use` di `assistant` e il `tool_result` che gli risponde, restituisce un errore 400. Un messaggio con `content` vuoto che imposta solo [`output_config.effort`](https://platform.claude.com/docs/it/build-with-claude/effort#change-effort-mid-conversation-beta) è accettato in qualsiasi punto di `messages`. I messaggi `system` consecutivi vengono valutati insieme, quindi un messaggio che imposta solo l'effort accanto a uno che contiene contenuto segue la regola per il contenuto.

### Posizionamento dopo i risultati degli strumenti

In un [ciclo agentico](https://platform.claude.com/docs/it/agents-and-tools/tool-use/overview), il messaggio di sistema va dopo il messaggio `user` che fornisce i risultati degli strumenti. Sulla maggior parte dei modelli, questo è anche il punto in cui la tua applicazione può inoltrare l'input che l'utente ha digitato mentre Claude stava lavorando, così il nuovo contesto viene assorbito senza riavviare il turno (per Claude Sonnet 5.5 e Claude Haiku 5.5, vedi la fine di questa sezione):

```json
[
  { "role": "user", "content": "Run the test suite and fix any failures." },
  {
    "role": "assistant",
    "content": [{ "type": "tool_use", "id": "toolu_01", "name": "run_tests", "input": {} }]
  },
  {
    "role": "user",
    "content": [
      { "type": "tool_result", "tool_use_id": "toolu_01", "content": "12 passed, 0 failed" }
    ]
  },
  {
    "role": "system",
    "content": "The user sent the following message while you were working: also update the changelog before you finish."
  }
]
```

Formula il contenuto di sistema come contesto anziché come un comando che prevale sull'utente. Enuncia il fatto ("è arrivato nuovo input dall'utente: X", "il budget di token rimanente è ora Y") e lascia che Claude agisca di conseguenza. Claude è addestrato a resistere alle istruzioni che sembrano andare contro l'utente, e quella protezione si applica anche al ruolo di sistema, quindi un linguaggio come "ignora ciò che ha detto l'utente" è meno efficace rispetto a indicare cosa è cambiato.

Questo schema serve a inoltrare input proveniente dall'utente finale della conversazione stessa. Non usarlo per passare output di strumenti, documenti recuperati o altri contenuti di terze parti; mantieni quei contenuti nei blocchi `tool_result` (vedi [Limitazioni](https://platform.claude.com/docs/it/build-with-claude/mid-conversation-system-messages#limitations)).

Su Claude Sonnet 5.5 e Claude Haiku 5.5, fornisci invece le parole dell'utente nel turno dell'utente. Questi modelli sono addestrati a resistere alla prompt injection tramite i risultati degli strumenti, quindi possono trattare un messaggio di sistema posizionato subito dopo il risultato di uno strumento come testo non attendibile e ignorarlo. Aggiungi le parole dell'utente come blocco `text` dopo l'ultimo `tool_result` nello stesso messaggio `user`. Mantieni gli avvisi dell'harness, come i promemoria, in un messaggio di sistema a metà conversazione separato dopo quel messaggio `user`, e non inserire mai un avviso e le parole dell'utente nello stesso blocco:

```json
[
  { "role": "user", "content": "Run the test suite and fix any failures." },
  {
    "role": "assistant",
    "content": [{ "type": "tool_use", "id": "toolu_01", "name": "run_tests", "input": {} }]
  },
  {
    "role": "user",
    "content": [
      { "type": "tool_result", "tool_use_id": "toolu_01", "content": "12 passed, 0 failed" },
      { "type": "text", "text": "Also update the changelog before you finish." }
    ]
  }
]
```

Per maggiori informazioni su questo comportamento, vedi [Scrivere prompt per Claude Sonnet 5.5](https://platform.claude.com/docs/it/build-with-claude/prompt-engineering/prompting-claude-sonnet-5-5#mid-turn-user-messages-and-task-budgets) e [Prompting per Claude Haiku 5.5](https://platform.claude.com/docs/it/build-with-claude/prompt-engineering/prompting-claude-haiku-5-5#mid-turn-user-messages).

### Messaggi di sistema limitati al turno

Per limitare un messaggio `role: "system"` al turno corrente, imposta il suo campo `clear_at`. Accetta uno di due valori:

* `"never"` (il valore predefinito): il messaggio viene reso nella sua posizione in ogni richiesta che lo include. Omettere il campo è equivalente.
* `"next_user_message"`: il messaggio è **limitato al turno**. Il suo testo viene reso solo finché nessun messaggio `role: "user"` lo segue in `messages`. Un messaggio dell'utente che contiene solo blocchi `tool_result` conta qui come messaggio dell'utente. Una volta che esiste un messaggio dell'utente successivo, il messaggio viene **cancellato**: rimane nell'array ma non rende nulla e non costa token di input, in quella richiesta e in ogni richiesta successiva.

I messaggi di sistema limitati al turno sono in beta. Includi l'[header beta](https://platform.claude.com/docs/it/api/beta-headers) `mid-conversation-system-clear-at-2026-08-21`. Senza di esso, `clear_at` viene rifiutato come campo sconosciuto.

```json
{
  "role": "system",
  "clear_at": "next_user_message",
  "content": "First privately list what you need next; then request every item that doesn't depend on another's result in this one response."
}
```

L'uso principale è un promemoria per turno in un ciclo di strumenti. Aggiungi il promemoria dopo il messaggio `tool_result` ogni volta che vuoi che il modello lo veda, e lascia ogni copia precedente dove si trova. Il modello vede solo le copie che seguono l'ultimo messaggio dell'utente, quindi il promemoria non si accumula mai. Nulla di precedente in `messages` cambia, quindi la [cache dei prompt](https://platform.claude.com/docs/it/build-with-claude/prompt-caching) continua a trovare corrispondenza. Su Claude Fable 5.1, Claude Opus 5.5, Claude Sonnet 5.5 e Claude Haiku 5.5 questo mantiene anche [validi i blocchi di ragionamento](https://platform.claude.com/docs/it/build-with-claude/thinking#preserved-in-conversation) successivi: eliminare un promemoria precedente cambierebbe la conversazione prima di quei blocchi e farebbe fallire il controllo della conversazione, mentre un messaggio cancellato rimane nell'array e lascia invariata quella conversazione.

La seguente richiesta è un passaggio successivo di un ciclo agentico. `messages[3]` è stato reso nella richiesta precedente, quando era l'ultimo messaggio dell'array. Una volta che esiste `messages[5]` (un messaggio dell'utente successivo), `messages[3]` viene cancellato: il messaggio cancellato rimane nell'array, quindi la conversazione prima del blocco di ragionamento in `messages[4]` è invariata, ma il modello non ne vede più il testo. `messages[6]` e `messages[7]` vengono entrambi resi, in ordine.

```json
{
  "model": "claude-fable-5-1",
  "max_tokens": 16000,
  "messages": [
    { "role": "user", "content": "Fix the failing test." },
    {
      "role": "assistant",
      "content": [
        { "type": "thinking", "thinking": "", "signature": "..." },
        {
          "type": "tool_use",
          "id": "toolu_01",
          "name": "read_file",
          "input": { "path": "test_auth.py" }
        }
      ]
    },
    {
      "role": "user",
      "content": [{ "type": "tool_result", "tool_use_id": "toolu_01", "content": "..." }]
    },
    {
      "role": "system",
      "clear_at": "next_user_message",
      "content": "Request independent reads in one turn."
    },
    {
      "role": "assistant",
      "content": [
        { "type": "thinking", "thinking": "", "signature": "..." },
        {
          "type": "tool_use",
          "id": "toolu_02",
          "name": "read_file",
          "input": { "path": "auth.py" }
        },
        {
          "type": "tool_use",
          "id": "toolu_03",
          "name": "read_file",
          "input": { "path": "tokens.py" }
        }
      ]
    },
    {
      "role": "user",
      "content": [
        { "type": "tool_result", "tool_use_id": "toolu_02", "content": "..." },
        {
          "type": "tool_result",
          "tool_use_id": "toolu_03",
          "content": "...",
          "cache_control": { "type": "ephemeral" }
        }
      ]
    },
    {
      "role": "system",
      "clear_at": "next_user_message",
      "content": "Request independent reads in one turn."
    },
    {
      "role": "system",
      "clear_at": "next_user_message",
      "content": "The shell exited with status 137."
    }
  ]
}
```

Regole per i messaggi limitati al turno:

* **Reinvia i messaggi cancellati alla lettera.** Un messaggio cancellato fa ancora parte della cronologia della conversazione. Ricostruirlo dallo stato corrente (un nuovo conteggio di token, un timestamp), eliminarlo perché ridondante o cambiarne il valore `clear_at` costituisce una modifica a un messaggio precedente. La cache dei prompt non trova corrispondenza da quel punto in poi, e su Claude Fable 5.1, Claude Opus 5.5, Claude Sonnet 5.5 e Claude Haiku 5.5 ogni blocco di ragionamento prodotto dopo di esso non supera il [controllo della conversazione](https://platform.claude.com/docs/it/build-with-claude/thinking#preserved-in-conversation).
* **Solo testo.** `content` è costituito da uno o più blocchi `text` (o da una stringa). I blocchi `tool_addition` e `tool_removal` restituiscono un errore 400 su un messaggio con ambito di turno, e lo stesso vale per `output_config`. Per questi usa un messaggio `role: "system"` separato senza `clear_at`.
* **Nessun `cache_control` sui suoi blocchi.** Un messaggio cancellato non fa mai parte di una chiave di cache, quindi un breakpoint su di esso non potrebbe mai trovare corrispondenza. Posiziona invece il breakpoint sull'ultimo blocco del turno dell'utente precedente, come fa l'esempio. Il campo di [cache automatica](https://platform.claude.com/docs/it/build-with-claude/prompt-caching#automatic-caching) di primo livello ignora i messaggi con ambito di turno quando sceglie un breakpoint. Nella richiesta che cancella un messaggio, il prefisso riutilizzabile memorizzato nella cache termina al turno dell'utente che lo precede, quindi viene rielaborato solo l'unico turno dell'assistente tra quel messaggio e il nuovo messaggio dell'utente.
* **Le regole di posizionamento si applicano comunque**, che il messaggio sia cancellato o meno. Un messaggio con ambito di turno deve seguire un turno `user` (o un turno `assistant` che termina con il risultato di uno strumento server) e precedere un turno `assistant` o chiudere l'array, come qualsiasi messaggio di sistema a metà conversazione. Uno che chiude l'array viene sempre reso. Uno seguito direttamente da un altro messaggio `user` è un errore 400, non un messaggio cancellato: inserisci tutti i risultati di un ciclo di strumenti in un unico messaggio dell'utente e i promemoria dopo di esso.
* **I turni dell'assistente non lo cancellano.** Un turno dell'assistente precompilato o [in pausa](https://platform.claude.com/docs/it/build-with-claude/handling-stop-reasons#pause-turn) dopo il messaggio, o un ciclo di strumenti lato server, non aggiunge alcun messaggio dell'utente, quindi il messaggio viene ancora reso in quella continuazione. Per mantenere visibile un promemoria durante un ciclo di strumenti lato client, aggiungilo di nuovo dopo ogni messaggio `tool_result`.
* **Il conteggio dei token segue ciò che viene reso.** Un messaggio cancellato non aggiunge nulla a `usage.input_tokens` né a un [conteggio dei token](https://platform.claude.com/docs/it/build-with-claude/token-counting).
* **Cronologia importata.** In una trascrizione che costruisci in un unico passaggio (esempi few-shot, una conversazione migrata), un messaggio con ambito di turno che ha già un turno dell'assistente e un messaggio dell'utente dopo di sé viene cancellato fin dalla prima richiesta e non viene mai reso. Questo è lo stato corretto per un promemoria per turno che stai trasferendo. Lascia `clear_at` non impostato solo su un messaggio che il modello deve vedere in ogni richiesta.

Gli errori di convalida sono:

```text wrap
messages.3.clear_at: Extra inputs are not permitted
messages.3.clear_at: clear_at is only permitted on role 'system' messages
messages.3.clear_at: Input should be 'next_user_message' or 'never'
messages.3: a turn-scoped system message supports text blocks only (clear_at: 'next_user_message')
messages.3: output_config is not permitted on a turn-scoped system message (clear_at: 'next_user_message')
messages.3.content.0: cache_control is not permitted on a turn-scoped system message (clear_at: 'next_user_message')
```

Il primo è l'errore restituito senza l'header beta. Su Google Cloud e su [Claude in Amazon Bedrock](https://platform.claude.com/docs/it/build-with-claude/claude-in-amazon-bedrock), invia il valore beta nell'header `anthropic-beta`, come sulla Claude API (vedi [Header beta](https://platform.claude.com/docs/it/api/beta-headers)). Con l'[API InvokeModel](https://platform.claude.com/docs/it/build-with-claude/claude-on-amazon-bedrock-legacy) di Amazon Bedrock, inseriscilo invece nell'array `anthropic_beta` del corpo della richiesta.

Tramite l'SDK, imposta `clear_at` (csharp, go: `ClearAt`; java: `.clearAt()`; php: `clearAt`) sulla voce `role: "system"` in `messages` e invia l'header beta. L'esempio seguente aggiunge un promemoria limitato al turno dopo il turno dell'utente; nella richiesta successiva, una volta che esiste un messaggio dell'utente successivo, il promemoria rimane nell'array ma non viene più reso:

<CodeGroup>
  ```bash cURL
  curl https://api.anthropic.com/v1/messages \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: mid-conversation-system-clear-at-2026-08-21" \
    -H "content-type: application/json" \
    -d '{
      "model": "claude-fable-5-1",
      "max_tokens": 4096,
      "messages": [
        {"role": "user", "content": "Draft a short status update on the database migration for the team channel."},
        {"role": "system", "clear_at": "next_user_message", "content": "The reader is on call: keep this reply under 50 words."}
      ]
    }'
  ```

  ```bash CLI
  ant beta:messages create --beta mid-conversation-system-clear-at-2026-08-21 \
    --transform 'content.#(type=="text").text' --raw-output <<'YAML'
  model: claude-fable-5-1
  max_tokens: 4096
  messages:
    - role: user
      content: Draft a short status update on the database migration for the team channel.
    # Promemoria limitato al turno: viene mostrato per questo turno, poi rimosso quando esiste un messaggio utente successivo.
    - role: system
      clear_at: next_user_message
      content: "The reader is on call: keep this reply under 50 words."
  YAML
  ```

  ```python Python
  client = anthropic.Anthropic()

  response = client.beta.messages.create(
      model="claude-fable-5-1",
      max_tokens=4096,
      messages=[
          {
              "role": "user",
              "content": "Draft a short status update on the database migration for the team channel.",
          },
          # Promemoria limitato al turno: viene mostrato per questo turno, poi rimosso quando esiste un messaggio utente successivo.
          {
              "role": "system",
              "clear_at": "next_user_message",
              "content": "The reader is on call: keep this reply under 50 words.",
          },
      ],
      betas=["mid-conversation-system-clear-at-2026-08-21"],
  )

  for block in response.content:
      if block.type == "text":
          print(block.text)
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  const response = await client.beta.messages.create({
    model: "claude-fable-5-1",
    max_tokens: 4096,
    messages: [
      {
        role: "user",
        content: "Draft a short status update on the database migration for the team channel."
      },
      // Promemoria limitato al turno: viene mostrato per questo turno, poi rimosso quando esiste un messaggio utente successivo.
      {
        role: "system",
        clear_at: "next_user_message",
        content: "The reader is on call: keep this reply under 50 words."
      }
    ],
    betas: ["mid-conversation-system-clear-at-2026-08-21"]
  });

  for (const block of response.content) {
    if (block.type === "text") {
      console.log(block.text);
    }
  }
  ```

  ```csharp C#
  using Anthropic.Models.Beta;
  using Anthropic.Models.Beta.Messages;
  using Messages = Anthropic.Models.Messages;

  AnthropicClient client = new();

  var response = await client.Beta.Messages.Create(new MessageCreateParams
  {
      Model = Messages::Model.ClaudeFable5_1,
      MaxTokens = 4096,
      Messages =
      [
          new() { Role = Role.User, Content = "Draft a short status update on the database migration for the team channel." },
          // Promemoria limitato al turno: viene mostrato per questo turno, poi rimosso quando esiste un messaggio utente successivo.
          new()
          {
              Role = Role.System,
              ClearAt = ClearAt.NextUserMessage,
              Content = "The reader is on call: keep this reply under 50 words.",
          },
      ],
      Betas = [AnthropicBeta.MidConversationSystemClearAt2026_08_21],
  });

  foreach (var block in response.Content)
  {
      if (block.TryPickText(out var textBlock))
      {
          Console.WriteLine(textBlock.Text);
      }
  }
  ```

  ```go Go
  client := anthropic.NewClient()

  response, err := client.Beta.Messages.New(context.Background(), anthropic.BetaMessageNewParams{
  	Model:     anthropic.ModelClaudeFable5_1,
  	MaxTokens: 4096,
  	Messages: []anthropic.BetaMessageParam{
  		anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("Draft a short status update on the database migration for the team channel.")),
  		// Promemoria limitato al turno: viene mostrato per questo turno, poi rimosso quando esiste un messaggio utente successivo.
  		{
  			Role:    anthropic.BetaMessageParamRoleSystem,
  			ClearAt: anthropic.BetaMessageParamClearAtNextUserMessage,
  			Content: []anthropic.BetaContentBlockParamUnion{anthropic.NewBetaTextBlock("The reader is on call: keep this reply under 50 words.")},
  		},
  	},
  	Betas: []anthropic.AnthropicBeta{anthropic.AnthropicBetaMidConversationSystemClearAt2026_08_21},
  })
  if err != nil {
  	log.Fatal(err)
  }

  for _, block := range response.Content {
  	if textBlock, ok := block.AsAny().(anthropic.BetaTextBlock); ok {
  		fmt.Println(textBlock.Text)
  	}
  }
  ```

  ```java Java
  import com.anthropic.models.beta.AnthropicBeta;
  import com.anthropic.models.beta.messages.BetaMessage;
  import com.anthropic.models.beta.messages.BetaMessageParam;
  import com.anthropic.models.beta.messages.MessageCreateParams;
  import com.anthropic.models.messages.Model;

  void main() {
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

      MessageCreateParams params = MessageCreateParams.builder()
          .model(Model.CLAUDE_FABLE_5_1)
          .maxTokens(4096L)
          .addBeta(AnthropicBeta.MID_CONVERSATION_SYSTEM_CLEAR_AT_2026_08_21)
          .addUserMessage("Draft a short status update on the database migration for the team channel.")
          // Promemoria limitato al turno: viene mostrato in questo turno, poi rimosso quando esiste un messaggio utente successivo.
          .addMessage(BetaMessageParam.builder()
              .role(BetaMessageParam.Role.SYSTEM)
              .clearAt(BetaMessageParam.ClearAt.NEXT_USER_MESSAGE)
              .content("The reader is on call: keep this reply under 50 words.")
              .build())
          .build();

      BetaMessage response = client.beta().messages().create(params);
      response.content().stream()
          .flatMap(block -> block.text().stream())
          .forEach(textBlock -> IO.println(textBlock.text()));
  }
  ```

  ```php PHP
  use Anthropic\Beta\AnthropicBeta;
  use Anthropic\Beta\Messages\BetaMessageParam;
  use Anthropic\Client;

  $client = new Client();

  $response = $client->beta->messages->create(
      model: 'claude-fable-5-1',
      maxTokens: 4096,
      messages: [
          BetaMessageParam::with(role: 'user', content: 'Draft a short status update on the database migration for the team channel.'),
          // Promemoria limitato al turno: viene mostrato per questo turno, poi rimosso quando esiste un messaggio utente successivo.
          BetaMessageParam::with(
              role: 'system',
              clearAt: 'next_user_message',
              content: 'The reader is on call: keep this reply under 50 words.',
          ),
      ],
      betas: [AnthropicBeta::MID_CONVERSATION_SYSTEM_CLEAR_AT_2026_08_21],
  );

  foreach ($response->content as $block) {
      if ($block->type === 'text') {
          echo $block->text, PHP_EOL;
      }
  }
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  response = client.beta.messages.create(
    model: "claude-fable-5-1",
    max_tokens: 4096,
    messages: [
      {role: "user", content: "Draft a short status update on the database migration for the team channel."},
      # Promemoria limitato al turno: viene mostrato per questo turno, poi rimosso quando esiste un messaggio utente successivo.
      {role: "system", clear_at: :next_user_message, content: "The reader is on call: keep this reply under 50 words."}
    ],
    betas: [Anthropic::AnthropicBeta::MID_CONVERSATION_SYSTEM_CLEAR_AT_2026_08_21]
  )

  response.content.each do |block|
    puts block.text if block.type == :text
  end
  ```
</CodeGroup>

## Combinazione con la cache dei prompt

I messaggi di sistema a metà conversazione e il ["prompt caching"](https://platform.claude.com/docs/it/build-with-claude/prompt-caching) (cache dei prompt) sono progettati per essere usati insieme:

* **Abilita la cache esplicitamente.** La memorizzazione nella cache avviene solo quando la richiesta include `cache_control`, tramite il campo di primo livello per la [cache automatica](https://platform.claude.com/docs/it/build-with-claude/prompt-caching#automatic-caching) oppure tramite un ["breakpoint" (punto di interruzione) esplicito](https://platform.claude.com/docs/it/build-with-claude/prompt-caching#explicit-cache-breakpoints) su un blocco di contenuto. Un messaggio di sistema a metà conversazione non crea da solo una voce nella cache. Senza la cache abilitata, non ci sono risparmi da preservare.
* **Memorizza nella cache il prefisso stabile come di consueto.** Posiziona `cache_control` sull'ultimo blocco che rimane invariato tra le richieste. Può trattarsi della fine del campo `system` di primo livello, della fine delle definizioni degli strumenti o di un punto stabile nella cronologia dei messaggi.
* **Aggiungi il messaggio di sistema dopo il breakpoint.** Poiché si trova dopo il prefisso memorizzato nella cache, non modifica l'hash del prefisso e si ottiene comunque un "cache hit" (riscontro nella cache).
* **Anche un messaggio di sistema a metà conversazione può essere memorizzato nella cache.** Una volta inserito nella conversazione, diventa parte della cronologia stabile. Al turno successivo puoi spostare il breakpoint della cache oltre di esso (o affidarti alla [cache automatica](https://platform.claude.com/docs/it/build-with-claude/prompt-caching#automatic-caching) per farlo). Il messaggio di sistema viene quindi letto dalla cache come qualsiasi altro turno.

Evita di modificare o rimuovere un messaggio di sistema a metà conversazione già inviato. Come qualsiasi altra modifica ai messaggi precedenti, ciò invalida la cache da quel punto in poi. Su Claude Fable 5.1, Claude Opus 5.5, Claude Sonnet 5.5 e Claude Haiku 5.5 invalida anche i [blocchi di ragionamento](https://platform.claude.com/docs/it/build-with-claude/thinking#preserved-in-conversation) in ogni turno successivo dell'assistente. Per indicazioni che devono applicarsi a un solo turno, usa un [messaggio di sistema limitato al turno](https://platform.claude.com/docs/it/build-with-claude/mid-conversation-system-messages#turn-scoped-system-messages) e lascialo al suo posto. Se l'istruzione deve evolvere, aggiungi un nuovo messaggio di sistema anziché riscrivere quello vecchio. I messaggi di sistema consecutivi sono accettati e trattati come un'unica sezione di sistema, che segue nel suo insieme la stessa regola di posizionamento.

## Limitazioni

* **Non per il primo messaggio.** Un messaggio `system` che contiene contenuto non può essere la prima voce in `messages`. Usa il campo `system` di primo livello per le istruzioni che si applicano fin dall'inizio.
* **Il posizionamento è vincolato.** Un messaggio `system` che contiene contenuto (blocchi `text`, `tool_addition` o `tool_removal`) deve seguire immediatamente un turno `user` (incluso un turno `user` che contiene blocchi `tool_result`) o un turno `assistant` che termina con il risultato di uno strumento server, e deve precedere un turno `assistant` o chiudere l'array. Non può trovarsi tra un blocco `tool_use` e il relativo `tool_result`. Posizionarlo altrove restituisce un errore 400. Un'eccezione: i blocchi `tool_addition` e `tool_removal` non sono accettati immediatamente dopo un turno `assistant` [in pausa](https://platform.claude.com/docs/it/build-with-claude/handling-stop-reasons#pause-turn) (uno che termina con il risultato di uno strumento server), mentre i blocchi `text` lo sono; riprendi prima il turno in pausa, poi invia la modifica agli strumenti nel messaggio `system` successivo. Un messaggio con `content` vuoto che imposta solo [`output_config.effort`](https://platform.claude.com/docs/it/build-with-claude/effort#change-effort-mid-conversation-beta) non renderizza nulla nella sua posizione ed è accettato ovunque in `messages`, anche come primo messaggio o tra un turno `assistant` e un turno `user`. I messaggi `system` consecutivi vengono valutati insieme, quindi aggiungere un messaggio con testo accanto a uno che imposta solo l'effort fa sì che l'intero gruppo segua la regola per i messaggi con contenuto.
* **I messaggi limitati al turno contengono solo testo e vanno reinviati alla lettera.** Un messaggio `clear_at: "next_user_message"` non contiene `tool_addition`, `tool_removal`, `output_config` né `cache_control`, e una volta cancellato deve rimanere in `messages` byte per byte nelle richieste successive. Vedi [Messaggi di sistema limitati al turno](https://platform.claude.com/docs/it/build-with-claude/mid-conversation-system-messages#turn-scoped-system-messages).
* **Non è il posto per contenuti non attendibili.** Claude tratta il contenuto di sistema come istruzioni dell'operatore e le segue. Non inserire direttamente in un messaggio di sistema testo proveniente dall'esterno della conversazione, come output grezzo degli strumenti, documenti recuperati o contenuti web; così facendo conferiresti a quel testo un'autorità a livello di operatore. Mantieni tali dati nei blocchi `tool_result` e continua a seguire [Mitigare jailbreak e prompt injection](https://platform.claude.com/docs/it/test-and-evaluate/strengthen-guardrails/mitigate-jailbreaks).

## Correlati

<CardGroup cols={2}>
  <Card title="Cache dei prompt" icon="bolt" href="https://platform.claude.com/docs/it/build-with-claude/prompt-caching">
    Come funziona la cache, dove posizionare i breakpoint e come leggere i campi di utilizzo della cache.
  </Card>

  <Card title="Diagnostica della cache" icon="magnifying-glass" href="https://platform.claude.com/docs/it/build-with-claude/cache-diagnostics">
    Scopri esattamente dove due richieste hanno divergito quando un riscontro in cache che ti aspettavi non si verifica.
  </Card>

  <Card title="Usare la Messages API" icon="message" href="https://platform.claude.com/docs/it/build-with-claude/working-with-messages">
    Struttura dei messaggi, conversazioni multi-turno e il campo `system`.
  </Card>

  <Card title="Best practice per il prompting" icon="text" href="https://platform.claude.com/docs/it/build-with-claude/prompt-engineering/claude-prompting-best-practices">
    Scrivere prompt e istruzioni di sistema efficaci.
  </Card>

  <Card title="Uso degli strumenti con Claude" icon="wrench" href="https://platform.claude.com/docs/it/agents-and-tools/tool-use/overview">
    Come sono strutturati i blocchi `tool_use` e `tool_result` nell'array `messages`.
  </Card>
</CardGroup>
