Chat Completions
POST https://router.1-lab.online/v1/chat/completions — основной эндпоинт: модель получает список сообщений и возвращает ответ. Формат совпадает с OpenAI, поэтому подойдут официальные SDK openai для Python и TypeScript и любые программы, которые умеют работать с OpenAI API.
Примеры ниже на Python; клиент создаётся так:
import os
from openai import OpenAI
client = OpenAI(base_url="https://router.1-lab.online/v1", api_key=os.environ["ROUTER_API_KEY"])
Основные параметры
| Параметр | Что задаёт |
|---|---|
model |
ID модели, например openai/gpt-6.1-sol (обязательный) |
messages |
список сообщений диалога (обязательный) |
max_tokens |
предел длины ответа в токенах |
temperature |
случайность ответа: 0 — предсказуемо, 1 и выше — разнообразнее |
top_p |
альтернатива temperature; обычно меняют что-то одно |
stop |
строка или список строк, на которых модель остановится |
stream |
true — ответ приходит по частям (см. ниже) |
tools, tool_choice |
вызов инструментов (см. ниже) |
response_format |
ответ в формате JSON (см. ниже) |
Роли сообщений:
system— инструкция для модели: роль, стиль, ограничения;user— сообщения пользователя;assistant— прошлые ответы модели (для продолжения диалога);tool— результат вызова инструмента.
Модель не помнит прошлые запросы: чтобы продолжить диалог, передавайте историю целиком.
resp = client.chat.completions.create(
model="anthropic/claude-sonnet-5.5",
messages=[
{"role": "system", "content": "Ты помощник юриста. Отвечай кратко."},
{"role": "user", "content": "Чем договор оказания услуг отличается от подряда?"},
],
temperature=0.3,
max_tokens=800,
)
print(resp.choices[0].message.content)
print(resp.usage) # prompt_tokens, completion_tokens, total_tokens
Поле finish_reason в ответе объясняет, почему модель остановилась: stop — закончила мысль, length — упёрлась в max_tokens, tool_calls — хочет вызвать инструмент.
Потоковый ответ (stream)
С "stream": true ответ приходит по частям, пока модель его пишет, — в формате Server-Sent Events. Пользователь видит текст сразу, не дожидаясь конца.
Python
stream = client.chat.completions.create(
model="openai/gpt-6.1-sol",
messages=[{"role": "user", "content": "Напиши короткое поздравление коллеге."}],
stream=True,
stream_options={"include_usage": True},
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
if chunk.usage: # приходит в последнем фрагменте
print("\nТокены:", chunk.usage.prompt_tokens, "+", chunk.usage.completion_tokens)
TypeScript
const stream = await client.chat.completions.create({
model: "openai/gpt-6.1-sol",
messages: [{ role: "user", content: "Напиши короткое поздравление коллеге." }],
stream: true,
stream_options: { include_usage: true },
});
for await (const chunk of stream) {
const text = chunk.choices[0]?.delta?.content;
if (text) process.stdout.write(text);
}
Если читаете поток без SDK: каждое событие — строка data: {...} с фрагментом в choices[0].delta, поток заканчивается строкой data: [DONE]. Строки, которые начинаются с двоеточия, — служебные, их нужно пропускать.
curl -N https://router.1-lab.online/v1/chat/completions \
-H "Authorization: Bearer $ROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "openai/gpt-6-luna", "stream": true,
"messages": [{"role": "user", "content": "Посчитай от 1 до 5"}]}'
Ошибка может прийти и посреди потока, когда HTTP-статус уже 200. Обрабатывайте ошибки на протяжении всего чтения, а не только при отправке запроса.
Вызов инструментов (function calling)
Модель может вернуть не текст, а просьбу вызвать вашу функцию с аргументами. Вы выполняете функцию у себя и отправляете результат обратно — модель формулирует ответ.
import json
tools = [{
"type": "function",
"function": {
"name": "get_order_status",
"description": "Статус заказа по номеру",
"parameters": {
"type": "object",
"properties": {"order_id": {"type": "string", "description": "Номер заказа"}},
"required": ["order_id"],
},
},
}]
messages = [{"role": "user", "content": "Где мой заказ 48213?"}]
resp = client.chat.completions.create(model="openai/gpt-6.1-sol", messages=messages, tools=tools)
msg = resp.choices[0].message
if msg.tool_calls:
messages.append(msg) # ответ модели с вызовом — обратно в историю
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = {"order_id": args["order_id"], "status": "передан в доставку"} # здесь ваш код
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(result, ensure_ascii=False),
})
final = client.chat.completions.create(model="openai/gpt-6.1-sol", messages=messages, tools=tools)
print(final.choices[0].message.content)
else:
print(msg.content)
tool_choice: "auto"(по умолчанию) — модель сама решает, вызывать ли инструмент;"none"— запретить;{"type": "function", "function": {"name": "..."}}— обязать вызвать конкретный.- Модель может запросить несколько вызовов сразу — обработайте все
tool_callsи верните результат на каждыйtool_call_id. - Описания инструментов оплачиваются как входные токены в каждом запросе.
Ответ в формате JSON
Параметр response_format просит модель вернуть JSON.
По схеме — ответ строго соответствует вашей JSON Schema:
resp = client.chat.completions.create(
model="openai/gpt-6.1-sol",
messages=[{"role": "user", "content": "Извлеки данные: Иван Петров, 34 года, Казань"}],
response_format={
"type": "json_schema",
"json_schema": {
"name": "person",
"strict": True,
"schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"},
"city": {"type": "string"},
},
"required": ["name", "age", "city"],
"additionalProperties": False,
},
},
},
)
data = json.loads(resp.choices[0].message.content)
Любой JSON — response_format={"type": "json_object"}. В этом режиме обязательно попросите в промпте ответить в JSON и опишите нужные поля.
Надёжнее всего ответ по схеме работает у моделей OpenAI, Anthropic и Google. С открытыми моделями (DeepSeek, Qwen, GLM, Kimi и др.) дополнительно описывайте формат в промпте и проверяйте ответ в коде.
Изображения на входе
Большинство моделей принимают картинки вместе с текстом — например, openai/gpt-6.1-sol, anthropic/claude-sonnet-5.5, google/gemini-4-argon. Только текст понимают deepseek/deepseek-v4-pro и z-ai/glm-5.3. Сообщение в этом случае — список частей:
resp = client.chat.completions.create(
model="openai/gpt-6.1-sol",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "Что на этом фото? Ответь одним предложением."},
{"type": "image_url", "image_url": {"url": "https://example.com/photo.jpg"}},
],
}],
)
Локальный файл передаётся в формате base64:
import base64
with open("scan.png", "rb") as f:
b64 = base64.b64encode(f.read()).decode()
image_part = {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{b64}"}}
Изображения пересчитываются во входные токены: чем больше разрешение, тем дороже запрос. Если модель не принимает изображения, запрос вернёт ошибку.