# 持久化

> LMSP 服务如何保存自己的状态：嵌入式 SQLite 数据库、建议保留的表、任务与事件的事务规则、保留期，以及启动时的恢复。

Source: https://madeforagent.com/zh-cn/lmsp/1.0/persistence/
Language: zh-CN
Specification: LMSP 1.0 (draft)
Updated: 2026-11-08

## 11.1 存储 {#storage}

服务**应**使用嵌入式 [SQLite](https://www.sqlite.org/) 数据库保存状态。建议的表如下：

| 表 | 内容 |
| --- | --- |
| `service_config` | 服务的身份与配置。 |
| `clients` | 已配对的客户端、令牌哈希和权限范围。 |
| `models` | 模型元数据和内容摘要。 |
| `responses` | 已保存的响应。 |
| `tasks` | 异步任务。 |
| `task_events` | 每个任务的事件日志，带序号。 |
| `idempotency_keys` | 幂等键、请求摘要和结果。 |

模型文件**必须**放在数据库之外，数据库只保存元数据与内容摘要。

表名和表结构由实现自行选择。客户端能够观察到的、需要互操作的，是接下来两节所规定的行为。

## 11.2 规则 {#rules}

无论服务使用何种存储，它都：

- **必须**先持久化任务，再返回 `202 Accepted`。
- **必须**在同一个事务中更新事件序号和任务状态。
- **必须**使取消状态转换原子化，避免出现“已取消又完成”的竞争。
- **应**把已结束的任务和事件保留一段可配置的保留期。
- **不得**在清理日志时删除未结束的任务。
- **必须**在启动时扫描遗留的 `queued`、`loading`、`running` 和 `cancelling` 任务，并执行各自的重启策略（[第 7.5 节](https://madeforagent.com/zh-cn/lmsp/1.0/tasks.md#restart)）。

## 11.3 启动时的恢复 {#recovery}

下表按 `on_restart` 策略列出遗留任务会被转入的状态：

| 启动时发现的状态 | `fail` | `retry` | `resume` |
| --- | --- | --- | --- |
| `queued` | `failed` | `queued` | `queued` |
| `loading` | `failed` | `queued` | `queued` |
| `running` | `failed` | `queued` | `running`，从快照继续 |
| `cancelling` | `cancelled` | `cancelled` | `cancelled` |

被转为 `failed` 的任务会得到错误码 `server_restarted` 和一个 `response.failed` 事件。被转为 `cancelled` 的任务会得到一个 `response.cancelled` 事件。新状态与对应的事件在同一个事务中写入（[第 11.2 节](https://madeforagent.com/zh-cn/lmsp/1.0/persistence.md#rules)）。
