# 通用協定規則

> 適用於所有 LMSP 介面的通用規則，包括版本請求標頭與擴充、冪等鍵、帶錯誤碼的 problem+json 錯誤格式，以及健康檢查。

Source: https://madeforagent.com/zh-tw/lmsp/1.0/common-rules/
Language: zh-TW
Specification: LMSP 1.0 (draft)
Updated: 2026-11-08

## 9.1 版本與擴充 {#versioning}

每個 LMSP 請求**可以**攜帶以下請求標頭：

```http
LMSP-Version: 1.0
LMSP-Client: example-client/1.2.0
```

`LMSP-Version` 是客戶端所面向的協定版本。`LMSP-Client` 以 `name/version` 的形式標識客戶端軟體，用於診斷。服務**不得**據此改變協定行為。

規則：

- 路徑中的 `v1` 表示主版本。
- 指明未知主版本的請求回傳 `426 Upgrade Required` 和錯誤碼 `unsupported_protocol_version`。
- 新增可選欄位**不得**破壞 1.x 相容性。
- 服務和客戶端**必須**忽略不認識的欄位。
- 私有擴充放入 `extensions` 物件，使用反向域名命名：

```json
{
  "extensions": {
    "com.example.cache": {
      "enabled": true
    }
  }
}
```

## 9.2 冪等 {#idempotency}

建立類請求，例如建立回應、建立任務或載入模型，支援冪等鍵：

```http
Idempotency-Key: <client-generated-unique-value>
```

服務儲存「冪等鍵＋請求主體摘要＋結果」：

- 相同冪等鍵和相同請求主體，回傳原結果。
- 相同冪等鍵但請求主體不同，回傳 `409 Conflict` 和 `idempotency_conflict`。

冪等鍵的作用域是客戶端和介面。它**應**是不超過 255 個字元的唯一值，例如 ULID 或 UUID。服務**應**至少儲存冪等鍵 24 小時。

服務**可以**在串流請求上忽略該冪等鍵。需要安全重試的客戶端應使用[任務](https://madeforagent.com/zh-tw/lmsp/1.0/tasks.md)。

## 9.3 錯誤格式 {#errors}

LMSP 介面上的所有錯誤都使用 `application/problem+json`（[RFC 9457](https://www.rfc-editor.org/rfc/rfc9457)）：

```json
{
  "type": "urn:lmsp:error:model-not-found",
  "title": "Model not found",
  "status": 404,
  "code": "model_not_found",
  "detail": "No local model with id 'qwen3:14b-q4_k_m'",
  "request_id": "req_01J8M9S6Y4W8C3P5R1V7Z2A0DH",
  "retryable": false
}
```

| 欄位 | 必需 | 含義 |
| --- | --- | --- |
| `type` | 是 | 標識錯誤種類的 URI。LMSP 使用 `urn:lmsp:error:`，後接把底線換成連字號的錯誤碼。 |
| `title` | 是 | 簡短的、便於閱讀的摘要。 |
| `status` | 是 | HTTP 狀態碼。 |
| `code` | 是 | 機器可讀的錯誤碼，取自下表。 |
| `detail` | 否 | 對本次錯誤的說明，便於閱讀。**不得**包含金鑰、提示詞或生成內容。 |
| `request_id` | 否 | 請求的識別碼，用於與服務日誌關聯。 |
| `retryable` | 是 | 稍後重複請求是否可能成功。 |

常用錯誤碼：

| 錯誤碼 | HTTP 狀態碼 | 可重試 | 含義 |
| --- | --- | --- | --- |
| `invalid_request` | 400 | 否 | 請求格式錯誤或引數無效。 |
| `unauthorized` | 401 | 否 | 權杖缺失、無效、過期或已被撤銷，或配對碼錯誤。 |
| `forbidden` | 403 | 否 | 權杖缺少所需的許可權範圍，或 `Origin`、`Host` 驗證未透過。 |
| `model_not_found` | 404 | 否 | 沒有該 id 的本地模型。 |
| `model_not_ready` | 409 | 是 | 模型未載入，且不會按需載入。 |
| `model_load_failed` | 500 | 是 | 載入模型失敗。 |
| `context_length_exceeded` | 400 | 否 | 輸入放不進模型的上下文視窗。 |
| `unsupported_capability` | 400 或 501 | 否 | 模型或服務不支援請求所需的能力。未實作的可選介面回傳 501。 |
| `unsupported_protocol_version` | 426 | 否 | 服務不支援所請求的主版本。 |
| `response_not_found` | 404 | 否 | 沒有該 id 的已儲存回應。 |
| `task_not_found` | 404 | 否 | 沒有該 id 的任務。 |
| `task_not_cancelable` | 409 | 否 | 任務已經 succeeded 或 failed。 |
| `idempotency_conflict` | 409 | 否 | 該冪等鍵已用於另一個不同的請求主體。 |
| `event_history_expired` | 410 | 否 | 請求的事件已超出保留期。 |
| `rate_limited` | 429 | 是 | 請求過多。 |
| `resource_exhausted` | 503 | 是 | 裝置記憶體或其他資源耗盡。 |
| `backend_unavailable` | 503 | 是 | 無法連線模型執行環境。 |
| `server_restarted` | 503 | 是 | 任務未完成時服務重啟了。 |
| `internal_error` | 500 | 視情況 | 服務內部發生了意外故障。 |

`retryable` 欄位具有權威性，上表給出的是常見取值。服務**可以**定義更多錯誤碼。客戶端遇到不認識的錯誤碼時，**必須**根據 HTTP 狀態碼和 `retryable` 欄位處理。

## 9.4 健康檢查 {#health}

```http
GET /lmsp/v1/health
```

```json
{
  "status": "ready",
  "service_id": "svc_01J8M4Y8K6M5E6K6Z7Z0Y8W3M2",
  "uptime_seconds": 86420,
  "loaded_models": 1,
  "active_tasks": 2,
  "storage": "ok"
}
```

| 欄位 | 含義 |
| --- | --- |
| `status` | `starting`、`ready`、`degraded` 或 `stopping`。 |
| `service_id` | 服務描述中的服務 id。 |
| `uptime_seconds` | 服務啟動以來的秒數。 |
| `loaded_models` | 處於 `ready` 狀態的模型數量。 |
| `active_tasks` | 處於 `queued`、`loading`、`running` 或 `cancelling` 的任務數量。 |
| `storage` | `ok` 或 `error`。 |

`status` 為 `ready` 或 `degraded` 時回傳 `200 OK`，否則回傳 `503 Service Unavailable`。

健康介面只回傳執行狀態，**不得**回傳模型路徑、提示詞、存取權杖等敏感資訊。
