Chat completions
POST /v1/chat/completions
Request body
| Parameter | Type | Description |
|---|---|---|
model |
string | Model to use. gemma for chat, qwen for long documents. See Models. Required |
messages |
array | Array of message objects with role and content. Required |
stream |
boolean | Stream partial responses as server-sent events. Default false. |
temperature |
number | Sampling temperature, 0-2. Lower = more deterministic. Default 1. |
max_tokens |
integer | Maximum tokens to generate. Model decides if not set. |
top_p |
number | Nucleus sampling threshold, 0-1. Default 1. |
top_k |
integer | Only sample from the k most likely next tokens. Default -1 (off). |
min_p |
number | Drop tokens whose probability is below this fraction of the most likely token, 0-1. Default 0 (off). |
frequency_penalty |
number | Penalize a token more each time it has already appeared, -2 to 2. Positive = less repetition. Default 0. |
presence_penalty |
number | Penalize any token that has already appeared, however often, -2 to 2. Positive = more new topics. Default 0. |
repetition_penalty |
number | Multiplicative penalty on tokens from the prompt and output so far. Above 1 discourages repetition; 1.05-1.1 is usually enough. Default 1 (off). |
seed |
integer | Fixes the random sampling, for reproducible output with the same request. |
tools |
array | Tool definitions the model may call. See Tool calling. |
tool_choice |
string or object | auto (default when tools is set), none, or a specific tool to force. |
user |
string | Your own end-user identifier, for usage attribution. Max 128 characters. See Usage attribution. |
session_id |
string | Groups requests into one conversation or run. Max 128 characters. See Usage attribution. |
top_k, min_p and repetition_penalty are not part of the OpenAI API, so the OpenAI SDKs have no argument for them. Pass them in extra_body (Python) or as extra fields in the request body (JavaScript, curl):
response = client.chat.completions.create(
model="gemma",
messages=[...],
frequency_penalty=0.3,
extra_body={"top_k": 30, "repetition_penalty": 1.05},
)
Keep repetition penalties low for reports and summaries: names and technical terms have to recur, and high values make the model reach for synonyms.
Message roles
Each message in the array has a role that determines how it’s treated.
| Role | Description |
|---|---|
system |
Sets context for the conversation. Placed first in messages array. |
user |
Messages from the user. The model generates a response to this. |
assistant |
Previous model responses. Use for multi-turn conversations. |
Example request
import os
from openai import OpenAI
client = OpenAI(
base_url="https://router.appelon.ai/v1",
api_key=os.environ["APPELON_API_KEY"]
)
response = client.chat.completions.create(
model="gemma",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is the capital of the Netherlands?"}
]
)
print(response.choices[0].message.content)
# → "The capital of the Netherlands is Amsterdam."
Response
Returns a completion object with the generated message.
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"model": "RedHatAI/gemma-4-31B-it-FP8-block",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "The capital of the Netherlands is Amsterdam."
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 28,
"completion_tokens": 12,
"total_tokens": 40
}
}
Streaming
Set stream: true to receive tokens as they’re generated.
stream = client.chat.completions.create(
model="gemma",
messages=[{"role": "user", "content": "Tell me a story"}],
stream=True
)
for chunk in stream:
print(chunk.choices[0].delta.content, end="")
Tool calling
Both chat models support tool calling, in the standard OpenAI shape: pass tools, and the model may answer with tool_calls instead of content. This is what agent frameworks and the n8n AI Agent node rely on.
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}]
response = client.chat.completions.create(
model="gemma",
messages=[{"role": "user", "content": "Wat voor weer is het in Groningen?"}],
tools=tools,
)
call = response.choices[0].message.tool_calls[0]
print(call.function.name) # get_weather
print(call.function.arguments) # {"city": "Groningen"}
Run the tool yourself, then send the result back as a tool message carrying the same tool_call_id, and call the model again with the extended history. That loop is the whole mechanism behind every coding agent.
Notes
- Both models work, but they use different parsers underneath. If a prompt produces reliable tool calls on one and not the other, try the other before rewriting the prompt.
- Parallel tool calls may come back as several entries in one
tool_callsarray. Answer each one with its owntoolmessage. - Streaming delivers tool calls in fragments:
argumentsarrives as a string built up across chunks, so accumulate before parsing it as JSON.
Tools built on this
- Hermes Agent, a coding agent
- n8n, workflow automation
- Migrating from OpenAI, for anything else that takes a custom base URL