响应与流式传输

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
}

核心协议采用 Responses 风格的 input/output 结构,而不是只支持简单的 messages 字符串,以便用同一种请求格式统一承载:

  • 多轮消息;
  • 文本、图片、音频和文件;
  • 工具调用及工具结果;
  • 结构化输出;
  • 推理摘要;
  • 多模态输出。

LMSP 1.0 只定义文本内容。图片、音频和文件的内容类型留待后续版本。

字段 必需 含义
model 是 要使用的模型 id。
input 是 输入项数组。message 项包含 role(system、user 或 assistant)和由多个部分组成的 content 数组,例如 input_text。使用工具时会增加 function_call 和 function_call_output 项(第 6.5 节)。
stream 否 为 true 时接收服务器发送事件,默认为 false。
max_output_tokens 否 生成 token 数的上限。
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 生成该响应的模型 id。
output 输出项数组。
usage token 用量:input_tokens、output_tokens 和 total_tokens。
error null;当 status 为 failed 时是一个 problem 对象(第 9.3 节)。
incomplete_details null;当 status 为 incomplete 时是带有 reason(例如 max_output_tokens)的对象。

输出项类型:

项类型 结构
message id、role(assistant)和 content,后者是 output_text 部分的数组,每个部分带有 text。
function_call id、call_id、name 和 arguments,后者是 JSON 编码的字符串。
reasoning id 和 summary,后者是 summary_text 部分的数组,每个部分带有 text。

如果生成失败,同步请求返回错误状态码和 problem 文档(第 9.3 节),而不是响应对象。failed 状态只出现在流、任务和已保存的响应中。

GET /lmsp/v1/responses/{response_id} 返回以 store: true 保存的响应。它是可选接口,需要 conversations 能力。未知的 id 返回 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 文本被追加到某个 message 项。 response_id、item_id、delta
response.output_item.done 一个输出项已完成。 response_id、output_index、item
response.completed 响应已完成。最终事件。 response_id、status、usage
response.incomplete 生成提前停止,例如达到 token 上限。最终事件。 response_id、status、incomplete_details、usage
response.failed 生成失败。最终事件。 response_id、status、error
response.cancelled 响应已取消。最终事件。 response_id、status
error 与某个具体响应无关的问题,出现后流无法继续。 error,一个 problem 对象

服务在最终事件或 error 事件之后关闭流。

服务可以发送额外的事件,例如工具调用参数、图片、音频和结构化 JSON 增量。客户端必须忽略不认识的事件类型。

如果客户端关闭了流式请求的连接,服务应停止生成。

6.4 事件 id 与重连

事件的 id 必须是整数序号,在该响应内严格递增,从 1 开始。

连接断开后,客户端通过发送自己收到的最后一个 id 来恢复。可以使用请求头:

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 项,以及一个 call_id 相同的 function_call_output 项。其 output 是字符串,通常为 JSON 编码。

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