# Streaming responses (/en/docs/developers/model/guides/streaming)



Streaming splits one answer into multiple events. After displaying text, read the terminal status and usage to confirm completion.

This page uses `deepseek-flash` with `POST /openai/v1/chat/completions` and `claude-opus-5` with `POST /anthropic/v1/messages`. Both examples were verified on 2026-10-12.

## 1. Prepare your terminal [#1-prepare-your-terminal]

Use a Praxis cloud API key in `PRAXIS_API_KEY`; see [API keys and authentication](/en/docs/developers/account/api-keys). Do not put the key in source code. Install Python and [uv](https://docs.astral.sh/uv/getting-started/installation/); TypeScript examples use [Bun](https://bun.sh/docs/installation).

```bash
test -n "$PRAXIS_API_KEY"
```

Expected: exit code 0. The examples default to `https://api.deepraxis.com`. To use another environment, set `PRAXIS_API_BASE` to its API origin, without a trailing slash or API path.

Save each Python block using its indicated filename. Run it with `uv run -q --no-project --with openai --with anthropic python <filename>`. Each block is independent.

## 2. Read text and final usage with Python [#2-read-text-and-final-usage-with-python]

Save as `streaming.py`. Run `uv run -q --no-project --with openai --with anthropic python streaming.py`.

```python
import os
from openai import OpenAI

client = OpenAI(api_key=os.environ['PRAXIS_API_KEY'],
    base_url=os.environ.get('PRAXIS_API_BASE', 'https://api.deepraxis.com') + '/openai/v1')
text, finish, usage = '', None, None
with client.chat.completions.with_streaming_response.create(
    model='deepseek-flash', messages=[{'role':'user','content':'Reply with exactly: Hello streaming.'}],
    max_tokens=256, stream=True, stream_options={'include_usage':True},
) as response:
    print('X-Request-Id:', response.headers.get('x-request-id'))
    for chunk in response.parse():
        if chunk.usage is not None:
            usage = chunk.usage
        for choice in chunk.choices:
            piece = choice.delta.content or ''
            text += piece
            print(piece, end='', flush=True)
            if choice.finish_reason is not None:
                finish = choice.finish_reason
print('\nfinish_reason:', finish)
assert text.strip() and finish == 'stop', 'Incomplete text response'
assert usage is not None, 'No final usage received'
print('usage:', usage.model_dump())
```

Expected: incremental `Hello streaming.`, then `finish_reason: stop` and `usage` containing input and output token counts. Exit code: 0.

Read Chat Completions in this order:

1. Collect `choices[].delta.content`. Role, thinking, or empty deltas may contain no answer text; do not display them as answer text.
2. Record `finish_reason`. This example ends with `stop`; `tool_calls` requires the [tool-calling flow](/en/docs/developers/model/guides/tool-calling).
3. With `stream_options.include_usage=true`, continue reading the final `usage` chunk. Its `choices` may be empty; do not access `choices[0]` unconditionally.
4. The HTTP stream ends with `data: [DONE]`. The SDK handles this marker and finishes iteration.

Do not break on `finish_reason`: usage may arrive afterward. A disconnected stream does not establish completion. Without terminal status or final usage, treat text as partial and usage as unknown.

## 3. Inspect the events with cURL [#3-inspect-the-events-with-curl]

Run in the same terminal:

```bash
curl --fail-with-body --no-buffer --silent --show-error --include \
  "${PRAXIS_API_BASE:-https://api.deepraxis.com}/openai/v1/chat/completions" \
  -H "Authorization: Bearer $PRAXIS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"deepseek-flash","messages":[{"role":"user","content":"Reply with exactly: Hello streaming."}],"max_tokens":256,"stream":true,"stream_options":{"include_usage":true}}'
```

Expected: HTTP 200 and `text/event-stream`. Text deltas precede `finish_reason: "stop"`, a usage chunk, and finally `data: [DONE]`. cURL exits 0. `--no-buffer` prevents display buffering. Exit code 0 alone does not prove answer completion; inspect the terminal status too.

## 4. Use Anthropic Messages [#4-use-anthropic-messages]

Messages sends `message_start`, content block `content_block_start` / `content_block_delta` / `content_block_stop`, then `message_delta` and `message_stop`. A `ping` may occur between events. Do not parse these as Chat Completions `choices`. Input usage appears in the starting message; the SDK aggregates later updates. `get_final_message()` returns the complete result.

Save as `streaming-anthropic.py`. Run `uv run -q --no-project --with openai --with anthropic python streaming-anthropic.py`.

```python
import os
from anthropic import Anthropic

client = Anthropic(api_key=os.environ['PRAXIS_API_KEY'],
    base_url=os.environ.get('PRAXIS_API_BASE', 'https://api.deepraxis.com') + '/anthropic')
with client.messages.stream(model='claude-opus-5', max_tokens=256,
    messages=[{'role':'user','content':'Reply with exactly: Hello streaming.'}]) as stream:
    print('X-Request-Id:', stream.response.headers.get('x-request-id'))
    for text in stream.text_stream:
        print(text, end='', flush=True)
    message = stream.get_final_message()
assert message.stop_reason == 'end_turn'
assert any(block.type == 'text' and block.text.strip() for block in message.content)
print('\nusage:', message.usage.model_dump())
```

Expected: the same text and final usage, with `stop_reason=end_turn`. Exit code: 0.

## Observed failure and fix [#observed-failure-and-fix]

Using `text-embedding-3-small` in this chat request returned HTTP 404:

> openai.chat.completions is not offered for text-embedding-3-small

The model does not offer this chat endpoint. Waiting for more events cannot resolve it. Using the verified `deepseek-flash` example returned text, terminal status, and final usage successfully.

Protocol details：[OpenAI](https://developers.openai.com/api/docs/guides/streaming-responses) · [Anthropic](https://platform.claude.com/docs/en/build-with-claude/streaming)。

[API reference →](/en/docs/api/compatible/openai) · [Cookbook →](/en/docs/cookbook)
