---
title: Chat Completions
description: Вызов POST /v1/chat/completions — члены запроса, роли в разговоре, форма ответа и указатели на поток, инструменты и структурированный вывод.
keywords: chat completions, openai, сообщения, choices, finish_reason, usage
group: gateway
---

## Быстро {#quick keywords="curl, python, node, первый вызов"}

Направьте OpenAI-совместимый клиент на `https://api.kumorouter.com/v1`, дайте ему ключ и назовите модель. Потолок вывода обязателен: `max_tokens` или `max_completion_tokens`.

:::code-group
```bash title=curl
curl https://api.kumorouter.com/v1/chat/completions \
  -H "Authorization: Bearer $KUMO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "<model>",
    "max_tokens": 128,
    "messages": [{ "role": "user", "content": "Объясни токены одной строкой." }]
  }'
```
```python title=Python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.kumorouter.com/v1",
    api_key=os.environ["KUMO_API_KEY"],
)

answer = client.chat.completions.create(
    model="<model>",
    max_tokens=128,
    messages=[{"role": "user", "content": "Объясни токены одной строкой."}],
)
print(answer.choices[0].message.content)
```
```javascript title=Node
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.kumorouter.com/v1",
  apiKey: process.env.KUMO_API_KEY,
});

const answer = await client.chat.completions.create({
  model: "<model>",
  max_tokens: 128,
  messages: [{ role: "user", content: "Объясни токены одной строкой." }],
});

const reply = answer.choices[0].message.content;
process.stdout.write((reply ?? "") + "\n");
```
:::

## Члены запроса {#request keywords="члены, поля, тело запроса, max_tokens, stream"}

Тело — один JSON-объект. Члена, которого нет в таблице, эта поверхность не принимает: лишний член отвергается, а не игнорируется.

| Член | Что это |
| --- | --- |
| `model` | Обязателен. Модель, которой отвечать: каноническое имя или псевдоним, который несёт опубликованный каталог. Ответ возвращает это же имя обратно. |
| `messages` | Обязателен. Разговор по порядку, от одного до 512 ходов. |
| `max_tokens` | Потолок вывода в том написании, которое шлют давно живущие клиенты. |
| `max_completion_tokens` | Тот же потолок в нынешнем написании. Шлите один из двух или оба с одинаковым значением; запрос без обоих отвергается. |
| `stream` | Отвечать ли потоком. `true` даёт `text/event-stream`. |
| `stream_options` | Только вместе со `stream: true`. Единственный член — `include_usage`. |
| `tools` | Инструменты, которые этот ход может вызвать; до 128 объявлений. |
| `tool_choice` | Требование вызвать один названный из объявленных инструментов. Без него выбирает модель. |
| `response_format` | Требование структурированного вывода: именованная JSON-схема. |

## Ходы разговора {#messages keywords="роли, system, user, assistant, tool, content"}

У хода есть `role` и `content`. Роли четыре: `system`, `user`, `assistant`, `tool`.

`content` — это текст хода либо `null`. `null` законен на ходе ассистента, весь ответ которого был вызовом инструмента: именно в такой форме OpenAI-совместимый клиент переигрывает свою историю обратно. На ходе `tool` в `content` лежит результат работы инструмента.

Эта поверхность несёт текст. Ход не собирается из частей и не принимает картинок: `content` — строка или `null`, и другой формы у него нет.

Два члена принадлежат обмену с инструментом.

| Член хода | Что это |
| --- | --- |
| `tool_calls` | Вызовы, которые сделал этот ход ассистента, переигранные обратно в разговор, чтобы результату было на что отвечать. Вызовы делает только ассистент. |
| `tool_call_id` | Вызов, на который отвечает этот результат. Обязателен на ходе `tool` и отвергается на всех остальных: поставщик сопоставляет результаты вызовам по нему, а не по позиции. |

> [Как выглядит целый круг с инструментом →](/ru/tools)

## Ответ {#response keywords="choices, finish_reason, usage, id, ответ"}

Массив `choices` содержит ровно один элемент — попросить больше эта поверхность не даёт, — и `index` у этого элемента всегда ноль.

| Член ответа | Что это |
| --- | --- |
| `id` | Личность запроса в Kumo. Её и называйте в обращении в поддержку. |
| `object` | Всегда `chat.completion`. |
| `created` | Момент ответа, целыми секундами эпохи Unix. |
| `model` | Имя, которое назвал запрос, возвращённое ровно тем же: назвавший псевдоним читает обратно псевдоним. |
| `choices` | Ответ. `message` с ролью `assistant` и `finish_reason`. |
| `usage` | Что, по сообщению поставщика, потратил запрос. Отсутствует, если поставщик не сообщил расхода вовсе. |

`finish_reason` принимает четыре значения: `stop`, `length`, `tool_calls`, `content_filter`.

В `message` кроме `content` может прийти `refusal` — собственный отказ модели отвечать. Это ответ, а не ошибка: запрос обслужен и оплачен как любой другой.

`usage` считает `prompt_tokens`, `completion_tokens` и `total_tokens`; `prompt_tokens_details.cached_tokens` — часть входных токенов, а не добавка к ним.

```json title=Ответ
{
  "id": "chatcmpl-8f2b7e10c9",
  "object": "chat.completion",
  "created": 1756900000,
  "model": "<model>",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Токены — это небольшие куски текста, которые модель читает и пишет."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 12,
    "completion_tokens": 18,
    "total_tokens": 30
  }
}
```

## Что дальше {#next keywords="поток, инструменты, структурированный вывод, ошибки"}

:::cards
- [Стриминг](/ru/streaming) — `stream: true`, имена событий и завершающий кадр, по которому виден целый ответ.
- [Инструменты](/ru/tools) — `tools`, `tool_choice` и ход с результатом.
- [Структурированный вывод](/ru/structured-output) — `response_format` с именованной строгой схемой.
- [Ошибки](/ru/errors) — конверт отказа, коды ответа и один 401 на любую беду с ключом.
- [Лимиты](/ru/limits) — потолки, ниже которых обязан быть вызов.
- [Справочник API](/ru/api-reference) — та же операция член за членом, прямо из описания API.
:::
