Respuestas y streaming
- Normativa
- Borrador 1.0
- Actualizado
- Ver como Markdown
6.1 Solicitud
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
}
El protocolo principal usa una estructura input y output al estilo Responses en lugar de una simple lista de cadenas de mensajes, de modo que una única forma de solicitud pueda transportar:
- mensajes de varios turnos;
- texto, imágenes, audio y archivos;
- llamadas a herramientas y resultados de herramientas;
- salida estructurada;
- resúmenes de razonamiento;
- salida multimodal.
LMSP 1.0 define solo contenido de texto. Los tipos de contenido de imagen, audio y archivo se reservan para versiones posteriores.
| Campo | Obligatorio | Significado |
|---|---|---|
model |
Sí | Id del modelo que se usará. |
input |
Sí | Matriz de elementos de entrada. Un elemento message tiene un role (system, user o assistant) y una matriz content de partes, como input_text. El uso de herramientas añade los elementos function_call y function_call_output (sección 6.5). |
stream |
No | true para recibir eventos enviados por el servidor. Por defecto es false. |
max_output_tokens |
No | Límite superior del número de tokens generados. |
temperature |
No | Temperatura de muestreo. |
response_format |
No | {"type": "text"} (el valor por defecto), o {"type": "json_schema", "json_schema": {"name": "...", "schema": {...}}} para salida estructurada. Requiere la capacidad structured_output. |
tools, tool_choice |
No | Herramientas de función que el modelo puede invocar (sección 6.5). Requiere la capacidad tools. |
store |
No | Pide al servicio que conserve la respuesta, para poder recuperarla más tarde y usarla como previous_response_id. Por defecto es false. Los servicios sin la capacidad conversations lo ignoran. |
previous_response_id |
No | Continúa desde una respuesta almacenada. Requiere la capacidad conversations. |
extensions |
No | Extensiones privadas (sección 9.1). |
Una solicitud que necesita una capacidad de la que el modelo carece se rechaza con 400 y unsupported_capability. Una solicitud que no cabe en la ventana de contexto se rechaza con 400 y context_length_exceeded.
Un servicio que pueda almacenar conversaciones PUEDE admitir también previous_response_id. En caso contrario, cada solicitud DEBE llevar el contexto completo. Un servicio NO DEBE depender de la conexión HTTP para mantener el estado de la conversación.
6.2 Respuesta síncrona
Cuando stream es false, el servicio devuelve 200 OK con un objeto de respuesta una vez terminada la generación.
{
"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
}
| Campo | Significado |
|---|---|
id |
Identificador de la respuesta, como resp_.... |
object |
Siempre "response". |
created_at |
Hora de creación, en segundos desde la época Unix. |
status |
in_progress, completed, incomplete, failed o cancelled. Una respuesta síncrona se devuelve en un estado final. |
model |
Id del modelo que produjo la respuesta. |
output |
Matriz de elementos de salida. |
usage |
Recuentos de tokens: input_tokens, output_tokens y total_tokens. |
error |
null, o un objeto de problema (sección 9.3) cuando status es failed. |
incomplete_details |
null, o un objeto con un reason como max_output_tokens cuando status es incomplete. |
Tipos de elemento de salida:
| Tipo de elemento | Forma |
|---|---|
message |
id, role (assistant) y content, una matriz de partes output_text que tienen cada una un text. |
function_call |
id, call_id, name y arguments, una cadena codificada en JSON. |
reasoning |
id y summary, una matriz de partes summary_text que tienen cada una un text. |
Si la generación falla, una solicitud síncrona recibe como respuesta un estado de error y un documento de problema (sección 9.3), no un objeto de respuesta. El estado failed aparece en los flujos, las tareas y las respuestas almacenadas.
GET /lmsp/v1/responses/{response_id} devuelve una respuesta que se almacenó con store: true. Es opcional y requiere la capacidad conversations. Un id desconocido produce 404 con response_not_found.
6.3 Streaming
Para recibir la respuesta en streaming, establece stream en la solicitud:
{
"stream": true
}
El servicio responde 200 OK con Content-Type: text/event-stream y envía eventos semánticos. Cada evento tiene un id, un nombre event y un objeto 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}}
Se definen al menos estos eventos:
| Evento | Significado | Campos de datos |
|---|---|---|
response.created |
Se creó la respuesta. | response_id, status (in_progress) |
response.output_item.added |
Comenzó un nuevo elemento de salida. | response_id, output_index, item |
response.output_text.delta |
Se añadió texto a un elemento de mensaje. | response_id, item_id, delta |
response.output_item.done |
Un elemento de salida está completo. | response_id, output_index, item |
response.completed |
La respuesta terminó. Evento final. | response_id, status, usage |
response.incomplete |
La generación se detuvo antes de tiempo, por ejemplo al llegar al límite de tokens. Evento final. | response_id, status, incomplete_details, usage |
response.failed |
La generación falló. Evento final. | response_id, status, error |
response.cancelled |
Se canceló la respuesta. Evento final. | response_id, status |
error |
Un problema no vinculado a una sola respuesta, tras el cual el flujo no puede continuar. | error, un objeto de problema |
Un servicio cierra el flujo después de un evento final o de un evento error.
Los servicios PUEDEN enviar eventos adicionales, por ejemplo para argumentos de llamadas a herramientas, imágenes, audio y deltas JSON estructurados. Los clientes DEBEN ignorar los tipos de evento que no conozcan.
Si el cliente cierra la conexión de una solicitud en streaming, el servicio DEBERÍA dejar de generar.
6.4 Ids de evento y reconexión
El id de un evento DEBE ser un número de secuencia entero estrictamente creciente dentro de la respuesta, que empieza en 1.
Tras una conexión interrumpida, un cliente reanuda enviando el último id que recibió. Lo hace con una cabecera:
Last-Event-ID: 2
o con un parámetro de consulta:
GET /lmsp/v1/tasks/{task_id}/events?after=2
Ambos van al endpoint de eventos de una tarea (sección 7.4). El servicio reproduce solo los eventos cuyo número de secuencia es mayor que 2. Si están presentes los dos, prevalece after.
Si los eventos solicitados son anteriores al período de retención, el servicio responde 410 Gone con el error event_history_expired. El cliente obtiene entonces el resultado final con GET /lmsp/v1/tasks/{task_id}.
Una respuesta transmitida directamente desde POST /lmsp/v1/responses pertenece a esa conexión HTTP y no se puede reanudar. Un cliente que necesite una salida reanudable DEBERÍA crear una tarea y seguir sus eventos.
6.5 Llamadas a herramientas
LMSP 1.0 define herramientas de función que ejecuta el cliente. El servicio no ejecuta herramientas por sí mismo. El ámbito tools:execute se reserva para las extensiones que sí lo hacen (sección 10.3).
Primero, el cliente enumera las herramientas. Cada entrada tiene type con el valor function, un name, una description y parameters, un objeto JSON Schema. tool_choice es auto (el valor por defecto), none, required o {"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"
}
Cuando el modelo decide llamar a una herramienta, la respuesta contiene un elemento function_call. Sus arguments son una cadena codificada en JSON. En un flujo, el elemento llega completo en 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
}
El cliente ejecuta la herramienta y luego envía una nueva solicitud que lleva el contexto completo: los elementos de entrada anteriores, el elemento function_call tal como se recibió y un elemento function_call_output con el mismo call_id. Su output es una cadena, normalmente codificada en JSON.
{
"type": "function_call_output",
"call_id": "call_01J8M7B3N9T2V5X8Z1C4D7F0HM",
"output": "{\"temperature_c\":17,\"condition\":\"light rain\"}"
}