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.
System Prompts
Section titled “System Prompts”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.
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?"} ] }'Multi-Turn Conversations
Section titled “Multi-Turn Conversations”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:
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)Response Structure
Section titled “Response Structure”The endpoint’s response is a JSON object with several fields. The most important ones are:
| Field | Meaning |
|---|---|
id | Unique identifier for the request. |
object | Object type, usually "chat.completion" (or "chat.completion.chunk" when streaming). |
choices | List of possible responses; with n=1 (default), it contains exactly one element. |
choices[i].index | Position of this alternative within choices. |
choices[i].message.role | Role of the generated message, typically "assistant". |
choices[i].message.content | The actual generated text. |
choices[i].finish_reason | Reason for completion: "stop", "length", "tool_calls", etc. |
usage.prompt_tokens | Number of tokens in the input prompt. |
usage.completion_tokens | Number of generated tokens in the response. |
usage.total_tokens | Sum 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.
Further Reading
Section titled “Further Reading”- Streaming Responses: receive and display responses token by token.
- Tool Calling (Function Calling): integrate functions and external APIs into the conversation.
