Ответы и потоковая передача

6.1 Запрос

POST /lmsp/v1/responses
Authorization: Bearer <token>
Content-Type: application/json
Idempotency-Key: 01J8M5T7Z2K4N6Q8S0V3X5B9DG
LMSP-Version: 1.0
{
  "model": "qwen3:14b-q4_k_m",
  "input": [
    {
      "type": "message",
      "role": "user",
      "content": [
        {
          "type": "input_text",
          "text": "Describe a local model service in one sentence."
        }
      ]
    }
  ],
  "stream": false,
  "max_output_tokens": 512,
  "temperature": 0.7,
  "response_format": {
    "type": "text"
  },
  "store": true
}

Основной протокол использует структуру input и output в стиле Responses, а не простой список строк сообщений, чтобы одна форма запроса могла нести:

  • многоходовые сообщения;
  • текст, изображения, аудио и файлы;
  • вызовы инструментов и их результаты;
  • структурированный вывод;
  • сводки рассуждений;
  • мультимодальный вывод.

LMSP 1.0 определяет только текстовое содержимое. Типы содержимого для изображений, аудио и файлов зарезервированы для будущих версий.

Поле Обязательное Значение
model Да Идентификатор используемой модели.
input Да Массив элементов ввода. Элемент message имеет role (system, user или assistant) и массив частей content, например input_text. Использование инструментов добавляет элементы function_call и function_call_output (раздел 6.5).
stream Нет true, чтобы получать события, отправляемые сервером. По умолчанию false.
max_output_tokens Нет Верхняя граница числа генерируемых токенов.
temperature Нет Температура сэмплирования.
response_format Нет {"type": "text"} (по умолчанию) или {"type": "json_schema", "json_schema": {"name": "...", "schema": {...}}} для структурированного вывода. Требует возможности structured_output.
tools, tool_choice Нет Функции-инструменты, которые может вызывать модель (раздел 6.5). Требует возможности tools.
store Нет Просит сервис сохранить ответ, чтобы его можно было получить позже и использовать как previous_response_id. По умолчанию false. Игнорируется сервисами без возможности conversations.
previous_response_id Нет Продолжает с сохранённого ответа. Требует возможности conversations.
extensions Нет Частные расширения (раздел 9.1).

Запрос, которому нужна возможность, отсутствующая у модели, отклоняется с 400 и кодом unsupported_capability. Запрос, который не помещается в контекстное окно, отклоняется с 400 и кодом context_length_exceeded.

Сервис, умеющий хранить диалоги, МОЖЕТ также поддерживать previous_response_id. В противном случае каждый запрос ДОЛЖЕН нести весь контекст. Сервис НЕ ДОЛЖЕН полагаться на то, что состояние диалога хранится в HTTP-соединении.

6.2 Синхронный ответ

Если stream равен false, сервис возвращает 200 OK и объект ответа после завершения генерации.

{
  "id": "resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF",
  "object": "response",
  "created_at": 1794200000,
  "status": "completed",
  "model": "qwen3:14b-q4_k_m",
  "output": [
    {
      "id": "msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE",
      "type": "message",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "A local model service is a resident interface layer that discovers, manages and calls models on the user's own device."
        }
      ]
    }
  ],
  "usage": {
    "input_tokens": 28,
    "output_tokens": 31,
    "total_tokens": 59
  },
  "error": null,
  "incomplete_details": null
}
Поле Значение
id Идентификатор ответа, например resp_....
object Всегда "response".
created_at Время создания в секундах с начала эпохи Unix.
status in_progress, completed, incomplete, failed или cancelled. Синхронный ответ возвращается в конечном статусе.
model Идентификатор модели, создавшей ответ.
output Массив элементов вывода.
usage Количество токенов: input_tokens, output_tokens и total_tokens.
error null или объект проблемы (раздел 9.3), когда status равен failed.
incomplete_details null или объект с полем reason, например max_output_tokens, когда status равен incomplete.

Типы элементов вывода:

Тип элемента Структура
message id, role (assistant) и content — массив частей output_text, у каждой из которых есть text.
function_call id, call_id, name и arguments — строка в формате JSON.
reasoning id и summary — массив частей summary_text, у каждой из которых есть text.

Если генерация не удалась, синхронный запрос получает статус ошибки и документ проблемы (раздел 9.3), а не объект ответа. Статус failed встречается в потоках, задачах и сохранённых ответах.

GET /lmsp/v1/responses/{response_id} возвращает ответ, сохранённый с store: true. Он необязателен и требует возможности conversations. Неизвестный идентификатор даёт 404 с кодом response_not_found.

6.3 Потоковая передача

Чтобы получить поток, задайте stream в запросе:

{
  "stream": true
}

Сервис отвечает 200 OK с Content-Type: text/event-stream и отправляет семантические события. У каждого события есть id, имя event и JSON-объект data:

id: 1
event: response.created
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","status":"in_progress"}

id: 2
event: response.output_item.added
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","output_index":0,"item":{"id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","type":"message","role":"assistant","content":[]}}

id: 3
event: response.output_text.delta
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","item_id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","delta":"A local model "}

id: 4
event: response.output_text.delta
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","item_id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","delta":"service is a resident interface layer."}

id: 5
event: response.output_item.done
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","output_index":0,"item":{"id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","type":"message","role":"assistant","content":[{"type":"output_text","text":"A local model service is a resident interface layer."}]}}

id: 6
event: response.completed
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","status":"completed","usage":{"input_tokens":28,"output_tokens":12,"total_tokens":40}}

Определены как минимум следующие события:

Событие Значение Поля данных
response.created Ответ создан. response_id, status (in_progress)
response.output_item.added Начался новый элемент вывода. response_id, output_index, item
response.output_text.delta К элементу-сообщению добавлен текст. response_id, item_id, delta
response.output_item.done Элемент вывода завершён. response_id, output_index, item
response.completed Ответ завершён. Последнее событие. response_id, status, usage
response.incomplete Генерация остановлена досрочно, например по лимиту токенов. Последнее событие. response_id, status, incomplete_details, usage
response.failed Генерация завершилась ошибкой. Последнее событие. response_id, status, error
response.cancelled Ответ отменён. Последнее событие. response_id, status
error Проблема, не связанная с одним ответом, после которой поток продолжаться не может. error — объект проблемы

Сервис закрывает поток после последнего события или события error.

Сервисы МОГУТ отправлять дополнительные события, например для аргументов вызовов инструментов, изображений, аудио и дельт структурированного JSON. Клиенты ДОЛЖНЫ игнорировать неизвестные им типы событий.

Если клиент закрывает соединение потокового запроса, сервису СЛЕДУЕТ прекратить генерацию.

6.4 Идентификаторы событий и переподключение

Идентификатор id события ДОЛЖЕН быть целым порядковым номером, строго возрастающим в пределах ответа и начинающимся с 1.

После обрыва соединения клиент возобновляет получение, отправив последний полученный идентификатор. Он делает это через заголовок:

Last-Event-ID: 2

или через параметр запроса:

GET /lmsp/v1/tasks/{task_id}/events?after=2

Оба варианта направляются на эндпоинт событий задачи (раздел 7.4). Сервис повторно отправляет только те события, чей порядковый номер больше 2. Если указаны оба, приоритет у after.

Если запрошенные события старше срока хранения, сервис отвечает 410 Gone с ошибкой event_history_expired. Тогда клиент получает итоговый результат запросом GET /lmsp/v1/tasks/{task_id}.

Ответ, переданный потоком напрямую из POST /lmsp/v1/responses, принадлежит этому HTTP-соединению и возобновлён быть не может. Клиенту, которому нужен возобновляемый вывод, СЛЕДУЕТ создать задачу и следить за её событиями.

6.5 Вызовы инструментов

LMSP 1.0 определяет функции-инструменты, которые выполняет клиент. Сам сервис инструменты не запускает. Область доступа tools:execute зарезервирована для расширений, которые это делают (раздел 10.3).

Сначала клиент перечисляет инструменты. У каждой записи есть type со значением function, name, description и parameters — объект JSON Schema. tool_choice принимает значения auto (по умолчанию), none, required или {"type": "function", "name": "get_weather"}.

{
  "model": "qwen3:14b-q4_k_m",
  "input": [
    {
      "type": "message",
      "role": "user",
      "content": [
        {
          "type": "input_text",
          "text": "What is the weather in Hangzhou?"
        }
      ]
    }
  ],
  "tools": [
    {
      "type": "function",
      "name": "get_weather",
      "description": "Get the current weather for a city.",
      "parameters": {
        "type": "object",
        "properties": {
          "city": { "type": "string" }
        },
        "required": ["city"]
      }
    }
  ],
  "tool_choice": "auto"
}

Когда модель решает вызвать инструмент, ответ содержит элемент function_call. Его arguments — строка в формате JSON. В потоке элемент приходит целиком в response.output_item.done.

{
  "id": "resp_01J8M7B3N6Q9T2V5X8Z1C4D7FH",
  "object": "response",
  "created_at": 1794200050,
  "status": "completed",
  "model": "qwen3:14b-q4_k_m",
  "output": [
    {
      "id": "fc_01J8M7B3N8R1S4W7Y0A3E6G9JK",
      "type": "function_call",
      "call_id": "call_01J8M7B3N9T2V5X8Z1C4D7F0HM",
      "name": "get_weather",
      "arguments": "{\"city\":\"Hangzhou\"}"
    }
  ],
  "usage": {
    "input_tokens": 74,
    "output_tokens": 18,
    "total_tokens": 92
  },
  "error": null,
  "incomplete_details": null
}

Клиент запускает инструмент и отправляет новый запрос с полным контекстом: прежние элементы ввода, элемент function_call в том виде, в каком он был получен, и элемент function_call_output с тем же call_id. Его output — строка, обычно в формате JSON.

{
  "type": "function_call_output",
  "call_id": "call_01J8M7B3N9T2V5X8Z1C4D7F0HM",
  "output": "{\"temperature_c\":17,\"condition\":\"light rain\"}"
}