---
title: Responses
description: Вызов POST /v1/responses — чем он отличается от Chat Completions, члены запроса, типизированные элементы ответа и завершающее событие потока.
keywords: responses, input, output, instructions, response.completed, response.failed
group: gateway
---

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

Тот же ключ и тот же base URL, что у остальных операций шлюза. Разговор едет в `input`, а системный промпт — в `instructions`.

:::code-group
```bash title=curl
curl https://api.kumorouter.com/v1/responses \
  -H "Authorization: Bearer $KUMO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "<model>",
    "instructions": "Отвечай одним предложением.",
    "input": [
      {
        "type": "message",
        "role": "user",
        "content": [{ "type": "input_text", "text": "Объясни токены." }]
      }
    ]
  }'
```
```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.responses.create(
    model="<model>",
    instructions="Отвечай одним предложением.",
    input=[
        {
            "type": "message",
            "role": "user",
            "content": [{"type": "input_text", "text": "Объясни токены."}],
        }
    ],
)
print(answer.output[0].content[0].text)
```
```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.responses.create({
  model: "<model>",
  instructions: "Отвечай одним предложением.",
  input: [
    {
      type: "message",
      role: "user",
      content: [{ type: "input_text", text: "Объясни токены." }],
    },
  ],
});

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

## Чем он отличается {#differences keywords="отличия, input, output, status, instructions"}

Это отдельный протокол, а не другое написание Chat Completions. Пять различий видны сразу.

- Разговор — это `input`: один упорядоченный список типизированных элементов. Ход, вызов инструмента и результат вызова — три вида элемента, а не члены одного сообщения.
- Системный промпт — это `instructions`, член запроса. Он становится ведущим системным ходом разговора, впереди всех элементов `input`.
- Ответ — это `output`: список элементов, а не `choices`.
- Ответ заявляет `status` — стадию жизненного цикла, `completed` или `incomplete`, — а не причину остановки. Два словаря не переводятся друг в друга.
- Потолок вывода необязателен: запрос без `max_output_tokens` отвечается по опубликованному умолчанию этой поверхности в 32768 токенов. Явный ноль отвергается: это просьба не выводить ничего.

Часть членов протокола эта поверхность **принимает и не пересылает**, и каждый говорит об этом сам: `parallel_tool_calls`, `reasoning`, `prompt_cache_key`, `client_metadata` и `text.verbosity`. Они не отвергаются и не исполняются молча — они не делают ничего. `include` — наполовину из них: значения, под которые эта поверхность публикует ответ, пересылаются, остальные не делают ничего.

:::note
`store` принимается только со значением `false`, и его отсутствие значит `false`. Платформа не хранит ни промптов, ни ответов, ни чанков, поэтому хранить и потом отдавать здесь нечего, а `true` отвергается, а не принимается с молчаливым невыполнением. По той же причине `previous_response_id` проверяется на принадлежность вашей организации, но не служит серверным контекстом: продолжать не из чего, контекст присылает клиент.
:::

## Члены запроса {#request keywords="члены, input, instructions, max_output_tokens, text, tools"}

| Член | Что это |
| --- | --- |
| `model` | Обязателен. Модель, которой отвечать: каноническое имя или псевдоним из опубликованного каталога. |
| `input` | Обязателен. Разговор по порядку, типизированными элементами; от одного до 512. |
| `instructions` | Системный промпт. Становится ведущим системным ходом разговора. |
| `max_output_tokens` | Потолок вывода. Без него действует умолчание поверхности в 32768 токенов; явный ноль отвергается. |
| `stream` | Отвечать ли потоком собственными именованными событиями этого протокола. |
| `text` | Как оформлен текст ответа. Здесь же и требование структурированного вывода — в `text.format`. |
| `tools` | Инструменты этого хода. Объявляются плоско: `type`, `name`, `parameters`. |
| `tool_choice` | Что запрос требует от своего списка инструментов: строка `auto`, `none` или `required` либо объект, называющий один объявленный инструмент. |
| `store` | Принимается только `false`. |
| `previous_response_id` | Ответ вашей же организации, за которым идёт этот запрос. Проверяется на принадлежность и серверным контекстом не служит. |
| `parallel_tool_calls` | Принимается и не пересылается. |
| `reasoning` | Принимается и не пересылается. |
| `include` | Пересылается для значений, под которые эта поверхность публикует ответ, — сегодня это ровно `reasoning.encrypted_content`: именно эта просьба заставляет поставщика подписать зашифрованную запись на элементах `reasoning` в вашем ответе. Отправьте эти элементы обратно во `input` на следующем ходу — и модель продолжит с отчёта, который подписала сама; без записи не продолжит. Любое другое значение принимается и не делает ничего: `include` просит поставщика ДОБАВИТЬ элементы в ответ, а элемент, которого эта поверхность не публикует, она отвергает как нарушение контракта поставщика — то есть пересылка такого значения превратила бы работающий запрос в неработающий. Сам член не отвергается никогда: клиенты, которые его шлют, шлют его на каждом запросе. |
| `prompt_cache_key` | Принимается и не пересылается. |
| `client_metadata` | Принимается и не пересылается: платформа не описывает поставщику ваши сессии. |

### Виды элементов входа

| `type` | Что несёт |
| --- | --- |
| `message` | Ход разговора: `role` (`system`, `user`, `developer`, `assistant`) и `content` частями `input_text` или `output_text`. Ход `developer` несётся как системный: это одна роль под двумя именами. |
| `function_call` | Вызов, который модель сделала раньше: `call_id`, `name` и `arguments` текстом JSON, плюс `namespace`, в котором инструмент был объявлен, если запрос объявлял инструменты группами. |
| `function_call_output` | Результат работы инструмента: `call_id` и `output` текстом. |
| `custom_tool_call` | Вызов инструмента, объявленного как `custom`: `call_id`, `name`, необязательный `namespace` и `input` — ответ модели на языке самого инструмента, а не JSON. Пустой `input` — законный ответ и посылается пустой строкой. |
| `custom_tool_call_output` | Результат его работы: `call_id` и `output`. Результат отвечает вызову своего вида: `custom_tool_call_output` отвечает `custom_tool_call`, а `function_call_output` — `function_call`. |
| `reasoning` | Собственный отчёт модели о прошлом ходе, переигранный: `id`, обязательный `summary` частями `summary_text`, необязательный `content` частями `reasoning_text`, `encrypted_content` и `status`. Платформа ничего из этого не читает — всё уезжает поставщику, который это и произвёл. |
| `web_search_call` | Поиск, который поставщик уже выполнил, переигранный: `id`, `status` и необязательный `action`. Отвечать на него некому. |
| `additional_tools` | Объявления инструментов, сгруппированные в пространства имён, — туда их кладут новейшие клиенты этого протокола вместо `tools`. Допускается первым элементом входа и только один. |

### Второй ход

Платформа не хранит ответов, поэтому ваш клиент несёт свою историю сам — а история у него та, которую дал ему ответ. **Каждый элемент, которым эта поверхность отвечает, принимается обратно во `input`**, в тех же членах, в которых он был опубликован: переиграть ответ дословно — законный запрос. Единственное исключение — часть содержимого `refusal`: отказ завершает обмен, которому принадлежит, и обратно ходом эта поверхность его не принимает.

## Ответ {#response keywords="output, status, usage, message, function_call"}

| Член ответа | Что это |
| --- | --- |
| `id` | Личность запроса в Kumo — та же, которую называет `previous_response_id`. |
| `object` | Всегда `response`. |
| `created_at` | Момент ответа, целыми секундами эпохи Unix. |
| `model` | Имя, которое назвал запрос, возвращённое ровно тем же. |
| `status` | `completed` или `incomplete`. |
| `output` | Что произвела модель, по порядку: элементы `message`, `function_call`, `custom_tool_call`, `web_search_call` и `reasoning`. |
| `usage` | `input_tokens`, `output_tokens`, `total_tokens`. Отсутствует, если поставщик не сообщил расхода вовсе. |

Части элемента `message` бывают двух видов: `output_text` — текст ответа, `refusal` — собственный отказ модели отвечать.

Элемент `reasoning` — собственный отчёт модели о том, как она пришла к ответу; рассуждающая модель ставит его первым, перед сообщением, которое он объясняет. Он несёт `id`, обязательный `summary` частями `summary_text` — присутствующий и пустой, если модель ничего не резюмировала, — необязательный `content` частями `reasoning_text`, `encrypted_content`, если вы попросили его через `include`, и `status`. Платформа ничего из этого не читает и ничего не хранит. **Отправьте его обратно во `input` на следующем ходу**, в тех же членах, в которых он опубликован: именно этого протокол просит от клиента, который несёт свой контекст сам, и именно это позволяет рассуждающей модели продолжить с того места, где она остановилась.

```json title=Ответ
{
  "id": "resp-4d19a0b7c2",
  "object": "response",
  "created_at": 1756900000,
  "model": "<model>",
  "status": "completed",
  "output": [
    {
      "type": "message",
      "role": "assistant",
      "content": [{ "type": "output_text", "text": "Токены — куски текста, которыми модель меряет ввод и вывод." }]
    }
  ],
  "usage": { "input_tokens": 14, "output_tokens": 21, "total_tokens": 35 }
}
```

## Поток {#stream keywords="stream, response.created, response.completed, response.failed"}

`"stream": true` даёт `text/event-stream` в именованных событиях этого протокола: сначала `response.created`, затем элементы вывода и их дельты, затем **ровно одно** завершающее событие — `response.completed` с готовым телом и расходом либо `response.failed` с конвертом ошибки этого протокола.

> [Все события и правило завершающего кадра →](/ru/streaming)

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

:::cards
- [Стриминг](/ru/streaming) — события трёх диалектов и то, чем кончается целый ответ.
- [Инструменты](/ru/tools) — плоское объявление, `function_call` и `function_call_output`.
- [Структурированный вывод](/ru/structured-output) — `text.format` с именованной строгой схемой.
- [Ошибки](/ru/errors) — конверт отказа и коды ответа.
- [Справочник API](/ru/api-reference) — операция член за членом, прямо из описания API.
:::
