Streaming

Streaming lets you receive output in real time as the model generates it, improving the user experience and perceived speed.

How it works#

诺玛AI implements streaming using the Server-Sent Events (SSE) protocol:

  • The client sets `stream: true` when sending the request
  • The server returns generated content chunks incrementally
  • Each chunk is sent over SSE with a `data: ` prefix
  • When generation ends, `data: [DONE]` is sent

OpenAI-compatible streaming#

cURL

Code
curl https://as.apinoma.com/v1/chat/completions \
  -H "Authorization: Bearer $APINOMA_API_KEY" \
  -H "Content-Type: application/json" \
  -N \
  -d '{
    "model": "openai/gpt-4o",
    "messages": [{"role": "user", "content": "Write a poem aboutprogramming"}],
    "stream": true
  }'

Python

TypeScript

Anthropic-compatible streaming#

Python

Code
import anthropic
 
client = anthropic.Anthropic(
    base_url="https://as.apinoma.com/anthropic",
    api_key="<your APINOMA_API_KEY>"
)
 
with client.messages.stream(
    model="anthropic/claude-sonnet-4.6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Write a poem aboutprogramming"}]
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

TypeScript

Streaming + function calling#

Streaming also works with function calling. The model first streams the tool-call request, and after you handle it you continue the conversation:

Code
stream = client.chat.completions.create(
    model="openai/gpt-4o",
    messages=[{"role": "user", "content": "What is the weather like in Beijing today?"}],
    tools=[{
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Get weather for a specified city",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "City name"}
                },
                "required": ["city"]
            }
        }
    }],
    stream=True
)
 
for chunk in stream:
    delta = chunk.choices[0].delta
    if delta.tool_calls:
        # Handle the tool call
        print(f"Calling tool: {delta.tool_calls[0].function}")
    elif delta.content:
        print(delta.content, end="", flush=True)

Error handling and reconnection#

A streaming connection can drop due to network issues. We recommend implementing reconnection logic.

Code
import time
 
def stream_with_retry(client, max_retries=3, **kwargs):
    for attempt in range(max_retries):
        try:
            stream = client.chat.completions.create(stream=True, **kwargs)
            for chunk in stream:
                yield chunk
            return  # Completed successfully
        except Exception as e:
            if attempt < max_retries - 1:
                wait = 2 ** attempt  # Exponential backoff
                print(f"\nConnection interrupted; retrying in {wait}s...")
                time.sleep(wait)
            else:
                raise e

Best practices#

  • Always set a timeout — avoid waiting indefinitely
  • Handle incomplete chunks — some chunks may have no content
  • Implement reconnection — use an exponential backoff strategy
  • Use `flush` on the frontend — ensure content displays immediately

Last updated on June 23, 2026