Claude Platform Docs
MensajesGestión del contexto

Mensajes del sistema y cambios de herramientas a mitad de conversación

Cambia las instrucciones del sistema o la disponibilidad de herramientas a mitad de una conversación sin invalidar el prefijo en caché que las precede.

Las instrucciones del sistema normalmente viven en el campo system de nivel superior, antes de cada mensaje de la conversación. Esa posición es excelente para el "prompt caching" (almacenamiento en caché de prompts): la indicación del sistema forma parte del prefijo estable, por lo que los turnos posteriores aciertan en la caché. Es una mala posición para instrucciones que solo descubres que necesitas a mitad de una sesión, porque editar el campo system de nivel superior cambia el comienzo mismo del prompt e invalida la caché para todo lo que sigue.

Los mensajes del sistema a mitad de conversación cierran esa brecha. Agregas un mensaje {"role": "system"} en el punto de la conversación donde la nueva instrucción se vuelve relevante, en lugar de editar el campo system de nivel superior. El prefijo en caché permanece igual, por lo que la siguiente solicitud aún lo lee desde la caché, y la nueva instrucción se sigue aplicando como una instrucción del sistema en lugar de como texto de usuario ordinario.

Cambios de herramientas a mitad de la conversación

El array tools se ubica incluso antes que el campo system de nivel superior en el prefijo de la solicitud sobre el que se calcula el hash, por lo que editarlo invalida la caché de prompts para toda la conversación. Los cambios de herramientas a mitad de la conversación son el equivalente, para las herramientas, de los mensajes del sistema a mitad de la conversación. En lugar de fijar la lista de herramientas durante toda la conversación, cambias qué herramientas se ofrecen al modelo entre turnos: declara el conjunto completo de herramientas en tools desde el principio y luego usa bloques tool_addition y tool_removal para ofrecer una herramienta al modelo, o retirarla, a partir de un punto específico de la conversación. El array tools en sí nunca cambia, por lo que el prefijo almacenado en caché permanece intacto. Los cambios de herramientas a mitad de la conversación están en beta y usan el encabezado beta inline-tools-2026-09-15 en la API de Claude.

tool_addition y tool_removal son bloques de contenido en el array content de un mensaje role: "system", y pueden combinarse con bloques text en el mismo mensaje. El mensaje sigue las reglas de ubicación de cualquier mensaje del sistema a mitad de la conversación, con una restricción adicional después de un turno pausado (consulta Limitaciones), y el cambio se aplica desde ese punto de la conversación en adelante. El campo tool de cada bloque hace referencia a una herramienta en lugar de definirla: {"type": "tool_reference", "name": "..."} nombra una herramienta declarada en el array tools de la solicitud, y las herramientas del conector MCP pueden referenciarse individualmente con mcp_tool_reference (server_name y name) o como un conjunto de herramientas completo con mcp_toolset_reference (server_name). Hacer referencia a un nombre que no está declarado en tools devuelve un error 400 (en la API de Claude, con error.details.error_code establecido en tool_reference_unresolved). Como alternativa, un bloque tool_addition puede contener la definición completa de la herramienta, algo que el encabezado mid-conversation-tool-changes-2026-07-01 no admite.

Cada herramienta declarada en tools se ofrece al modelo desde el inicio de la conversación, a menos que se declare con defer_loading: true, lo que la mantiene retenida hasta que un bloque tool_addition la haga visible. tool_addition también vuelve a ofrecer una herramienta que un tool_removal anterior retiró.

La siguiente solicitud declara get_weather en tools y luego la retira después del primer turno del usuario con un bloque tool_removal. La solicitud envía el encabezado beta inline-tools-2026-09-15.

client = anthropic.Anthropic()

response = client.beta.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    betas=["inline-tools-2026-09-15"],
    # El conjunto completo de herramientas se declara desde el inicio y nunca cambia, así que el
    # prefijo en caché permanece intacto.
    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.",
        },
        # Retira get_weather a partir de este punto. El bloque hace referencia a
        # la herramienta por nombre en lugar de editar `tools`, así los turnos anteriores quedan
        # idénticos byte a byte y la caché sigue acertando.
        {
            "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)

Definir herramientas en un mensaje (beta)

Con el encabezado beta inline-tools-2026-09-15, un bloque tool_addition puede definir una herramienta por valor, con su definición completa, en lugar de nombrarla por referencia. Esto te permite introducir una herramienta que se desconoce al inicio de la conversación, o cuyo esquema cambia más adelante, agregando un mensaje role: "system". El arreglo tools y todos los mensajes anteriores permanecen exactamente como se enviaron, por lo que la caché de prompts sigue acertando y solo el mensaje agregado se procesa como entrada nueva. La única excepción, un arreglo tools sin ninguna herramienta no diferida, se trata en las reglas a continuación. El encabezado también cubre agregar y quitar herramientas por referencia, por lo que no necesitas enviar también mid-conversation-tool-changes-2026-07-01.

Envuelve la definición en un objeto tool de tipo tool_definition. La definition es una entrada de tools, como una herramienta personalizada o una herramienta de cliente o de servidor definida por Anthropic, con su configuración habitual, incluidos cache_control y defer_loading. Durante la beta, algunos tipos de herramientas (entre ellos la herramienta de uso de computadora) todavía no pueden definirse en un mensaje y devuelven un error 400 que lo indica; decláralas en tools y agrégalas por referencia. Por ejemplo, para definir una herramienta personalizada a mitad de la conversación:

{
  "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"]
          }
        }
      }
    }
  ]
}

Desde esa posición en adelante, el modelo puede llamar a la herramienta de la misma manera en que llama a una herramienta declarada en tools. Enviar de nuevo una definición idéntica no cambia nada, por lo que un cliente puede reenviarla con seguridad, por ejemplo, en un reintento.

La siguiente solicitud mantiene get_weather en tools y define db_query después del primer turno del usuario:

client = anthropic.Anthropic()

response = client.beta.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    betas=["inline-tools-2026-09-15"],
    # Mantén al menos una herramienta no diferida en `tools`, para que una herramienta definida
    # después no cambie el inicio del prompt renderizado.
    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?"},
        # Define db_query por valor a partir de aquí. `tools` y los
        # mensajes anteriores quedan tal como se enviaron, así que la caché sigue acertando.
        {
            "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)

El content de la respuesta incluye un bloque tool_use para la nueva herramienta, por ejemplo:

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

Para cambiar el esquema de una herramienta, o para pasar una herramienta de servidor a una versión más reciente, envía una definición diferente con el mismo nombre. La nueva definición reemplaza a la anterior desde esa posición en adelante. Una definición que reutiliza el nombre de un tipo de herramienta diferente devuelve un error 400 con error.details.error_code establecido en tool_name_conflict. Una versión más reciente de la misma herramienta no cuenta como un tipo diferente. tool_removal sigue recibiendo una referencia, y una herramienta eliminada puede definirse u ofrecerse de nuevo más adelante.

De la posición donde se renderiza la definición se derivan algunas reglas:

  • Declara desde el principio lo que ya conoces. Una herramienta que conoces en la primera solicitud pertenece a tools, con defer_loading: true y una referencia tool_addition posterior si el modelo todavía no debe verla. Define por valor solo lo que se desconoce en la primera solicitud o lo que cambia más adelante.
  • Mantén al menos una herramienta no diferida en tools. Se acepta una conversación cuyo arreglo tools no tiene ninguna herramienta no diferida, pero la primera herramienta que define por valor cambia el inicio del prompt renderizado, lo que cuesta un fallo de caché completo en esa solicitud. Una herramienta de búsqueda de herramientas cuenta como no diferida.
  • Los tipos de herramientas con fecha conservan sus propios encabezados beta. Si una herramienta de servidor que defines por valor requiere su propio encabezado beta, envía ese encabezado en cada solicitud posterior de la conversación.
  • cache_control va en el bloque o en la definición, no en ambos, y cuenta para el límite de puntos de interrupción de la solicitud. Una definición diferida no puede llevar cache_control.

Una solicitud devuelve un error 400 con error.details.error_code establecido en available_tools_limit_exceeded cuando se supera cualquiera de estos límites:

  • Hay más de 10,000 herramientas diferidas disponibles después de cualquier mensaje.
  • Hay más de 10,000 herramientas definidas después del primer mensaje del usuario disponibles después de cualquier mensaje.
  • Las definiciones de herramientas enviadas después del primer mensaje del usuario que siguen disponibles después de cualquier mensaje suman más de 4 MB (4,194,304 bytes).
  • El texto de herramientas renderizado supera los 4 MB (4,194,304 bytes).

Agregar un servidor MCP a mitad de la conversación (beta)

Para agregar un servidor del conector MCP a mitad de una conversación, envía el encabezado beta mcp-client-2026-09-15 junto con inline-tools-2026-09-15. La definition en un bloque tool_addition puede entonces ser un mcp_toolset, de modo que las herramientas del servidor quedan disponibles sin editar tools. Enumera los detalles de conexión del servidor en mcp_servers como de costumbre y luego agrega el conjunto de herramientas donde el servidor pasó a estar disponible:

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

El objeto mcp_toolset es el mismo que pondrías en tools, incluidos default_config y configs. Un bloque tool_addition nunca contiene una URL ni un token de servidor. Esos permanecen en mcp_servers.

La siguiente solicitud mantiene get_weather en tools, enumera el servidor de calendario en mcp_servers y agrega el conjunto de herramientas del servidor después del primer turno del usuario:

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?"},
        # Haz que las herramientas del servidor de calendario estén disponibles a partir de este punto.
        # El bloque nombra el servidor; nunca contiene una URL ni un token.
        {
            "role": "system",
            "content": [
                {
                    "type": "tool_addition",
                    "tool": {
                        "type": "tool_definition",
                        "definition": {
                            "type": "mcp_toolset",
                            "mcp_server_name": "calendar",
                        },
                    },
                },
            ],
        },
    ],
)

# La respuesta comienza con un bloque mcp_tool_listing para el servidor de calendario,
# así que verifica el tipo de cada bloque en lugar de leer 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)

Con mcp-client-2026-09-15, una respuesta para la cual la API obtuvo la lista de herramientas de un servidor comienza con un bloque mcp_tool_listing, uno por cada servidor consultado. Si tu código lee content[0], omite estos bloques. Devuelve el mensaje del asistente sin cambios, incluido este bloque, y sigue enviando mcp-client-2026-09-15 en cada solicitud que lo contenga. Las solicitudes posteriores usan entonces la lista registrada en lugar de volver a consultar al servidor. Para fijar tú mismo un conjunto de herramientas, copia esa lista en el campo tools del mcp_toolset, como se describe en Fijar la lista de herramientas de un servidor MCP.

mcp-client-2026-09-15 incluye todo lo que incluye mcp-client-2025-11-20, por lo que no necesitas enviar ambos. Estas funciones están disponibles en la API de Claude. Las solicitudes que usan el conector MCP mantienen sus condiciones de retención de datos.

Cuándo usar un mensaje del sistema a mitad de conversación

El almacenamiento en caché de prompts aplica hash al prefijo de la solicitud en orden: tools, luego system, luego messages. Un acierto de caché requiere que el prefijo coincida exactamente con una solicitud reciente, byte por byte, hasta el punto de interrupción de caché.

Ese orden significa que el campo system de nivel superior se ubica muy cerca del inicio del prefijo con hash. Cualquier cambio en él, incluso agregar una oración, produce un hash diferente, y la solicitud falla en la caché para la indicación del sistema y cada mensaje en caché posterior.

Los mensajes del sistema a mitad de conversación te permiten agregar la instrucción al final del historial de mensajes en su lugar. Todo lo anterior a la nueva instrucción permanece sin cambios, por lo que la entrada de caché existente aún coincide, y solo el nuevo mensaje se procesa como entrada nueva.

Algunas situaciones en las que esto importa:

  • Cambios de política o de persona a mitad de sesión. Una sesión agéntica larga necesita una nueva restricción ("de ahora en adelante, escribe todo el SQL como consultas parametrizadas") después de docenas de turnos en caché. Agregarla al campo system de nivel superior volvería a procesar todo el historial.
  • Contexto por turno que debe ser autoritativo. Quieres inyectar una nota de actualidad, una fecha límite de sesión o un cambio de disponibilidad de herramientas con peso de nivel de sistema, y cambia con demasiada frecuencia para vivir en el prefijo en caché.
  • Recordatorios por turno que no deberían acumularse. Un arnés da un empujón al modelo después de cada lote de resultados de herramientas ("solicita las lecturas independientes juntas", "el usuario no ha sabido de ti en un rato") y quiere que el modelo vea solo la copia más reciente. Un mensaje del sistema con alcance de turno se renderiza durante un turno y luego no cuesta nada, sin eliminar nada del historial.
  • Cambios de estado que tu aplicación observa. Tu aplicación nota algo que Claude debería tratar como un hecho de nivel de operador: archivos que cambiaron en disco, el usuario activó o desactivó una configuración de aprobación automática, las herramientas disponibles cambiaron o el presupuesto de tokens restante cayó por debajo de un umbral.
  • Entrada del usuario que no debería interrumpir un bucle agéntico. Un usuario escribe un seguimiento mientras Claude todavía está ejecutando herramientas para la solicitud anterior. Transmitirlo como un mensaje del sistema después del siguiente resultado de herramienta permite que Claude incorpore la nueva entrada al trabajo que ya está haciendo, en lugar de tratarla como una solicitud nueva a la que cambiar. En Claude Sonnet 5.5 y Claude Haiku 5.5, agrega en su lugar las palabras del usuario como un bloque text después del último tool_result en el mismo mensaje user. Consulta Ubicación después de los resultados de herramientas.
  • Cambios de modo que otorgan permisos permanentes. Un modo de nivel de sesión puede usar un mensaje del sistema a mitad de conversación para otorgar consentimiento permanente a una capacidad costosa, como lanzar automáticamente flujos de trabajo multiagente, con un breve recordatorio cada varios turnos y un aviso de salida cuando el modo se desactiva. Para un ejemplo desarrollado, consulta Construir un modo de orquestación.

En todos estos casos podrías poner la instrucción en un mensaje user normal, y Claude sí sigue las instrucciones que llegan en turnos de usuario. La diferencia es la prioridad: un mensaje user se trata como proveniente del usuario final, mientras que un mensaje system se trata como proveniente de ti, el operador de la aplicación. Cuando ambos entran en conflicto, las instrucciones del sistema tienen precedencia, así que usa el rol system para hechos y restricciones de nivel de operador que deben mantenerse incluso si el usuario final pide algo diferente. Un mensaje del sistema a mitad de conversación conserva esa prioridad de nivel de operador sin pagar el costo de fallo de caché de editar el campo system de nivel superior.

Cómo funciona

Agrega un mensaje con "role": "system" al arreglo messages. Usa una cadena simple o bloques de contenido para content, igual que en un turno user o assistant. La instrucción se aplica desde ese punto de la conversación en adelante. Cuando las instrucciones entran en conflicto, los mensajes del sistema posteriores tienen prioridad sobre los anteriores, y los mensajes del sistema a mitad de la conversación tienen prioridad sobre el campo system de nivel superior para los turnos que les siguen.

Aún puedes establecer el campo system de nivel superior para instrucciones que deben aplicarse a toda la conversación. Reserva los mensajes del sistema a mitad de la conversación para instrucciones que solo se vuelven relevantes más adelante, o que quieres agregar sin invalidar el prefijo almacenado en caché.

Un mensaje role: "system" también puede llevar output_config.effort para cambiar el nivel de esfuerzo a mitad de una conversación. Esto está en beta en Claude Fable 5.1, Claude Mythos 5.1, Claude Opus 5.5, Claude Opus 5, Claude Sonnet 5.5 y Claude Haiku 5.5 en la API de Claude y Google Cloud, y requiere el encabezado beta mid-conversation-output-config-2026-07-01. En Amazon Bedrock, está en beta en Claude Fable 5.1, Claude Mythos 5.1 y Claude Opus 5.5, con el mismo valor beta. Claude Opus 5 no lo admite en Amazon Bedrock. Consulta Esfuerzo por mensaje.

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    # Almacenamiento automático en caché de prompts: cada solicitud guarda en caché la conversación hasta ahora,
    # y la siguiente solicitud lee desde la caché el prefijo sin cambios.
    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 mitad de la sesión, el revisor se da cuenta de que todas las sugerencias deben
        # cumplir también la estricta política de tipado del equipo. Agregar la
        # instrucción aquí mantiene los turnos anteriores idénticos byte a byte, así que el
        # prefijo guardado en caché por la solicitud anterior se sigue leyendo desde la caché.
        {
            "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)

Este ejemplo habilita el almacenamiento en caché automático con el campo cache_control de nivel superior. El almacenamiento en caché de prompts es opcional: si una solicitud no tiene un campo cache_control (automático o un punto de interrupción explícito), no se almacena nada en caché y cada solicitud paga el precio normal de tokens de entrada por toda la conversación. Con el almacenamiento en caché habilitado, agregar el mensaje del sistema deja sin cambios los turnos ya almacenados en caché, por lo que la solicitud que lleva la nueva instrucción sigue leyéndolos desde la caché en lugar de procesarlos de nuevo. El almacenamiento en caché también requiere que la conversación alcance la longitud mínima de prompt almacenable en caché; un ejemplo tan corto como este queda por debajo de ella, por lo que cache_creation_input_tokens y cache_read_input_tokens permanecen en 0 hasta que la conversación crece.

Un mensaje del sistema a mitad de la conversación que lleva contenido (bloques text, tool_addition o tool_removal) debe seguir inmediatamente a un turno user (o a un turno assistant que termina en un resultado de herramienta de servidor), y debe ser la última entrada en messages o estar seguido inmediatamente por un turno assistant. Un mensaje user que lleva bloques tool_result cuenta: en un bucle agéntico puedes colocar el mensaje del sistema justo después de los resultados de herramientas, antes del siguiente turno de Claude. Cualquier otra posición para un mensaje que lleva contenido, incluida la que está entre un bloque tool_use de assistant y el tool_result que le responde, devuelve un error 400. Un mensaje con content vacío que solo establece output_config.effort se acepta en cualquier lugar de messages. Los mensajes system consecutivos se evalúan en conjunto, por lo que un mensaje que solo establece el esfuerzo junto a uno que lleva contenido sigue la regla de contenido.

Ubicación después de los resultados de herramientas

En un bucle agéntico, el mensaje del sistema va después del mensaje user que entrega los resultados de herramientas. En la mayoría de los modelos, aquí es también donde tu aplicación puede transmitir la entrada que el usuario escribió mientras Claude trabajaba, de modo que el nuevo contexto se absorba sin reiniciar el turno (para Claude Sonnet 5.5 y Claude Haiku 5.5, consulta el final de esta sección):

[
  { "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."
  }
]

Redacta el contenido del sistema como contexto en lugar de como una orden que anula al usuario. Enuncia el hecho ("llegó nueva entrada del usuario: X", "el presupuesto de tokens restante ahora es Y") y deja que Claude actúe en consecuencia. Claude está entrenado para resistir instrucciones que parecen ir en contra del usuario, y esa protección sigue aplicándose al rol del sistema, por lo que un lenguaje como "ignora lo que dijo el usuario" es menos efectivo que enunciar qué cambió.

Este patrón es para transmitir entrada del propio usuario final de la conversación. No lo uses para pasar salida de herramientas, documentos recuperados u otro contenido de terceros; mantén ese contenido en bloques tool_result (consulta Limitaciones).

En Claude Sonnet 5.5 y Claude Haiku 5.5, entrega en su lugar las palabras del usuario en el turno del usuario. Estos modelos están entrenados para resistir la inyección de prompts a través de resultados de herramientas, por lo que pueden tratar un mensaje del sistema colocado justo después de un resultado de herramienta como texto no confiable e ignorarlo. Agrega las palabras del usuario como un bloque text después del último tool_result en el mismo mensaje user. Mantén los avisos del arnés, como los recordatorios, en un mensaje del sistema a mitad de la conversación separado después de ese mensaje user, y nunca pongas un aviso y las palabras del usuario en el mismo bloque:

[
  { "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." }
    ]
  }
]

Para obtener más información sobre este comportamiento, consulta Cómo escribir prompts para Claude Sonnet 5.5 y Cómo escribir prompts para Claude Haiku 5.5.

Mensajes del sistema con alcance de turno

Para limitar un mensaje role: "system" al turno actual, establece su campo clear_at. Acepta uno de dos valores:

  • "never" (el valor predeterminado): el mensaje se renderiza en su posición en cada solicitud que lo incluye. Omitir el campo es idéntico.
  • "next_user_message": el mensaje tiene alcance de turno. Su texto se renderiza solo mientras no haya ningún mensaje role: "user" después de él en messages. Un mensaje de usuario que lleva solo bloques tool_result cuenta aquí como mensaje de usuario. Una vez que existe un mensaje de usuario posterior, el mensaje queda borrado: permanece en el arreglo, pero no renderiza nada y no cuesta tokens de entrada, en esa solicitud y en todas las posteriores.

Los mensajes del sistema con alcance de turno están en beta. Incluye el encabezado beta mid-conversation-system-clear-at-2026-08-21. Sin él, clear_at se rechaza como campo desconocido.

{
  "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."
}

El uso principal es un recordatorio por turno en un bucle de herramientas. Agrega el recordatorio después del mensaje tool_result cada vez que quieras que el modelo lo vea, y deja cada copia anterior donde está. El modelo ve solo las copias que vienen después del último mensaje del usuario, por lo que el recordatorio nunca se acumula. Nada anterior en messages cambia, por lo que la caché de prompts sigue coincidiendo. En Claude Fable 5.1, Claude Opus 5.5, Claude Sonnet 5.5 y Claude Haiku 5.5, esto también mantiene válidos los bloques de pensamiento posteriores: eliminar un recordatorio anterior cambiaría la conversación antes de esos bloques y haría fallar la verificación de la conversación, mientras que un mensaje borrado permanece en el arreglo y deja esa conversación sin cambios.

La siguiente solicitud es un paso posterior de un bucle de agente. messages[3] se renderizó en la solicitud anterior, cuando era el último mensaje del arreglo. Una vez que existe messages[5] (un mensaje de usuario posterior), messages[3] queda borrado: el mensaje borrado permanece en el arreglo, por lo que la conversación previa al bloque de pensamiento en messages[4] no cambia, pero el modelo ya no ve su texto. messages[6] y messages[7] se renderizan ambos, en orden.

{
  "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."
    }
  ]
}

Reglas para los mensajes con alcance de turno:

  • Reenvía los mensajes borrados textualmente. Un mensaje borrado sigue siendo parte del historial de la conversación. Reconstruirlo a partir del estado actual (un recuento de tokens nuevo, una marca de tiempo), descartarlo por redundante o cambiar su valor clear_at es una edición de un mensaje anterior. La caché de prompts falla a partir de ese punto, y en Claude Fable 5.1, Claude Opus 5.5, Claude Sonnet 5.5 y Claude Haiku 5.5, cada bloque de pensamiento producido después de él no supera la verificación de la conversación.
  • Solo texto. content es uno o más bloques text (o una cadena). Los bloques tool_addition y tool_removal devuelven un error 400 en un mensaje con alcance de turno, y lo mismo ocurre con output_config. Para esos casos, usa un mensaje role: "system" separado sin clear_at.
  • Sin cache_control en sus bloques. Un mensaje borrado nunca forma parte de una clave de caché, por lo que un punto de interrupción en él nunca podría coincidir. En su lugar, coloca el punto de interrupción en el último bloque del turno de usuario anterior, como hace el ejemplo. El campo de nivel superior de almacenamiento en caché automático omite los mensajes con alcance de turno al elegir un punto de interrupción. En la solicitud que borra un mensaje, el prefijo almacenado en caché reutilizable termina en el turno de usuario anterior a él, por lo que solo se vuelve a procesar el único turno del asistente que hay entre ese mensaje y el nuevo mensaje de usuario.
  • Las reglas de ubicación siguen aplicándose, esté borrado o no. Un mensaje con alcance de turno debe seguir a un turno user (o a un turno assistant que termina en un resultado de herramienta de servidor) y preceder a un turno assistant o cerrar el array, como cualquier mensaje del sistema a mitad de la conversación. Uno que cierra el array siempre se renderiza. Uno seguido directamente por otro mensaje user produce un error 400, no un mensaje borrado: coloca todos los resultados de una ronda de herramientas en un solo mensaje de usuario y los recordatorios después de él.
  • Los turnos del asistente no lo borran. Un turno del asistente prellenado o pausado después del mensaje, o un bucle de herramientas del lado del servidor, no agrega ningún mensaje de usuario, por lo que el mensaje sigue renderizándose en esa continuación. Para mantener un recordatorio visible durante un bucle de herramientas del lado del cliente, agrégalo de nuevo después de cada mensaje tool_result.
  • El recuento de tokens refleja lo que se renderiza. Un mensaje borrado no agrega nada a usage.input_tokens ni a un recuento de tokens.
  • Historial importado. En una transcripción que construyes en un solo paso (ejemplos few-shot, una conversación migrada), un mensaje con alcance de turno que ya tiene después un turno del asistente y un mensaje de usuario se borra desde la primera solicitud y nunca se renderiza. Ese es el estado correcto para un recordatorio por turno que estás trasladando. Deja clear_at sin establecer solo en los mensajes que el modelo deba ver en cada solicitud.

Los errores de validación son:

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')

El primero es el error que se devuelve sin el encabezado beta. En Google Cloud y Claude en Amazon Bedrock, envía el valor beta en el encabezado anthropic-beta, como en la API de Claude (consulta Encabezados beta). Con la API InvokeModel de Amazon Bedrock, colócalo en cambio en el arreglo anthropic_beta del cuerpo de la solicitud.

A través del SDK, establece clear_at en la entrada role: "system" de messages y envía el encabezado beta. El siguiente ejemplo agrega un recordatorio con alcance de turno después del turno del usuario; en la siguiente solicitud, una vez que existe un mensaje del usuario posterior, el recordatorio permanece en el arreglo pero ya no se renderiza:

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.",
        },
        # Recordatorio limitado al turno: se muestra en este turno y se borra cuando existe un mensaje de usuario posterior.
        {
            "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)

Combinación con el almacenamiento en caché de prompts

Los mensajes del sistema a mitad de conversación y el almacenamiento en caché de prompts están diseñados para usarse juntos:

  • Habilita el almacenamiento en caché explícitamente. El almacenamiento en caché solo ocurre cuando la solicitud incluye cache_control, ya sea el campo de almacenamiento en caché automático de nivel superior o un punto de interrupción explícito en un bloque de contenido. Un mensaje del sistema a mitad de conversación no crea una entrada de caché por sí mismo, y sin el almacenamiento en caché habilitado no hay ahorros que preservar.
  • Almacena en caché el prefijo estable como de costumbre. Coloca cache_control en el último bloque que permanece igual entre solicitudes, ya sea el final del campo system de nivel superior, el final de tus definiciones de herramientas o un punto estable en el historial de mensajes.
  • Agrega el mensaje del sistema después del punto de interrupción. Como viene después del prefijo en caché, no cambia el hash del prefijo y la caché sigue acertando.
  • Un mensaje del sistema a mitad de conversación es en sí mismo almacenable en caché. Una vez que está en la conversación, se convierte en parte del historial estable. En el siguiente turno puedes mover tu punto de interrupción de caché más allá de él (o confiar en el almacenamiento en caché automático para hacerlo) y el mensaje del sistema se lee desde la caché como cualquier otro turno.

Evita editar o eliminar un mensaje del sistema a mitad de la conversación que ya se haya enviado. Como cualquier otro cambio en mensajes anteriores, eso invalida la caché a partir de ese punto. En Claude Fable 5.1, Claude Opus 5.5, Claude Sonnet 5.5 y Claude Haiku 5.5, también invalida los bloques de pensamiento de cada turno posterior del asistente. Para indicaciones que deben aplicarse a un solo turno, usa un mensaje del sistema con alcance de turno y déjalo en su lugar. Si la instrucción necesita evolucionar, agrega un nuevo mensaje del sistema en lugar de reescribir el anterior. Los mensajes del sistema consecutivos se aceptan y se tratan como una sola sección del sistema, que sigue la misma regla de ubicación en su conjunto.

Limitaciones

  • No para el primer mensaje. Un mensaje system que lleva contenido no puede ser la primera entrada de messages. Usa el campo system de nivel superior para instrucciones que se aplican desde el principio.
  • La ubicación está restringida. Un mensaje system que lleva contenido (bloques text, tool_addition o tool_removal) debe seguir inmediatamente a un turno user (incluido un turno user que lleva bloques tool_result) o a un turno assistant que termine en un resultado de herramienta de servidor, y debe preceder a un turno assistant o terminar el arreglo. No puede ubicarse entre un bloque tool_use y su tool_result. Colocarlo en otro lugar devuelve un error 400. Una excepción: los bloques tool_addition y tool_removal no se aceptan inmediatamente después de un turno assistant pausado (uno que termina en un resultado de herramienta de servidor), aunque los bloques text sí; primero reanuda el turno pausado y luego envía el cambio de herramientas en el siguiente mensaje system. Un mensaje con content vacío que solo establece output_config.effort no renderiza nada en su posición y se acepta en cualquier lugar de messages, incluso como primera entrada o entre un turno assistant y un turno user. Los mensajes system consecutivos se evalúan en conjunto, así que agregar un mensaje con texto junto a uno que solo establece el esfuerzo hace que todo el grupo siga la regla de contenido.
  • Los mensajes con alcance de turno son solo de texto y se reenvían textualmente. Un mensaje clear_at: "next_user_message" no lleva tool_addition, tool_removal, output_config ni cache_control, y una vez borrado debe permanecer en messages byte por byte en las solicitudes posteriores. Consulta Mensajes del sistema con alcance de turno.
  • No es un lugar para contenido no confiable. Claude trata el contenido del sistema como instrucciones del operador y las sigue. No coloques directamente en un mensaje del sistema texto proveniente de fuera de la conversación, como resultados sin procesar de herramientas, documentos recuperados o contenido web; hacerlo le otorga a ese texto autoridad de nivel de operador. Mantén esos datos en bloques tool_result y sigue aplicando Mitigar jailbreaks e inyecciones de prompts.

Cómo funciona el almacenamiento en caché, dónde colocar los puntos de interrupción y cómo leer los campos de uso de caché.

Descubre exactamente dónde divergieron dos solicitudes cuando un acierto de caché que esperabas no ocurre.

Estructura de mensajes, conversaciones de múltiples turnos y el campo system.

Cómo escribir prompts e instrucciones del sistema efectivos.

Cómo se estructuran los bloques tool_use y tool_result en el arreglo messages.

Was this page helpful?