Skip to main content

Salida de transmisión

En aplicaciones de chat en tiempo real o generación de textos largos, los tiempos de espera prolongados degradan la experiencia del usuario y pueden provocar tiempos de espera en el lado del servidor, causando fallos en las tareas. La salida de transmisión resuelve estos problemas al devolver continuamente fragmentos de texto a medida que el modelo los genera.

Funcionamiento

La salida de transmisión utiliza el protocolo Server-Sent Events (SSE). Después de que se inicia una solicitud de transmisión, el servidor establece una conexión persistente HTTP con el cliente. Cada vez que el modelo genera un bloque de texto (llamado fragmento), lo envía inmediatamente a través de esta conexión. Una vez generado todo el contenido, el servidor envía una señal de finalización. El cliente escucha el flujo de eventos y recibe y procesa fragmentos de texto en tiempo real, por ejemplo, renderizando caracteres uno por uno en la interfaz. Esto contrasta con las llamadas sin streaming, que devuelven todo el contenido de una sola vez.
Las respuestas con y sin transmisión difieren en su estructura: sin transmisión devuelve un único objeto JSON con el texto en choices[0].message.content; con transmisión devuelve fragmentos a través de SSE con el texto en choices[0].delta.content, que el cliente debe concatenar, terminando con data: [DONE].

Facturación

La salida de streaming utiliza la misma regla de facturación que las llamadas sin streaming, cobrando según el número de tokens de entrada y tokens de salida en la solicitud. Si se interrumpe una solicitud, los tokens de salida se cuentan solo para la parte generada antes de que el servidor reciba la solicitud de terminación.

Cómo usar

La edición de código abierto de Qwen3, las ediciones comercial y de código abierto de QwQ, QVQ y modelos Omni anteriores (Qwen3.5-Omni, Qwen3-Omni-Flash y Qwen-Omni-Turbo) solo admiten salida de streaming.

Paso 1: Configurar su clave de API y seleccionar una región

Debe haber obtenido una clave de API y configurarla como una variable de entorno.
Configurar su clave de API como una variable de entorno (DASHSCOPE_API_KEY) es más seguro que codificarla directamente en su código.

Paso 2: Realizar una solicitud de streaming

  • Compatible con OpenAI
  • DashScope
  • Cómo habilitar Establezca stream en true.
  • Ver uso de tokens El protocolo OpenAI no devuelve el uso de tokens de forma predeterminada. Establezca stream_options={"include_usage": true} para que el último fragmento de datos devuelto incluya información sobre el uso de tokens.
  • Python
  • Node.js
  • curl
import os
from openai import OpenAI

# 1. Prepare: Initialize the client
client = OpenAI(
    # Configure the API key using an environment variable to avoid hard coding.
    api_key=os.environ["DASHSCOPE_API_KEY"],
    # The API key is tightly bound to a region. Ensure base_url matches the region of your API key.
    # Singapore region URL. Replace {WorkspaceId} with your actual workspace ID. URLs vary by region.
    base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1",
)

# 2. Make a streaming request
completion = client.chat.completions.create(
    model="qwen-plus",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Please introduce yourself"}
    ],
    stream=True,
    stream_options={"include_usage": True}
)

# 3. Handle the streaming response
# Store response fragments in a list. Joining them at the end is more efficient than repeated string concatenation.
content_parts = []
print("AI: ", end="", flush=True)

for chunk in completion:
    if chunk.choices:
        content = chunk.choices[0].delta.content or ""
        print(content, end="", flush=True)
        content_parts.append(content)
    elif chunk.usage:
        print("\n--- Request usage ---")
        print(f"Input Tokens: {chunk.usage.prompt_tokens}")
        print(f"Output Tokens: {chunk.usage.completion_tokens}")
        print(f"Total Tokens: {chunk.usage.total_tokens}")

full_response = "".join(content_parts)
# print(f"\n--- Full response ---\n{full_response}")

Respuesta

AI: Hello! I am Qwen, a large-scale language model independently developed by Tongyi Lab under Alibaba Group. I can answer questions, create content such as stories, official documents, emails, scripts, perform logical reasoning, programming, express opinions, play games, and more. I support multiple languages, including but not limited to Chinese, English, German, French, and Spanish. If you have any questions or need help, feel free to ask me anytime!
--- Request usage ---
Input Tokens: 26
Output Tokens: 87
Total Tokens: 113

Salida de streaming para modelos multimodales

Los modelos multimodales permiten agregar imágenes, audio y otro contenido a las conversaciones. Su implementación de salida de streaming difiere de los modelos de solo texto en los siguientes aspectos:
  • Construcción de mensajes de usuario: Las entradas de modelos multimodales incluyen no solo texto, sino también imágenes, audio y otra información multimodal.
  • Interfaz del SDK de DashScope: Utilice la interfaz MultiModalConversation en el SDK de Python de DashScope. Utilice la clase MultiModalConversation en el SDK de Java de DashScope.
Para modelos multimodales, consulte Comprensión de imágenes y videos, Extracción de texto, Comprensión de audio—Qwen3-Omni-Captioner, Kimi, etc. Qwen3.5-Omni, Qwen3-Omni-Flash y Qwen-Omni-Turbo admiten solo salida de transmisión. Su salida puede incluir texto o audio y otro contenido multimodal. El análisis de sus resultados difiere del de otros modelos. Para más detalles, consulte Omni-modal.
  • Compatible con OpenAI
  • DashScope
Python
from openai import OpenAI
import os

client = OpenAI(
    # API keys differ by region. Get your API key: https://www.alibabacloud.com/help/model-studio/get-api-key
    # If you haven't configured an environment variable, replace the next line with your Model Studio API key: api_key="sk-xxx"
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # Singapore region URL. Replace {WorkspaceId} with your actual workspace ID. URLs vary by region.
    base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1",
)

completion = client.chat.completions.create(
    model="qwen3-vl-plus",  # Replace with other multimodal models as needed and adjust messages accordingly
    messages=[
        {"role": "user",
        "content": [{"type": "image_url",
                    "image_url": {"url": "https://dashscope.oss-cn-beijing.aliyuncs.com/images/dog_and_girl.jpeg"},},
                    {"type": "text", "text": "What scene is depicted in the image?"}]}],
    stream=True,
  # stream_options={"include_usage": True}
)
full_content = ""
print("Streaming output content:")
for chunk in completion:
    # If stream_options.include_usage is True, the last chunk's choices field is an empty list and should be skipped (token usage can be obtained via chunk.usage)
    if chunk.choices and chunk.choices[0].delta.content != "":
        full_content += chunk.choices[0].delta.content
        print(chunk.choices[0].delta.content)
print(f"Full content: {full_content}")

Salida de streaming para modelos de pensamiento

Los modelos de pensamiento primero devuelven reasoning_content (el proceso de pensamiento) y luego devuelven content (la respuesta). Determine si la etapa actual es de pensamiento o de respuesta basándose en el estado del paquete de datos.
Para obtener detalles sobre los modelos de pensamiento, consulte Pensamiento profundo y Comprensión de imágenes y videos.
Para la implementación de salida de streaming de Qwen3-Omni-Flash (modo de pensamiento), consulte Omni-modal.
  • Compatible con OpenAI
  • DashScope
A continuación se muestra el formato de respuesta al llamar al modo de pensamiento del modelo qwen-plus utilizando el SDK de Python de OpenAI en modo streaming:
# Thinking stage
...
ChoiceDelta(content=None, function_call=None, refusal=None, role=None, tool_calls=None, reasoning_content='Cover all key points while')
ChoiceDelta(content=None, function_call=None, refusal=None, role=None, tool_calls=None, reasoning_content='remaining natural and fluent.')
# Response stage
ChoiceDelta(content='Hello! I am **Qwen', function_call=None, refusal=None, role=None, tool_calls=None, reasoning_content=None)
ChoiceDelta(content='** (', function_call=None, refusal=None, role=None, tool_calls=None, reasoning_content=None)
...
  • Si reasoning_content no es None y content es None, la etapa actual es de pensamiento.
  • Si reasoning_content es None y content no es None, la etapa actual es de respuesta.
  • Si ambos son None, la etapa permanece igual que en el paquete anterior.
  • Python
  • Node.js
  • HTTP

Código de ejemplo

from openai import OpenAI
import os

# Initialize the OpenAI client
client = OpenAI(
    # If you haven't configured an environment variable, replace with your Alibaba Cloud Model Studio API key: api_key="sk-xxx"
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1",
)

messages = [{"role": "user", "content": "Who are you"}]

completion = client.chat.completions.create(
    model="qwen-plus",  # Replace with other deep-thinking models as needed
    messages=messages,
    # The enable_thinking parameter enables the thinking process. This parameter has no effect on models QwQ.
    extra_body={"enable_thinking": True},
    stream=True,
    # stream_options={
    #     "include_usage": True
    # },
)

reasoning_content = ""  # Full thought process
answer_content = ""  # Full response
is_answering = False  # Whether in the response stage
print("\n" + "=" * 20 + "Thought process" + "=" * 20 + "\n")

for chunk in completion:
    if not chunk.choices:
        print("\nUsage:")
        print(chunk.usage)
        continue

    delta = chunk.choices[0].delta

    # Collect only thinking content
    if hasattr(delta, "reasoning_content") and delta.reasoning_content is not None:
        if not is_answering:
            print(delta.reasoning_content, end="", flush=True)
        reasoning_content += delta.reasoning_content

    # Received content, start responding
    if hasattr(delta, "content") and delta.content:
        if not is_answering:
            print("\n" + "=" * 20 + "Full response" + "=" * 20 + "\n")
            is_answering = True
        print(delta.content, end="", flush=True)
        answer_content += delta.content

Respuesta

====================Thought process====================

Okay, the user asked "Who are you," so I need to give an accurate and friendly answer. First, I should confirm my identity as Qwen, developed by Tongyi Lab under Alibaba Group. Next, explain my main functions, like answering questions, creating text, logical reasoning, etc. Keep the tone approachable and avoid overly technical terms so the user feels comfortable. Also, avoid complex jargon and ensure the answer is concise. Additionally, include some interactive elements to encourage further questions. Finally, check for any missing key information, such as my Chinese name "Tongyi Qianwen" and English name "Qwen," along with my company and lab. Make sure the response is comprehensive and meets user expectations.
====================Full response====================

Hello! I am Qwen, a large-scale language model independently developed by Tongyi Lab under Alibaba Group. I can answer questions, create text, perform logical reasoning, programming, and more, aiming to provide high-quality information and services. You can call me Qwen or simply Tongyi Qianwen. How can I help you?

Puesta en marcha

  • Gestión de rendimiento y recursos: En los servicios backend, mantener una conexión persistente HTTP para cada solicitud de transmisión consume recursos. Configure su servicio con un tamaño de grupo de conexiones y valores de tiempo de espera adecuados. En escenarios de alta concurrencia, supervise el uso de descriptores de archivo para evitar su agotamiento.
  • Renderizado del lado del cliente: En frontends web, utilice las API ReadableStream y TextDecoderStream para manejar y renderizar sin problemas los flujos de eventos SSE, brindando la mejor experiencia de usuario.
  • Monitoreo de modelos:
    • Métricas clave: Monitoree el Tiempo hasta el primer token (TTFT), la métrica principal para la experiencia de streaming. También monitoree la tasa de errores de la API y el tiempo promedio de respuesta.
    • Alertas: Configure alertas para tasas anómalas de errores de API, especialmente errores 4xx y 5xx.
  • Configuración de proxy Nginx: Si utiliza Nginx como proxy inverso, su almacenamiento en búfer de salida predeterminado (proxy_buffering) rompe la naturaleza en tiempo real de las respuestas de transmisión. Para garantizar que los datos se envíen a los clientes de inmediato, desactive esta función estableciendo proxy_buffering off en su archivo de configuración de Nginx.

Códigos de error

Si la llamada al modelo falla y devuelve un mensaje de error, consulte Códigos de error para su resolución.

FAQ

P: ¿Por qué no hay información de uso en la respuesta?

R: El protocolo OpenAI no devuelve información de uso de forma predeterminada. Establezca el parámetro stream_options para incluir información de uso en el último paquete devuelto.

P: ¿Habilitar la salida de streaming afecta la calidad de respuesta del modelo?

R: No. Sin embargo, algunos modelos solo admiten salida de streaming, y las llamadas sin streaming podrían causar errores de tiempo de espera agotado. Recomendamos utilizar la salida de streaming.

P: ¿Cuál es la diferencia entre las llamadas sin streaming y con streaming?

R: Diferencias clave:
  • Límite de tiempo de espera: Para llamadas sin streaming, el tiempo de espera máximo es de al menos 300 segundos y varía según la región y el modelo. Si no se completa a tiempo, la solicitud se termina.
  • Estructura de salida: Las llamadas sin transmisión devuelven la respuesta completa (un único objeto JSON) de una sola vez. Las llamadas con transmisión devuelven fragmentos de datos progresivamente mediante el protocolo SSE, y cada fragmento contiene parte del contenido generado. El cliente debe ensamblar estos fragmentos.
  • Compatibilidad de funciones: Ambos admiten funciones como JSON Mode y Function Call sin diferencias funcionales.
Recomendamos utilizar la salida de streaming para evitar tiempos de espera agotados y mejorar la experiencia del usuario.

P: ¿La salida de streaming admite JSON Mode (salida estructurada)?

R: Sí. Establezca stream en true y response_format en {"type": "json_object"} en la solicitud. El modelo devolverá fragmentos de contenido con formato JSON progresivamente. La salida final ensamblada será un JSON válido.