Skip to content

Text Generation (Chat Completions)

The /chat/completions endpoint is the central building block of the noris “LLM as a Service” platform. You submit a list of messages (a “conversation”), and the model responds with another message that can be seamlessly appended to the conversation.

Every message has a role (system, user, or assistant) and a content field. The order of messages reflects the chronological flow of the conversation. This structure lets you explicitly separate system instructions, user requests, and previous model responses.

Messages with the system role control the model’s behavior, tone, and formatting rules without being perceived directly as a question. Typically place the system message as the first element in the messages array. A clear, concise system instruction significantly improves response consistency.

Terminal window
curl -X POST https://ai.noris.de/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "vllm/release/gpt-oss-120b",
"messages": [
{"role": "system", "content": "You are a precise technical assistant. Answer concisely."},
{"role": "user", "content": "What is a vector index?"}
]
}'

Pass the full conversation history with every call. This way, the model “remembers” previous statements. Alternatively, you can manage history server-side and send only the relevant recent turns to reduce token cost.

The following example shows two complete turns (each a user and an assistant message) followed by a new user question:

Terminal window
curl -X POST https://ai.noris.de/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "vllm/release/gpt-oss-120b",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is the capital of France?"},
{"role": "assistant", "content": "The capital of France is Paris."},
{"role": "user", "content": "Roughly how many inhabitants does that city have?"},
{"role": "assistant", "content": "Paris has around 2.1 million inhabitants in the city proper."},
{"role": "user", "content": "And what's the name of the river that flows through it?"}
]
}'

With the openai SDK, the same multi-turn dialogue looks like this in Python:

from openai import OpenAI
client = OpenAI(base_url="https://ai.noris.de/v1", api_key="YOUR_API_KEY")
conversation = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is the capital of France?"},
{"role": "assistant", "content": "The capital of France is Paris."},
{"role": "user", "content": "Roughly how many inhabitants does that city have?"},
{"role": "assistant", "content": "Paris has around 2.1 million inhabitants in the city proper."},
{"role": "user", "content": "And what's the name of the river that flows through it?"}
]
response = client.chat.completions.create(
model="vllm/release/gpt-oss-120b",
messages=conversation
)
print(response.choices[0].message.content)

The endpoint’s response is a JSON object with several fields. The most important ones are:

FieldMeaning
idUnique identifier for the request.
objectObject type, usually "chat.completion" (or "chat.completion.chunk" when streaming).
choicesList of possible responses; with n=1 (default), it contains exactly one element.
choices[i].indexPosition of this alternative within choices.
choices[i].message.roleRole of the generated message, typically "assistant".
choices[i].message.contentThe actual generated text.
choices[i].finish_reasonReason for completion: "stop", "length", "tool_calls", etc.
usage.prompt_tokensNumber of tokens in the input prompt.
usage.completion_tokensNumber of generated tokens in the response.
usage.total_tokensSum of prompt and completion tokens (basis for AI-Punkte billing).

A minimal response example:

{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"choices": [
{
"index": 0,
"message": {"role": "assistant", "content": "The Seine flows through Paris."},
"finish_reason": "stop"
}
],
"usage": {"prompt_tokens": 48, "completion_tokens": 8, "total_tokens": 56}
}

Check finish_reason: if the value is "length", the response was cut off because the token limit was reached and should be continued. With "tool_calls", the model expects a tool to be executed, see Tool Calling.