响应与流式传输
- 规范性
- 草案 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
}
核心协议采用 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\"}"
}