# API 参考

对外接口按协议分为 MQTT、HTTP 和 WebSocket：MQTT 用于设备接入，HTTP 用于对话、查询和控制，WebSocket 用于实时语音。示例使用本地运行时，其中 `productId` 是设备智能体 ID，`deviceId` 是真实设备 ID，HTTP 路径里的 `products` 按设备智能体理解。

```txt
HTTP: http://127.0.0.1:3000
Voice WebSocket: ws://127.0.0.1:3001/ws/voice
Voice HTTP: http://127.0.0.1:3001/api/chat, /api/vision/frames
```

## 选择协议

| 使用场景 | 推荐协议 | 说明 |
| --- | --- | --- |
| 真实设备长期在线、上报状态、接收命令 | MQTT | 适合设备端连接、状态同步和命令响应。 |
| 业务系统、控制台扩展或自动化脚本调用 Device Agent | HTTP | 适合一次性请求、查询和命令下发。 |
| 实时语音交互 | WebSocket | 适合连续音频输入、实时识别结果和语音合成输出。 |
| 浏览器或设备端通过 WebSocket 连接 MQTT Broker | MQTT over WebSocket | 这是 MQTT 的传输方式，不是 Device Agent 的语音 WebSocket。 |

## MQTT

MQTT 用于设备侧接入。设备通过 MQTT 上线、上报状态、接收命令、返回命令结果和上报事件。MQTT 服务地址、用户名、密码和主题模板以控制台配置为准。

| 方向 | 主题 | 用途 |
| --- | --- | --- |
| MQTT 客户端 -> Device Agent | `device-agent/{productId}/in` | 向某个设备智能体发送文本请求。 |
| Device Agent -> MQTT 客户端 | `device-agent/{productId}/out` | 返回设备智能体回复。 |
| MQTT 客户端 -> Device Agent | `device-agent/{productId}/device/{deviceId}/in` | 向某台设备上下文发送文本请求。 |
| Device Agent -> MQTT 客户端 | `device-agent/{productId}/device/{deviceId}/out` | 返回带设备上下文的回复。 |
| Device Agent -> 设备 | `device-agent/{productId}/device/{deviceId}/commands` | 下发设备命令。 |
| 设备 -> Device Agent | `device-agent/{productId}/device/{deviceId}/responses` | 返回命令结果。 |
| 设备 -> Device Agent | `v1/{productId}/{deviceId}/telemetry` | 上报在线状态和当前数据。 |
| 设备 -> Device Agent | `v1/{productId}/{deviceId}/event` | 上报设备事件。 |
| 设备 -> Device Agent | `device-agent/{productId}/device/{deviceId}/ntp/request` | 发起时间同步。 |
| Device Agent -> 设备 | `device-agent/{productId}/device/{deviceId}/ntp/response` | 返回时间同步结果。 |

文本请求消息体：

```json
{
  "prompt": "查看当前温度",
  "sessionId": "session-default:thermostat:thermostat-001",
  "metadata": {
    "source": "mqtt-client"
  }
}
```

设备智能体回复消息体：

```json
{
  "sessionId": "session-default:thermostat:thermostat-001",
  "text": "当前温度是 28 度。",
  "metadata": {
    "timestamp": "2026-05-11T10:00:00.000Z"
  },
  "timestamp": "2026-05-11T10:00:00.000Z"
}
```

设备上线状态：

```json
{
  "type": "status",
  "data": {
    "status": "online",
    "state": {
      "temperature": 28,
      "humidity": 62,
      "mode": "auto"
    }
  },
  "metadata": {
    "productId": "thermostat",
    "source": "existing-device"
  }
}
```

设备命令：

```json
{
  "cmd": "set_target_temperature",
  "params": {
    "target_temperature": 24
  },
  "requestId": "req-001",
  "ts": 1710000010000
}
```

命令响应：

```json
{
  "code": 0,
  "msg": "ok",
  "requestId": "req-001",
  "data": {
    "target_temperature": 24
  },
  "metadata": {
    "productId": "thermostat",
    "source": "existing-device"
  }
}
```

设备事件：

```json
{
  "type": "event",
  "data": {
    "event": "temperature_alert",
    "temperature": 38.5,
    "level": "warning"
  },
  "metadata": {
    "productId": "thermostat",
    "source": "existing-device"
  }
}
```

时间同步请求和响应：

```json
{
  "deviceSendTime": 1710000010000
}
```

```json
{
  "deviceSendTime": 1710000010000,
  "serverRecvTime": 1710000010100,
  "serverSendTime": 1710000010105
}
```

更多消息体规则、校验方式和 MQTTX 示例见 [MQTT 接入](../device-access/mqtt.md)。

HTTP 侧下发的设备命令最终会通过 MQTT 命令主题发送给设备；设备通过 MQTT 响应主题返回结果。设备事件也来自 MQTT 事件主题，上报后可通过 HTTP 事件接口查询。

## HTTP

HTTP API 路径都以 `/api` 开头。除 `/api/chat` 返回 Server-Sent Events 外，其他对外接口通常使用 JSON。

`/api/chat` 和 `/api/vision/frames` 同时挂在主 HTTP 端口和语音服务端口上。业务系统通常使用 `3000`；语音或摄像头客户端如果已经连接 `3001`，可以直接使用同名接口。

### 对话和视觉

| 方法 | 路径 | 用途 |
| --- | --- | --- |
| `GET` | `/api/health` | 检查 HTTP API 是否可用。 |
| `POST` | `/api/chat` | 发起文本对话，必须设置 `stream: true`。 |
| `GET` | `/api/sessions/:sessionId/history` | 查询会话历史。 |
| `POST` | `/api/sessions/:sessionId/interrupt` | 中断当前会话。 |
| `DELETE` | `/api/sessions/:sessionId` | 清空会话。 |
| `POST` | `/api/vision/frames` | 上传视觉帧，供后续对话使用。 |

对话示例：

```bash
$ curl -N http://127.0.0.1:3000/api/chat \
  -H 'Content-Type: application/json' \
  -H 'Accept: text/event-stream' \
  -d '{
    "message": "查看当前温度，并把目标温度设置为 24 度",
    "stream": true,
    "sessionId": "demo-session",
    "metadata": {
      "productId": "thermostat",
      "deviceId": "thermostat-001"
    }
  }'
```

视觉帧先通过 `/api/vision/frames` 上传，再把返回的 `frameId` 和 `capturedAt` 作为 `visionRefs` 传给 `/api/chat`。`mimeType` 支持 `image/jpeg`、`image/png` 和 `image/webp`。

```bash
$ curl http://127.0.0.1:3000/api/vision/frames \
  -H 'Content-Type: application/json' \
  -d '{
    "sessionId": "demo-session",
    "deviceId": "thermostat-001",
    "mimeType": "image/png",
    "imageBase64": "<base64>",
    "source": "camera"
  }'
```

上传成功后，响应会返回：

```json
{
  "frameId": "frame-001",
  "capturedAt": "2026-05-11T10:00:00.000Z",
  "source": "camera",
  "mimeType": "image/png"
}
```

带视觉帧发起对话：

```json
{
  "message": "根据这张图判断设备屏幕是否异常",
  "stream": true,
  "sessionId": "demo-session",
  "visionRefs": [
    {
      "frameId": "frame-001",
      "capturedAt": "2026-05-11T10:00:00.000Z",
      "source": "camera"
    }
  ]
}
```

### 设备、命令和事件

| 方法 | 路径 | 用途 |
| --- | --- | --- |
| `GET` | `/api/products/:productId/devices` | 查询某个设备智能体下的设备列表。 |
| `GET` | `/api/devices/:deviceId` | 查询设备详情。 |
| `POST` | `/api/devices/:deviceId/commands` | 向在线设备下发命令。 |
| `GET` | `/api/devices/:deviceId/events` | 查询设备事件。 |

常见调用顺序是：

1. 用 `GET /api/products/:productId/devices` 查询设备列表，拿到要操作的 `deviceId`。
2. 用 `GET /api/devices/:deviceId` 查看设备是否在线，以及当前数据。
3. 用 `POST /api/devices/:deviceId/commands` 下发设备规格中定义过的命令。
4. 用 `GET /api/devices/:deviceId/events` 查看设备最近上报的事件。

查询设备列表：

```bash
$ curl 'http://127.0.0.1:3000/api/products/thermostat/devices?status=online'
```

查询设备详情：

```bash
$ curl 'http://127.0.0.1:3000/api/devices/thermostat-001'
```

命令示例：

```bash
$ curl http://127.0.0.1:3000/api/devices/thermostat-001/commands \
  -H 'Content-Type: application/json' \
  -d '{
    "command": "set_target_temperature",
    "params": {
      "target_temperature": 24
    },
    "timeoutMs": 30000
  }'
```

查询设备事件：

```bash
$ curl 'http://127.0.0.1:3000/api/devices/thermostat-001/events?limit=50'
```

控制台创建、更新、发布设备智能体，生成 SDK，修改配置，查看日志，管理技能和工具等能力属于产品界面内部接口，不在对外 API 参考中展开。

## WebSocket

WebSocket 目前主要用于语音通道。默认地址：

```txt
ws://127.0.0.1:3001/ws/voice
```

语音服务端口还会处理 `POST /api/chat` 和 `POST /api/vision/frames`，用于语音和摄像头客户端在同一个服务地址下提交文本请求和视觉帧。

连接时可带 Header：

| Header | 说明 |
| --- | --- |
| `Protocol-Version` | 协议版本，当前为 `3`。 |
| `Device-Id` | 当前设备 ID。 |
| `Client-Id` | 客户端 ID，不传时默认使用设备 ID。 |

语音连接建立后，先发送 `hello`：

```json
{
  "type": "hello",
  "version": 3,
  "audio_params": {
    "format": "pcm",
    "sample_rate": 16000,
    "channels": 1
  },
  "sessionId": "demo-session",
  "productId": "thermostat",
  "deviceId": "thermostat-001",
  "provider": "aliyun"
}
```

一次语音交互的消息顺序通常是：

| 方向 | 消息 | 说明 |
| --- | --- | --- |
| 客户端 -> Device Agent | `hello` | 建立语音会话，提交音频参数、设备上下文和语音服务商。 |
| Device Agent -> 客户端 | `hello` | 返回会话 ID 和服务端语音输出参数。 |
| 客户端 -> Device Agent | `listen` | 开始收音。 |
| 客户端 -> Device Agent | 音频二进制帧 | 发送语音数据。 |
| Device Agent -> 客户端 | `asr` | 返回实时或最终识别文本。 |
| 客户端 -> Device Agent | `stop` | 结束收音，可携带 `visionRefs`。 |
| Device Agent -> 客户端 | `agent_reply` | 返回设备智能体文本回复。 |
| Device Agent -> 客户端 | `tts` | 返回待合成文本。 |
| Device Agent -> 客户端 | 语音合成音频二进制帧 | 播放语音回复。 |
| Device Agent -> 客户端 | `tts_complete` | 本轮语音完成。 |
| 客户端 -> Device Agent | `abort` | 中断当前轮次。 |
| 客户端 -> Device Agent | `goodbye` | 关闭语音会话。 |

语音配置和使用方式见 [语音交互](../usage/voice.md)。

注意，`mqtt.wsUrl` 是 MQTT Broker 的 WebSocket 地址，用来通过 WebSocket 传输 MQTT 协议；`/ws/voice` 是 Device Agent 的语音通道，两者不是同一个接口。
