Respostas e streaming
- Normativa
- Rascunho 1.0
- Atualizado em
- Ver como Markdown
6.1 Requisição
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
}
O protocolo principal usa uma estrutura input e output no estilo Responses, em vez de uma lista simples de strings de mensagem, para que um único formato de requisição possa carregar:
- mensagens de vários turnos;
- texto, imagens, áudio e arquivos;
- chamadas de ferramentas e resultados de ferramentas;
- saída estruturada;
- resumos de raciocínio;
- saída multimodal.
O LMSP 1.0 define apenas conteúdo de texto. Os tipos de conteúdo de imagem, áudio e arquivo ficam reservados para versões futuras.
| Campo | Obrigatório | Significado |
|---|---|---|
model |
Sim | ID do modelo a usar. |
input |
Sim | Array de itens de entrada. Um item message tem um role (system, user ou assistant) e um array content de partes, como input_text. O uso de ferramentas acrescenta itens function_call e function_call_output (seção 6.5). |
stream |
Não | true para receber eventos enviados pelo servidor. O padrão é false. |
max_output_tokens |
Não | Limite superior do número de tokens gerados. |
temperature |
Não | Temperatura de amostragem. |
response_format |
Não | {"type": "text"} (o padrão) ou {"type": "json_schema", "json_schema": {"name": "...", "schema": {...}}} para saída estruturada. Exige a capacidade structured_output. |
tools, tool_choice |
Não | Ferramentas de função que o modelo pode chamar (seção 6.5). Exige a capacidade tools. |
store |
Não | Pede ao serviço que guarde a resposta, para que ela possa ser recuperada depois e usada como previous_response_id. O padrão é false. Ignorado por serviços sem a capacidade conversations. |
previous_response_id |
Não | Continua a partir de uma resposta armazenada. Exige a capacidade conversations. |
extensions |
Não | Extensões privadas (seção 9.1). |
Uma requisição que exige uma capacidade que o modelo não tem é rejeitada com 400 e unsupported_capability. Uma requisição que não cabe na janela de contexto é rejeitada com 400 e context_length_exceeded.
Um serviço que consegue armazenar conversas PODE também suportar previous_response_id. Caso contrário, toda requisição DEVE carregar o contexto completo. Um serviço NÃO DEVE depender da conexão HTTP para manter o estado da conversa.
6.2 Resposta síncrona
Quando stream é false, o serviço retorna 200 OK com um objeto de resposta depois que a geração termina.
{
"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 da resposta, como resp_.... |
object |
Sempre "response". |
created_at |
Momento da criação, em segundos desde a época Unix. |
status |
in_progress, completed, incomplete, failed ou cancelled. Uma resposta síncrona é retornada em um status final. |
model |
ID do modelo que produziu a resposta. |
output |
Array de itens de saída. |
usage |
Contagens de tokens: input_tokens, output_tokens e total_tokens. |
error |
null ou um objeto de problema (seção 9.3) quando status é failed. |
incomplete_details |
null ou um objeto com um reason, como max_output_tokens, quando status é incomplete. |
Tipos de itens de saída:
| Tipo de item | Formato |
|---|---|
message |
id, role (assistant) e content, um array de partes output_text que têm, cada uma, um text. |
function_call |
id, call_id, name e arguments, uma string codificada em JSON. |
reasoning |
id e summary, um array de partes summary_text que têm, cada uma, um text. |
Se a geração falhar, uma requisição síncrona é respondida com um status de erro e um documento de problema (seção 9.3), e não com um objeto de resposta. O status failed aparece em streams, tarefas e respostas armazenadas.
GET /lmsp/v1/responses/{response_id} retorna uma resposta que foi armazenada com store: true. É opcional e exige a capacidade conversations. Um ID desconhecido resulta em 404 com response_not_found.
6.3 Streaming
Para fazer streaming, defina stream na requisição:
{
"stream": true
}
O serviço responde 200 OK com Content-Type: text/event-stream e envia eventos semânticos. Cada evento tem um id, um nome event e um 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}}
Pelo menos estes eventos são definidos:
| Evento | Significado | Campos de dados |
|---|---|---|
response.created |
A resposta foi criada. | response_id, status (in_progress) |
response.output_item.added |
Um novo item de saída começou. | response_id, output_index, item |
response.output_text.delta |
Texto foi acrescentado a um item de mensagem. | response_id, item_id, delta |
response.output_item.done |
Um item de saída está completo. | response_id, output_index, item |
response.completed |
A resposta terminou. Evento final. | response_id, status, usage |
response.incomplete |
A geração parou antes do fim, por exemplo no limite de tokens. Evento final. | response_id, status, incomplete_details, usage |
response.failed |
A geração falhou. Evento final. | response_id, status, error |
response.cancelled |
A resposta foi cancelada. Evento final. | response_id, status |
error |
Um problema que não está ligado a uma única resposta, após o qual o fluxo não pode continuar. | error, um objeto de problema |
Um serviço fecha o fluxo após um evento final ou um evento error.
Os serviços PODEM enviar eventos adicionais, por exemplo para argumentos de chamadas de ferramentas, imagens, áudio e deltas de JSON estruturado. Os clientes DEVEM ignorar os tipos de evento que não conhecem.
Se o cliente fechar a conexão de uma requisição em streaming, o serviço DEVERIA parar de gerar.
6.4 IDs de evento e reconexão
O id de um evento DEVE ser um número de sequência inteiro, estritamente crescente dentro da resposta, começando em 1.
Após uma conexão interrompida, um cliente retoma enviando o último ID que recebeu. Ele faz isso com um cabeçalho:
Last-Event-ID: 2
ou com um parâmetro de consulta:
GET /lmsp/v1/tasks/{task_id}/events?after=2
Ambos vão para o endpoint de eventos de uma tarefa (seção 7.4). O serviço reenvia apenas os eventos cujo número de sequência é maior que 2. Se ambos estiverem presentes, after prevalece.
Se os eventos solicitados forem mais antigos que o período de retenção, o serviço responde 410 Gone com o erro event_history_expired. O cliente então busca o resultado final, com GET /lmsp/v1/tasks/{task_id}.
Uma resposta enviada em streaming diretamente por POST /lmsp/v1/responses pertence àquela conexão HTTP e não pode ser retomada. Um cliente que precisa de saída retomável DEVERIA criar uma tarefa e acompanhar os seus eventos.
6.5 Chamadas de ferramentas
O LMSP 1.0 define ferramentas de função que o cliente executa. O serviço não executa ferramentas por conta própria. O escopo tools:execute é reservado para extensões que o fazem (seção 10.3).
Primeiro, o cliente lista as ferramentas. Cada entrada tem type definido como function, um name, uma description e parameters, um objeto JSON Schema. tool_choice é auto (o padrão), none, required ou {"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"
}
Quando o modelo decide chamar uma ferramenta, a resposta contém um item function_call. Seus arguments são uma string codificada em JSON. Em um stream, o item chega completo em 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
}
O cliente executa a ferramenta e então envia uma nova requisição que carrega o contexto completo: os itens de entrada anteriores, o item function_call como foi recebido e um item function_call_output com o mesmo call_id. Seu output é uma string, geralmente codificada em JSON.
{
"type": "function_call_output",
"call_id": "call_01J8M7B3N9T2V5X8Z1C4D7F0HM",
"output": "{\"temperature_c\":17,\"condition\":\"light rain\"}"
}