Mejores prácticas de streaming
El streaming es poco fiable por naturaleza: las conexiones de larga duración se caen, los proxies almacenan la salida en búfer y los clientes se desconectan a mitad de respuesta.
Esta página recopila las prácticas que mantienen sólida una integración de streaming una vez que sale de una demostración y llega al tráfico de producción.
Cómo usar esta lista
- Trate los grupos con letras como capas: primero la fiabilidad del transporte, luego la corrección del estado acumulado, y finalmente la experiencia del usuario y el coste.
- Cada regla se relaciona con un modo de fallo concreto: si no puede visualizar el fallo, la regla probablemente aún no se aplica a su caso.
- Vuelva a consultar esta lista cada vez que añada un nuevo consumidor de un stream (una nueva interfaz de usuario, un nuevo punto de conexión de retransmisión), ya que cada uno reintroduce los mismos modos de fallo de forma independiente.
A - Fiabilidad de la conexión
- Envuelva cada stream en un
try/exceptque cubra toda la iteración, no solo la llamada que lo abre.anthropic.APIStatusErrory sus subclases (comoRateLimitError,APIConnectionError) pueden aparecer a mitad de la consumición del stream, no solo cuando se abre. - Establezca un tiempo de espera de solicitud explícito distinto de su política de reintentos. Un stream que se queda en silencio (sin nuevos eventos) durante más tiempo del razonable debe tratarse como fallido y reintentarse, no esperarse indefinidamente.
- Reintente con retroceso exponencial ante errores transitorios, no ante todos los errores. Reintente
APIConnectionErroryAPIStatusErrorde clase 5xx; no reintente errores 4xx como una solicitud mal formada, que fallará de la misma manera cada vez. - Nunca reintente una respuesta parcialmente transmitida reanudando a mitad de stream. El endpoint de streaming de la API de Mensajes no admite la reanudación de una conexión caída desde donde se quedó: un reintento significa reenviar la solicitud completa e iniciar un nuevo stream.
- Limite el número total de intentos de reintento y muestre un fallo claro al usuario después del límite. Un bucle de reintento ilimitado contra un backend que falla persistentemente solo consume tiempo y llamadas a la API.
B - Almacenamiento en búfer y estado
- Almacene en búfer los deltas de cada bloque de contenido de forma independiente, indexados por
index. Una respuesta puede contener varios bloques (texto, tool_use, thinking) intercalados por índice; un único búfer global corrompe el estado en el momento en que se transmiten más de un bloque. - Nunca analice fragmentos de
input_json_deltaindividualmente. Acumule la cadena completa de un bloque y analícela una vez, encontent_block_stop: consulte Manejo de JSON parcial durante llamadas a herramientas transmitidas. - Trate
text_deltacomo un fragmento opaco, nunca como un límite de token o palabra. La lógica de detección de oraciones, filtrado de profanidades o análisis de markdown debe ejecutarse sobre la cadena acumulada, no sobre deltas individuales. - Agrupe las actualizaciones de la interfaz de usuario en lugar de volver a renderizar en cada delta. Enviar el texto acumulado a la interfaz de usuario cada 25-50 ms (en lugar de por delta) reduce sustancialmente la sobrecarga de renderizado sin un coste de latencia perceptible.
- Llame a
get_final_message()solo después de que el stream se haya iterado completamente. Llamarla prematuramente puede devolver un objetoMessageincompleto.
C - Manejo de errores
- Distinga un
message_stoplimpio de un stream que simplemente se quedó en silencio. Si su bucle finaliza sin haber visto nuncamessage_stop, trátelo como una condición de fallo y regístrelo de forma distinta a una finalización exitosa. - Maneje explícitamente el tipo de evento
error, no solo las excepciones. Un eventoerrora mitad de stream (por ejemplo, por un modelo sobrecargado) es una parte normal del vocabulario de eventos, no siempre se eleva como una excepción de Python dependiendo de la versión del SDK; compruebe ambas vías. - Falle ruidosamente ante valores inesperados de
stop_reasonen rutas de código que asumen la finalización. Si su código espera"end_turn"pero recibe"max_tokens", la respuesta se truncó; no la trate silenciosamente como completa. - Registre el contenido parcial acumulado en caso de fallo, no solo el mensaje de error. Una respuesta parcial suele ser útil para la depuración (y a veces recuperable para el usuario) incluso cuando el stream finalmente falló.
- Valide el JSON de la llamada a la herramienta después de analizarlo, no solo que se haya analizado. Un JSON analizado correctamente que carece de un campo requerido del
input_schemade la herramienta sigue siendo una llamada mal formada que su código de ejecución debe rechazar limpiamente.
D - Estrategia de reconexión
- Reenvíe la solicitud completa al reconectar en lugar de intentar una reanudación parcial. Dado que la API no tiene capacidad de reanudación, su "reconexión" es en realidad "reintentar la solicitud completa"; diseñe su bucle de reintentos teniendo en cuenta esa suposición desde el principio.
- Decida de antemano si una reconexión reinicia el mensaje visible para el usuario o se le añade. Reiniciar silenciosamente una burbuja de chat a medio mostrar parece un error; límpiela y muestre un indicador de reintento en su lugar.
- Utilice lógica de aplicación segura contra idempotencia en torno a la ejecución de herramientas antes de un reintento. Si una llamada a herramienta se transmitió completamente y se ejecutó antes de que la conexión se cayera en un bloque posterior, un reintento ingenuo de la solicitud completa podría volver a ejecutar esa herramienta por segunda vez; proteja las herramientas que tienen efectos secundarios en consecuencia.
- Limite los intentos de reconexión con el mismo retroceso y límite que los reintentos de conexión (Grupo A). Un bucle de reconexión es un bucle de reintento; no mantenga políticas separadas e inconsistentes para ambos.
E - Coste y observabilidad
- Cierre el stream explícitamente cuando un cliente se desconecte. Una pestaña del navegador abandonada que no se detecta en el lado del servidor sigue consumiendo (y facturando) tokens de salida para una respuesta que nadie verá.
- Registre
usagedemessage_delta, no una estimación. Los recuentos de tokens solo son exactos una vez que la API los informa; contar caracteres o palabras en el lado del cliente no es un sustituto fiable para la facturación o la contabilidad de límites de velocidad. - Rastree la distribución de
stop_reasonen las métricas de producción. Una tasa creciente de paradas"max_tokens"generalmente significa que su límitemax_tokenses demasiado bajo para el tráfico real, no que las respuestas se están volviendo naturalmente más largas. - Alértese ante una tasa creciente de eventos
erroro reconexiones fallidas, no solo ante fallos directos de la solicitud. Los fallos de streaming pueden ocultarse dentro de un HTTP 200 "exitoso" que nunca llega amessage_stop.
Preguntas frecuentes
¿Cuál es la práctica de mayor prioridad en esta lista?
Envolver toda la iteración de streaming, no solo la llamada inicial, en el manejo de errores. La mayoría de los errores de streaming en producción provienen de un error que aparece a mitad de stream y que el código nunca esperó capturar allí.
¿Puedo reanudar un stream caído desde donde lo dejé?
No. El endpoint de streaming de la API de Mensajes no tiene capacidad de reanudación: una "reconexión" es en realidad reenviar la solicitud completa e iniciar un nuevo stream.
¿Cómo distingo un stream exitoso de uno que falló silenciosamente?
El bucle de un stream exitoso finaliza después de observar message_stop. Si su bucle finaliza (o la conexión se cierra) sin haber visto nunca message_stop, considérelo un fallo, regístrelo y considere un reintento.
¿Debo reintentar cada error de la misma manera?
No. Reintente errores transitorios como APIConnectionError o APIStatusError de clase 5xx con retroceso. No reintente errores 4xx (como una solicitud inválida), ya que fallarán de la misma manera cada vez.
¿Es seguro volver a renderizar todo el texto acumulado en cada delta individual?
Funciona, pero a escala es un desperdicio. Agrupar las actualizaciones de la interfaz de usuario en un intervalo corto (25-50 ms) en lugar de por delta reduce el coste de renderizado sin un impacto perceptible en la experiencia del usuario.
¿Qué sucede si un usuario cierra su pestaña del navegador a mitad de stream?
Nada se detiene automáticamente en el lado de Claude a menos que su backend detecte la desconexión del cliente y cierre su propio stream; de lo contrario, seguirá pagando por los tokens de salida que nadie verá.
¿Cómo debo manejar una llamada a herramienta que se ejecutó parcialmente antes de una caída de conexión?
Tenga cuidado con la idempotencia: si la herramienta ya se ejecutó y tuvo un efecto secundario antes de la caída, reintentar ciegamente la solicitud completa podría volver a activar ese efecto secundario. Proteja las herramientas con efectos secundarios utilizando claves de idempotencia o lógica de deduplicación.
¿Qué suele indicar una tasa creciente de razones de parada `max_tokens`?
Su límite max_tokens es demasiado bajo para las respuestas que su tráfico está generando actualmente: es una señal para aumentar el límite o investigar por qué las respuestas son más largas de lo esperado, no algo que deba ignorarse silenciosamente.
¿Necesito una lógica de reintento diferente para las solicitudes de streaming y las no de streaming?
La lógica de decisión de reintento (qué errores reintentar, estrategia de retroceso, límites) es la misma. La diferencia es solo que un fallo de streaming puede ocurrir después de que la solicitud ya pareciera tener éxito (a mitad de stream), por lo que la detección requiere observar toda la iteración, no solo la respuesta inicial.
¿Debo registrar el texto acumulado completo cuando falla un stream?
Sí, el contenido parcial hasta el punto del fallo es valioso para la depuración y, en algunas interfaces de usuario, se puede mostrar al usuario con un aviso de "respuesta interrumpida" en lugar de descartarlo por completo.
Relacionados
- Cómo los eventos enviados por servidor potencian las respuestas de streaming de Claude - el modelo de eventos sobre el que operan estas prácticas.
- Manejo de JSON parcial durante llamadas a herramientas transmitidas - el patrón de almacenamiento en búfer al que se hace referencia en el Grupo B.
- Combinación de streaming con el bucle de uso de herramientas - consideraciones de idempotencia para la ejecución de herramientas a las que se hace referencia en el Grupo D.
- Referencia de configuración de reintentos y tiempos de espera del SDK de Python - la configuración a nivel de SDK detrás del Grupo A.
- Tipos de excepciones del SDK de Python de un vistazo - qué excepciones son seguras para reintentar.
Versiones de la pila: Escrito contra la línea de modelos de Claude actual a partir de ~junio de 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (el predeterminado) y Claude Haiku 4.5 - y el SDK oficial de Python
anthropic(última versión 0.x). Los nombres de los modelos, las versiones del SDK y los precios cambian rápidamente; verifique los detalles actuales en platform.claude.com/docs antes de confiar en ellos.