# Streaming de respuestas: mostrar la IA mientras escribe

> El streaming de respuestas muestra el texto de un modelo de IA mientras se genera, en vez de esperar al final. Cómo funciona con SSE y cómo diseñarlo.

*Tags: ia, ux, interfaces, latencia*

---


> [!info] Definición Rápida
> El **streaming de respuestas** es la forma de entregar el resultado de un modelo de IA en fragmentos, a medida que se genera, para que la persona empiece a leer antes de que termine. Suele enviarse con SSE (server-sent events, eventos enviados por el servidor). El modelo no tarda menos: cambia el momento en que aparece el texto.


## ¿Qué es y cómo funciona?

Un modelo de lenguaje genera la respuesta token por token (si no tienes claro qué es un token, mira [[tokens|tokens]]). Sin streaming, el servidor espera a tener el texto completo y lo envía de una vez. Con streaming, envía cada fragmento en cuanto lo tiene.

SSE es un mecanismo web de una sola vía: el servidor responde con el tipo de contenido `text/event-stream` y el cliente recibe eventos mientras la conexión sigue abierta. No se pueden enviar eventos del cliente al servidor por ese mismo canal (MDN).

En la API de Claude se activa con `"stream": true` y el flujo sigue siempre el mismo orden:

| Evento | Qué trae | Qué puede hacer tu interfaz |
|---|---|---|
| `message_start` | Un mensaje con `content` vacío | Mostrar el indicador inicial |
| `content_block_start` | Abre un bloque de contenido (texto, uso de herramienta, razonamiento) | Crear el contenedor del bloque |
| `content_block_delta` | Un fragmento nuevo; en bloques de texto, un `text_delta` | Añadir el texto a lo ya mostrado |
| `content_block_stop` | Cierra el bloque | Dar el formato final al bloque |
| `message_delta` | Cambios del mensaje, como `stop_reason`; el uso de tokens es acumulado | Guardar el motivo de parada |
| `message_stop` | Fin del flujo | Quitar el botón de detener |
| `ping` | Mantiene viva la conexión; puede llegar varias veces | Ignorarlo |
| `error` | Por ejemplo `overloaded_error` | Marcar la respuesta como incompleta |

Los bloques de uso de herramientas y de razonamiento también llegan por deltas (`input_json_delta` y `thinking_delta`); decide si los muestras. Pueden aparecer tipos de evento nuevos, así que tu código debe ignorar los que no conoce.

No tienes que leer este protocolo a mano: los SDK oficiales de Python y TypeScript ofrecen ayudantes que entregan solo el texto (`text_stream` en Python, el evento `text` en TypeScript). Si no necesitas mostrar nada a medias, el SDK puede usar streaming por dentro y devolverte el mensaje completo, útil con valores grandes de `max_tokens` para evitar tiempos de espera HTTP.

## ¿Por qué le importa a un diseñador?

Porque cambia lo que la persona percibe como espera. Nielsen Norman Group recuerda los tres límites clásicos: 0,1 s es lo que se siente como instantáneo, 1 s es lo máximo para no cortar el hilo de pensamiento y 10 s es el límite para mantener la atención en la tarea. Con una respuesta de ocho segundos que aparece de golpe, la persona mira una pantalla quieta; con texto desde el primer segundo, ya está leyendo.

Ojo: el streaming no acelera la respuesta. Mejora el **tiempo hasta el primer contenido útil**: si el modelo tarda seis segundos en generarlo todo, esos seis segundos siguen ahí; cambia qué ve la persona durante ellos.

Hay tres decisiones de diseño que dependen de esto:

1. **Qué mostrar antes de que llegue texto.** Un indicador breve (un punto que pulsa, "Pensando") que desaparece cuando empieza el texto. Para elegir entre spinner, esqueleto o barra, mira [[estados-de-carga-en-ia|estados de carga en interfaces de IA]].
2. **Cómo mostrar el texto parcial.** Un texto que salta con cada token cansa. Agrupa fragmentos y mantén estable lo ya escrito.
3. **Qué pasa si se corta.** Si la conexión cae o hay un error, la persona no debe perder lo que ya leyó sin saberlo.

## ¿Cuándo usar streaming y cuándo no?

| Situación | ¿Streaming? | Por qué |
|---|---|---|
| Resumen largo, borrador de correo, explicación de varios párrafos | Sí | La persona lee mientras llega y el texto parcial ya tiene valor |
| Respuesta de una palabra o un número | No | Se entiende de golpe; el streaming solo añade parpadeo |
| Acción que se confirma al final (crear un registro) | No | El resultado parcial no sirve para decidir |
| Salida estructurada (un JSON que otro código va a leer) | No | Un JSON a medias no se puede interpretar hasta que cierra |
| Agente con varios pasos | Sí, pero de pasos | Mostrar qué hace pesa más que el texto |

Regla práctica: si la persona necesita el resultado completo para actuar, muestra un estado de carga y entrega el resultado entero. Si puede empezar a leer, usa streaming.

Para agentes con herramientas, el [[loop-de-agente|loop de un agente]] explica por qué la interfaz debe mostrar pasos. Y para medir la espera, mira [[latencia-en-llms|latencia y tokens por segundo]].

## ¿Cómo se implementa bien en la interfaz?

1. **Agrupa las actualizaciones.** Repintar en cada token es caro. Acumula fragmentos y actualiza una vez por cuadro de animación del navegador.
2. **No fuerces el scroll.** Si la persona subió para releer, no la devuelvas abajo con cada fragmento. Sigue el final solo si ya estaba ahí.
3. **Renderiza el formato con cuidado.** Un bloque de código o una tabla a medio escribir puede romper la maqueta. Muestra el bloque en curso como texto plano hasta que cierre.
4. **Cuida a los lectores de pantalla.** MDN recomienda `aria-live="polite"` para cambios importantes que no sean tan rápidos como para molestar, y pide crear la región antes de actualizar su contenido. Anuncia el inicio y el final de la respuesta, no cada token.
5. **Da una salida.** Un botón de detener la generación, visible desde el primer fragmento. El patrón completo está en [[interrumpir-y-redirigir|interrumpir y redirigir a un agente]].
6. **Revisa por qué terminó.** Un flujo puede cerrarse sin error y aun así estar truncado. El `stop_reason` del `message_delta` lo dice: `end_turn` es un final normal; `max_tokens`, por ejemplo, indica que el límite cortó la respuesta.

## ¿Qué hacer cuando el flujo se corta?

La API puede enviar errores dentro del flujo, por ejemplo `overloaded_error` en periodos de mucha demanda, que llegan como un evento `error` y no como un código HTTP. Trátalo como un caso normal.

La documentación de Claude describe una estrategia de recuperación en tres pasos: guardar lo recibido, crear una solicitud nueva que incluya ese texto parcial y seguir con el streaming desde ahí. En Claude 4.6 y posteriores, el texto parcial va en un mensaje de usuario con la instrucción de continuar. Límite: los bloques de herramientas y de razonamiento no se recuperan a medias; solo puedes reanudar desde el último bloque de texto.

En diseño: conserva el texto parcial, márcalo como incompleto y ofrece "Reintentar" o "Continuar".

## Ejemplo

Ejemplo ilustrativo: una herramienta interna resume reportes de ventas de 1.500 palabras. La primera versión muestra un spinner durante unos siete segundos y luego el resumen entero. Algunas personas creen que la app se colgó y recargan, lo que duplica las solicitudes.

El equipo cambia a streaming. Los primeros encabezados aparecen casi de inmediato y el texto crece debajo. Añaden un aviso fijo ("Generando resumen") y un botón de detener. La duración total no cambia, pero hay algo que leer desde el primer segundo. Si el flujo falla, se conserva el texto recibido con un aviso de "Respuesta incompleta" y un botón de reintento.

## Errores comunes

- Hacer streaming de respuestas cortas, donde el texto parcial no aporta nada.
- Actualizar el DOM en cada token sin agrupar, lo que vuelve la pantalla lenta y parpadeante.
- No manejar el error a mitad del flujo y dejar una respuesta cortada sin aviso.
- Dar por buena una respuesta solo porque el flujo terminó, sin mirar el `stop_reason`.
- Quitar la opción de detener la generación o anunciar cada fragmento a los lectores de pantalla.

## Fuentes

- [Streaming messages (documentación de Claude)](https://platform.claude.com/docs/en/build-with-claude/streaming): eventos del flujo, errores en el flujo, ayudantes de los SDK y recuperación de flujos interrumpidos.
- [Using server-sent events (MDN)](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events): qué es SSE y el tipo `text/event-stream`.
- [Response Times: The 3 Important Limits (Nielsen Norman Group)](https://www.nngroup.com/articles/response-times-3-important-limits/): los límites de 0,1 s, 1 s y 10 s.
- [ARIA live regions (MDN)](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Guides/Live_regions): `aria-live="polite"` y regiones creadas antes de actualizarse.


---

Source: https://www.fernandoux.com/es/wiki/ia/streaming-de-respuestas/
