# 非同步任務

> LMSP 如何把長時間的生成作為持久化任務來執行，包括建立任務、任務狀態機、冪等取消、事件流，以及未完成任務的重啟策略。

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

## 7.1 建立任務 {#create}

客戶端透過傳送它想要執行的回應請求來建立任務，請求要包在任務信封中。建議攜帶 `Idempotency-Key` 請求標頭（[第 9.2 節](https://madeforagent.com/zh-tw/lmsp/1.0/common-rules.md#idempotency)）。

```http
POST /lmsp/v1/tasks
Authorization: Bearer <token>
Idempotency-Key: 01J8M7C4Y3N5P8R2T6V9X1Z4BH
```

```json
{
  "type": "response",
  "input": {
    "model": "qwen3:14b-q4_k_m",
    "input": [
      {
        "type": "message",
        "role": "user",
        "content": [
          {
            "type": "input_text",
            "text": "Write a long report."
          }
        ]
      }
    ]
  },
  "on_restart": "fail"
}
```

| 欄位 | 必需 | 含義 |
| --- | --- | --- |
| `type` | 是 | `response`，1.0 中唯一的任務型別。 |
| `input` | 是 | 一個回應請求，與 `POST /lmsp/v1/responses` 的請求相同。其中的 `stream` 欄位會被忽略。 |
| `on_restart` | 否 | `fail`（預設）、`retry` 或 `resume`。參見[第 7.5 節](https://madeforagent.com/zh-tw/lmsp/1.0/tasks.md#restart)。 |

服務**必須**先持久化任務，再作出應答。隨後回傳：

```http
HTTP/1.1 202 Accepted
```

```json
{
  "id": "task_01J8M8R5X3V7B2N4Q9T1W6Y0ZC",
  "object": "task",
  "type": "response",
  "status": "queued",
  "created_at": 1794200100,
  "updated_at": 1794200100,
  "response_id": "resp_01J8M8R5X4B9D2F6H1K3N7Q0ZW",
  "events_url": "/lmsp/v1/tasks/task_01J8M8R5X3V7B2N4Q9T1W6Y0ZC/events",
  "on_restart": "fail",
  "response": null,
  "error": null
}
```

| 任務欄位 | 含義 |
| --- | --- |
| `id` | 任務識別碼，例如 `task_...`。 |
| `object` | 始終為 `"task"`。 |
| `type` | `response`。 |
| `status` | 當前狀態（[第 7.2 節](https://madeforagent.com/zh-tw/lmsp/1.0/tasks.md#states)）。 |
| `created_at`、`updated_at` | 時間，自 Unix 紀元起的秒數。 |
| `response_id` | 該任務所產生的回應的 id，在建立任務時分配。 |
| `events_url` | 事件流的路徑。`event_resume` 能力為 `true` 時存在。 |
| `on_restart` | 該任務的重啟策略。 |
| `response` | `status` 為 `succeeded` 後是回應物件，否則為 `null`。 |
| `error` | `status` 為 `failed` 時是一個 problem 物件（[第 9.3 節](https://madeforagent.com/zh-tw/lmsp/1.0/common-rules.md#errors)），否則為 `null`。 |

`GET /lmsp/v1/tasks/{task_id}` 回傳任務物件。不使用事件流的客戶端輪詢該介面。未知的 id 回傳 `404` 和 `task_not_found`。已結束的任務如下所示：

```json
{
  "id": "task_01J8M8R5X3V7B2N4Q9T1W6Y0ZC",
  "object": "task",
  "type": "response",
  "status": "succeeded",
  "created_at": 1794200100,
  "updated_at": 1794200162,
  "response_id": "resp_01J8M8R5X4B9D2F6H1K3N7Q0ZW",
  "events_url": "/lmsp/v1/tasks/task_01J8M8R5X3V7B2N4Q9T1W6Y0ZC/events",
  "on_restart": "fail",
  "response": {
    "id": "resp_01J8M8R5X4B9D2F6H1K3N7Q0ZW",
    "object": "response",
    "created_at": 1794200100,
    "status": "completed",
    "model": "qwen3:14b-q4_k_m",
    "output": [
      {
        "id": "msg_01J8M8R6A2C5E8G1J4M7P0S3VY",
        "type": "message",
        "role": "assistant",
        "content": [
          {
            "type": "output_text",
            "text": "Local model services make on-device inference a shared, discoverable utility..."
          }
        ]
      }
    ],
    "usage": {
      "input_tokens": 12,
      "output_tokens": 1480,
      "total_tokens": 1492
    },
    "error": null,
    "incomplete_details": null
  },
  "error": null
}
```

## 7.2 狀態機 {#states}

```text
queued --> loading --> running --> succeeded
  |           |           |
  |           |           +--> failed
  |           |           +--> cancelling --> cancelled
  |           +--------------> failed
  +--------------------------> cancelled
```

| 狀態 | 含義 | 後續狀態 |
| --- | --- | --- |
| `queued` | 已接受並持久化，等待開始。 | `loading`、`cancelled`、`failed` |
| `loading` | 正在載入模型。 | `running`、`cancelling`、`failed` |
| `running` | 模型正在生成。 | `succeeded`、`failed`、`cancelling` |
| `cancelling` | 已請求取消，後端尚未停止。 | `cancelled` |
| `succeeded` | 終態。回應已完成。 | 無 |
| `failed` | 終態。 | 無 |
| `cancelled` | 終態。 | 無 |

終態只有 `succeeded`、`failed` 和 `cancelled`。處於終態的任務**不得**再發生變化。回應以 `incomplete` 結束的任務（例如達到 token 上限）是 `succeeded`。

每次狀態轉換都是原子的，因此任務不會既被取消又已完成，先提交的轉換生效。

## 7.3 取消 {#cancel}

```http
POST /lmsp/v1/tasks/{task_id}/cancel
```

服務回傳 `200 OK` 和當前任務物件。`queued` 任務立即變為 `cancelled`；`loading` 或 `running` 任務先變為 `cancelling`，直到後端停止後再變為 `cancelled`。

取消操作**必須**冪等：重複取消已處於 `cancelling` 或 `cancelled` 的任務，仍回傳當前任務，不產生新錯誤。

取消已經 `succeeded` 或 `failed` 的任務，回傳 `409` 和 `task_not_cancelable`。未知的 id 回傳 `404` 和 `task_not_found`。

## 7.4 事件流 {#events}

```http
GET /lmsp/v1/tasks/{task_id}/events
Accept: text/event-stream
```

該介面是可選的，在 `event_resume` 能力為 `true` 時可用。

- 事件是[第 6.3 節](https://madeforagent.com/zh-tw/lmsp/1.0/responses.md#streaming)中的回應事件，對應該任務所產生的回應。序號與恢復規則遵循[第 6.4 節](https://madeforagent.com/zh-tw/lmsp/1.0/responses.md#reconnection)。
- 事件流以 `response.created` 開始，它在任務被接受時記錄。流以與結果相符的一個最終事件結束：`response.completed`、`response.incomplete`、`response.failed` 或 `response.cancelled`。
- 較晚連線的客戶端先收到自己錯過的事件，再收到即時事件。服務在最終事件之後關閉流。
- 事件會保留一段保留期（[第 11.2 節](https://madeforagent.com/zh-tw/lmsp/1.0/persistence.md#rules)）。更早的事件回傳 `410 Gone` 和 `event_history_expired`。

## 7.5 重啟語義 {#restart}

`on_restart` 規定服務重啟時對未完成任務如何處理：

| 取值 | 行為 |
| --- | --- |
| `fail` | 預設值。服務把未完成的任務標記為 `failed`，錯誤碼為 `server_restarted`。 |
| `retry` | 服務從頭重新執行該任務。 |
| `resume` | 服務從快照繼續執行。僅當後端明確支援可恢復快照時才允許，否則建立請求會被拒絕，回傳 `400` 和 `unsupported_capability`。 |

服務重啟時處於 `cancelling` 的任務，無論其策略如何，都會完成取消並變為 `cancelled`。

不建議把 `retry` 作為預設值，因為任務可能已經執行了工具或產生了外部副作用。選擇 `retry` 的客戶端**必須**同時使用 `Idempotency-Key`，並使其工具呼叫冪等。
