Streaming de mensajes
Transmite respuestas de la API de Messages de forma incremental con eventos enviados por el servidor, incluyendo texto, uso de herramientas y deltas de pensamiento extendido.
Al crear un Message, puedes establecer "stream": true para transmitir la respuesta de forma incremental usando eventos enviados por el servidor (SSE).
Streaming con SDKs
El SDK de Python y el SDK de TypeScript ofrecen múltiples formas de hacer streaming. El SDK de PHP proporciona streaming a través de createStream(). El SDK de Python permite streams tanto síncronos como asíncronos. Consulta la documentación de cada SDK para obtener más detalles.
client = anthropic.Anthropic()
with client.messages.stream(
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
model="claude-opus-5-5",
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)Obtener el mensaje final sin manejar eventos
Si no necesitas procesar el texto a medida que llega, los SDKs proporcionan una forma de usar streaming internamente mientras devuelven el objeto Message completo, idéntico a lo que devuelve .create(). Esto es especialmente útil para solicitudes con valores grandes de max_tokens, donde los SDKs requieren streaming para evitar tiempos de espera HTTP.
client = anthropic.Anthropic()
with client.messages.stream(
max_tokens=128000,
messages=[{"role": "user", "content": "Write a detailed analysis..."}],
model="claude-opus-5-5",
) as stream:
message = stream.get_final_message()
for block in message.content:
if block.type == "text":
print(block.text)La llamada .stream() mantiene viva la conexión HTTP con eventos enviados por el servidor, luego .get_final_message() (Python) o .finalMessage() (TypeScript) acumula todos los eventos y devuelve el objeto Message completo. En Go, llamas a message.Accumulate(event) dentro del bucle del stream para construir el mismo Message completo. En Java, usa MessageAccumulator.create() y llama a accumulator.accumulate(event) en cada evento. En C#, espera el método de extensión .Aggregate() del stream para obtener el Message completo, o pasa un MessageContentAggregator a .CollectAsync() para agregar mientras manejas eventos. En Ruby, llama a .accumulated_message en el stream. En el SDK de PHP, iteras sobre los eventos del stream manualmente para acumular la respuesta.
Tipos de eventos
Cada evento enviado por el servidor incluye un tipo de evento con nombre y datos JSON asociados. Cada evento usa un nombre de evento SSE (por ejemplo, event: message_stop), e incluye el type de evento correspondiente en sus datos.
Cada stream usa el siguiente flujo de eventos:
message_start: contiene un objetoMessageconcontentvacío. Bajo el encabezado betathinking-binding-controls-2026-08-01, este objetoMessagetambién lleva el arrayinput_transformations. Después de un fallback del lado del servidor a mitad del stream, el evento finalmessage_deltalleva el array nuevamente con las entradas del modelo que está sirviendo.- Una serie de bloques de contenido, cada uno de los cuales tiene un
content_block_start, uno o más eventoscontent_block_delta, y un eventocontent_block_stop. Cada bloque de contenido tiene unindexque corresponde a su índice en el arraycontentdel Message final. Una excepción: durante las respuestas de fallback del lado del servidor, un bloque de contenidofallbackllega en cada límite de modelo como un parcontent_block_startycontent_block_stopsin deltas entre ellos. - Uno o más eventos
message_delta, que indican cambios de nivel superior en el objetoMessagefinal. - Un evento final
message_stop.
Eventos ping
Los streams de eventos también pueden incluir cualquier número de eventos ping.
Eventos de error
La API puede enviar ocasionalmente errores en el stream de eventos. Por ejemplo, durante períodos de alto uso, puedes recibir un overloaded_error, que normalmente correspondería a un HTTP 529 en un contexto sin streaming:
event: error
data: {"type": "error", "error": {"type": "overloaded_error", "message": "Overloaded"}}Otros eventos
De acuerdo con la política de versionado, se pueden agregar nuevos tipos de eventos, y tu código debe manejar los tipos de eventos desconocidos de forma elegante.
Tipos de delta de bloques de contenido
Cada evento content_block_delta contiene un delta de un tipo que actualiza el bloque content en un index dado.
Delta de texto
Un delta de bloque de contenido text se ve así:
event: content_block_delta
data: {"type": "content_block_delta","index": 0,"delta": {"type": "text_delta", "text": "ello frien"}}Delta de JSON de entrada
Los deltas para los bloques de contenido tool_use corresponden a actualizaciones del campo input del bloque. Para admitir la máxima granularidad, los deltas son cadenas JSON parciales, mientras que el tool_use.input final siempre es un objeto.
Puedes acumular los deltas de cadena y analizar el JSON una vez que recibas un evento content_block_stop, usando una biblioteca como Pydantic para hacer análisis parcial de JSON, o usando los SDKs, que proporcionan ayudantes para acceder a los valores incrementales analizados.
Un delta de bloque de contenido tool_use se ve así:
event: content_block_delta
data: {"type": "content_block_delta","index": 1,"delta": {"type": "input_json_delta","partial_json": "{\"location\": \"San Fra"}}}Nota: Los modelos actuales solo admiten emitir una propiedad completa de clave y valor de input a la vez. Por lo tanto, al usar herramientas, puede haber retrasos entre los eventos de streaming mientras el modelo está trabajando. Una vez que se acumulan una clave y un valor de input, se emiten como múltiples eventos content_block_delta con JSON parcial fragmentado para que el formato pueda admitir automáticamente una granularidad más fina en modelos futuros.
Delta de pensamiento
Al usar pensamiento con streaming habilitado, recibirás contenido de pensamiento a través de eventos thinking_delta. Estos deltas corresponden al campo thinking de los bloques de contenido thinking.
Para el contenido de pensamiento, se envía un evento especial signature_delta justo antes del evento content_block_stop. Esta firma se usa para verificar la integridad del bloque de pensamiento.
Cuando se establece display: "omitted" en la configuración de pensamiento, no se transmite ningún texto de pensamiento. El bloque de pensamiento se abre, recibe un thinking_delta con una cadena thinking vacía y luego un único signature_delta, y se cierra. Con display: "updates" (beta), los bloques de razonamiento se transmiten de la misma manera, y solo las actualizaciones de progreso que algunos modelos escriben entre llamadas a herramientas transmiten eventos thinking_delta que contienen texto. Consulta Controlar la visualización del pensamiento.
Un delta de pensamiento típico se ve así:
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "I need to find the GCD of 1071 and 462 using the Euclidean algorithm.\n\n1071 = 2 × 462 + 147"}}El delta de firma se ve así:
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "signature_delta", "signature": "EqQBCgIYAhIM1gbcDa9GJwZA2b3hGgxBdjrkzLoky3dl1pkiMOYds..."}}Respuesta completa del stream HTTP
Usa los SDKs de cliente al usar el modo de streaming. Sin embargo, si estás construyendo una integración directa con la API, necesitas manejar estos eventos tú mismo.
Una respuesta de stream consiste en:
- Un evento
message_start - Potencialmente múltiples bloques de contenido, cada uno de los cuales contiene:
- Un evento
content_block_start - Potencialmente múltiples eventos
content_block_delta - Un evento
content_block_stop
- Un evento
- Uno o más eventos
message_delta - Un evento
message_stop
También puede haber eventos ping dispersos a lo largo de la respuesta. Consulta Tipos de eventos para obtener más detalles sobre el formato.
Solicitud básica de streaming
client = anthropic.Anthropic()
with client.messages.stream(
model="claude-opus-5-5",
messages=[{"role": "user", "content": "Hello"}],
max_tokens=256,
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)event: message_start
data: {"type": "message_start", "message": {"id": "msg_1nZdL29xx5MUA1yADyHTEsnR8uuvGzszyY", "type": "message", "role": "assistant", "content": [], "model": "claude-opus-5-5", "stop_reason": null, "stop_sequence": null, "usage": {"input_tokens": 25, "output_tokens": 1}}}
event: content_block_start
data: {"type": "content_block_start", "index": 0, "content_block": {"type": "text", "text": ""}}
event: ping
data: {"type": "ping"}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "text_delta", "text": "Hello"}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "text_delta", "text": "!"}}
event: content_block_stop
data: {"type": "content_block_stop", "index": 0}
event: message_delta
data: {"type": "message_delta", "delta": {"stop_reason": "end_turn", "stop_sequence":null}, "usage": {"output_tokens": 15}}
event: message_stop
data: {"type": "message_stop"}
Solicitud de streaming con uso de herramientas
Esta solicitud le pide a Claude que use una herramienta para informar el clima.
client = anthropic.Anthropic()
tools = [
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
}
},
"required": ["location"],
},
}
]
with client.messages.stream(
model="claude-opus-5",
max_tokens=1024,
tools=tools,
tool_choice={"type": "any"},
messages=[
{"role": "user", "content": "What is the weather like in San Francisco?"}
],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)event: message_start
data: {"type":"message_start","message":{"id":"msg_014p7gG3wDgGV9EUtLvnow3U","type":"message","role":"assistant","model":"claude-opus-5","stop_sequence":null,"usage":{"input_tokens":472,"output_tokens":2},"content":[],"stop_reason":null}}
event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
event: ping
data: {"type": "ping"}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Okay"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":","}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" let"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"'s"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" check"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" the"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" weather"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" for"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" San"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Francisco"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":","}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" CA"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":":"}}
event: content_block_stop
data: {"type":"content_block_stop","index":0}
event: content_block_start
data: {"type":"content_block_start","index":1,"content_block":{"type":"tool_use","id":"toolu_01T1x1fJ34qAmk2tNTrN7Up6","name":"get_weather","input":{}}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"{\"location\":"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":" \"San"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":" Francisc"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"o,"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":" CA\"}"}}
event: content_block_stop
data: {"type":"content_block_stop","index":1}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":null},"usage":{"output_tokens":89}}
event: message_stop
data: {"type":"message_stop"}Solicitud de streaming con pensamiento
Esta solicitud habilita el pensamiento con streaming. La configuración display: "summarized" transmite un resumen condensado del razonamiento de Claude en lugar de la cadena de pensamiento completa.
client = anthropic.Anthropic()
with client.messages.stream(
model="claude-opus-5-5",
max_tokens=20000,
thinking={"type": "adaptive", "display": "summarized"},
messages=[
{
"role": "user",
"content": "What is the greatest common divisor of 1071 and 462?",
}
],
) as stream:
for event in stream:
if event.type == "content_block_delta":
delta = event.delta
match delta.type:
case "thinking_delta":
print(delta.thinking, end="", flush=True)
case "text_delta":
print(delta.text, end="", flush=True)event: message_start
data: {"type": "message_start", "message": {"id": "msg_01...", "type": "message", "role": "assistant", "content": [], "model": "claude-opus-5-5", "stop_reason": null, "stop_sequence": null}}
event: content_block_start
data: {"type": "content_block_start", "index": 0, "content_block": {"type": "thinking", "thinking": "", "signature": ""}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "I need to find the GCD of 1071 and 462 using the Euclidean algorithm.\n\n1071 = 2 × 462 + 147"}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "\n462 = 3 × 147 + 21"}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "\n147 = 7 × 21 + 0"}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "\nThe remainder is 0, so GCD(1071, 462) = 21."}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "signature_delta", "signature": "EqQBCgIYAhIM1gbcDa9GJwZA2b3hGgxBdjrkzLoky3dl1pkiMOYds..."}}
event: content_block_stop
data: {"type": "content_block_stop", "index": 0}
event: content_block_start
data: {"type": "content_block_start", "index": 1, "content_block": {"type": "text", "text": ""}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 1, "delta": {"type": "text_delta", "text": "The greatest common divisor of 1071 and 462 is **21**."}}
event: content_block_stop
data: {"type": "content_block_stop", "index": 1}
event: message_delta
data: {"type": "message_delta", "delta": {"stop_reason": "end_turn", "stop_sequence": null}}
event: message_stop
data: {"type": "message_stop"}Solicitud de streaming con uso de la herramienta de búsqueda web
Esta solicitud le pide a Claude que busque en la web información meteorológica actual.
client = anthropic.Anthropic()
with client.messages.stream(
model="claude-opus-5-5",
max_tokens=1024,
tools=[{"type": "web_search_20250305", "name": "web_search", "max_uses": 5}],
messages=[
{"role": "user", "content": "What is the weather like in New York City today?"}
],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)event: message_start
data: {"type":"message_start","message":{"id":"msg_01G...","type":"message","role":"assistant","model":"claude-opus-5-5","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":2679,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":3}}}
event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"I'll check"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" the current weather in New York City for you"}}
event: ping
data: {"type": "ping"}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"."}}
event: content_block_stop
data: {"type":"content_block_stop","index":0}
event: content_block_start
data: {"type":"content_block_start","index":1,"content_block":{"type":"server_tool_use","id":"srvtoolu_014hJH82Qum7Td6UV8gDXThB","name":"web_search","input":{}}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"{\"query"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"\":"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":" \"weather"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":" NY"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"C to"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"day\"}"}}
event: content_block_stop
data: {"type":"content_block_stop","index":1 }
event: content_block_start
data: {"type":"content_block_start","index":2,"content_block":{"type":"web_search_tool_result","tool_use_id":"srvtoolu_014hJH82Qum7Td6UV8gDXThB","content":[{"type":"web_search_result","title":"Weather in New York City in May 2025 (New York) - detailed Weather Forecast for a month","url":"https://world-weather.info/forecast/usa/new_york/may-2025/","encrypted_content":"Ev0DCioIAxgCIiQ3NmU4ZmI4OC1k...","page_age":null},...]}}
event: content_block_stop
data: {"type":"content_block_stop","index":2}
event: content_block_start
data: {"type":"content_block_start","index":3,"content_block":{"type":"text","text":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":3,"delta":{"type":"text_delta","text":"Here's the current weather information for New York"}}
event: content_block_delta
data: {"type":"content_block_delta","index":3,"delta":{"type":"text_delta","text":" City:\n\n# Weather"}}
event: content_block_delta
data: {"type":"content_block_delta","index":3,"delta":{"type":"text_delta","text":" in New York City"}}
event: content_block_delta
data: {"type":"content_block_delta","index":3,"delta":{"type":"text_delta","text":"\n\n"}}
...
event: content_block_stop
data: {"type":"content_block_stop","index":17}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":10682,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":510,"server_tool_use":{"web_search_requests":1}}}
event: message_stop
data: {"type":"message_stop"}Recuperación de errores
Claude 4.5 y anteriores
Para los modelos Claude 4.5 y anteriores, puedes recuperar una solicitud de streaming que se interrumpió debido a problemas de red, tiempos de espera u otros errores reanudando desde donde se interrumpió el stream. Este enfoque te evita tener que volver a procesar toda la respuesta.
La estrategia básica de recuperación implica:
- Capturar la respuesta parcial: Guarda todo el contenido que se recibió correctamente antes de que ocurriera el error.
- Construir una solicitud de continuación: Crea una nueva solicitud de API que incluya la respuesta parcial del asistente como el comienzo de un nuevo mensaje del asistente.
- Reanudar el streaming: Continúa recibiendo el resto de la respuesta desde donde se interrumpió.
Claude 4.6 y posteriores
Para los modelos Claude 4.6 y posteriores, se aplica la misma estrategia de captura y reanudación, pero el paso 2 cambia: en lugar de colocar la respuesta parcial en un mensaje del asistente, agrega un mensaje del usuario que instruya al modelo a continuar desde donde se quedó.
- Capturar la respuesta parcial: Guarda todo el contenido que se recibió correctamente antes de que ocurriera el error.
- Construir una solicitud de continuación: Crea una nueva solicitud de API con un mensaje del usuario que contenga la respuesta parcial y una instrucción para continuar, por ejemplo:
Sample prompt
Your previous response was interrupted and ended with [previous_response]. Continue from where you left off. - Reanudar el streaming: Continúa recibiendo el resto de la respuesta desde donde se interrumpió.
Mejores prácticas de recuperación de errores
- Usa las funciones del SDK: Aprovecha las capacidades integradas de acumulación de mensajes y manejo de errores del SDK.
- Maneja los tipos de contenido: Ten en cuenta que los mensajes pueden contener múltiples bloques de contenido (
text,tool_use,thinking). Los bloques de uso de herramientas y de pensamiento extendido no se pueden recuperar parcialmente. Puedes reanudar el streaming desde el bloque de texto más reciente.
Próximos pasos
Maneja cada valor de stop_reason una vez que se completa un stream.
Transmite el JSON de entrada de herramientas sin almacenamiento en búfer del lado del servidor para una menor latencia.
Transmite la salida de pensamiento con eventos thinking_delta y signature_delta.
Usa los SDKs oficiales, que manejan el streaming, la acumulación y la reconexión por ti.
Procesa grandes volúmenes de solicitudes de forma asíncrona cuando no necesitas respuestas en tiempo real.
Was this page helpful?