Chat completions

Quickstart

Query chat models with single prompts, multi-turn conversations, and system prompts.

Send a single query

Use chat.completions.create to send a single query to a chat model:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.reka.ai/v1",
    api_key=os.environ["REKA_API_KEY"],
)

response = client.chat.completions.create(
    model="deepseek4-flash",
    messages=[{"role": "user", "content": "What are some fun things to do in New York?"}],
)

print(response.choices[0].message.content)

The create method takes a model id and a messages array. Each message is an object with content and a role naming the author.

In the example above, the role is user. The user role tells the model that the message comes from the end user of your system, for example, a customer using your chatbot app.

The other two roles are assistant and system, covered below.

Multi-turn conversations

Every query to a chat model is self-contained, so models don’t automatically remember prior queries. The assistant role solves this by carrying historical context for how a model has responded to prior queries, which makes it useful for chatbots and long-running conversations.

To provide a chat history for a new query, pass the previous messages to the messages array. Tag the user-provided messages with the user role and the model’s responses with the assistant role:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.reka.ai/v1",
    api_key=os.environ["REKA_API_KEY"],
)

response = client.chat.completions.create(
    model="deepseek4-flash",
    messages=[
        {"role": "user", "content": "What are some fun things to do in New York?"},
        {"role": "assistant", "content": "You could go to the Empire State Building!"},
        {"role": "user", "content": "That sounds fun! Where is it?"},
    ],
)

print(response.choices[0].message.content)

How your app stores historical messages is up to you.

Add a system prompt

You can query a model with only a user message, but you’ll typically want to give the model a system prompt with context for how to respond. For example, if you’re building a travel chatbot, you might tell the model to act like a helpful travel guide.

To add a system prompt, provide an initial message with the system role:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.reka.ai/v1",
    api_key=os.environ["REKA_API_KEY"],
)

response = client.chat.completions.create(
    model="deepseek4-flash",
    messages=[
        {"role": "system", "content": "You are a helpful travel guide."},
        {"role": "user", "content": "What are some fun things to do in New York?"},
    ],
)

print(response.choices[0].message.content)

Stream the response

Streaming returns the response token by token as it’s generated, instead of making you wait for the full reply. This is especially helpful with a reasoning model like GLM 5.3 Flash, which works through a problem before answering and can produce a lot of output.

A reasoning model’s response has two parts: the step-by-step thinking, in a reasoning_content field, and the final answer, in content. Set stream=True (Python) or stream: true (TypeScript/cURL) and read delta.reasoning_content and delta.content off each chunk. The thinking streams first, then the answer, and usage totals arrive on the final chunk:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.reka.ai/v1",
    api_key=os.environ["REKA_API_KEY"],
)

stream = client.chat.completions.create(
    model="glm5.3-flash",
    messages=[{"role": "user", "content": "What are the top 3 things to do in New York?"}],
    stream=True,
)

printed_answer_header = False

for chunk in stream:
    if not chunk.choices:
        continue
    delta = chunk.choices[0].delta

    # Reasoning models stream their thinking in reasoning_content.
    reasoning = getattr(delta, "reasoning_content", None)
    if reasoning:
        print(reasoning, end="", flush=True)

    # The final answer arrives in content.
    if delta.content:
        if not printed_answer_header:
            print("\n\n--- Answer ---\n", flush=True)
            printed_answer_header = True
        print(delta.content, end="", flush=True)

With a non-reasoning model, reasoning_content stays empty and only content is returned, so the same loop works unchanged. DeepSeek V4 Flash, DeepSeek V4 Pro and Qwen3.8 27B behave that way unless you set reasoning_effort; see Reasoning. The response reference has the full chunk shape.

Next steps