Ответы и потоковая передача
- Нормативная
- Черновик 1.0
- Обновлено
- Открыть как Markdown
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\"}"
}